11<script setup lang="ts">
2- import { twMerge } from ' tailwind-merge' ;
3- import { computed } from ' vue' ;
2+ import { cva , type VariantProps } from ' class-variance-authority' ;
3+ import { cn } from ' ./utils/cn' ;
4+
5+ const timeTrackerVariants = cva (
6+ ' flex items-center justify-center transition focus:outline-0 rounded-full' ,
7+ {
8+ variants: {
9+ variant: {
10+ primary:
11+ ' text-white ring-accent-200/10 focus-visible:ring-ring focus-visible:ring-2 ring-4 sm:ring-[6px]' ,
12+ secondary:
13+ ' bg-tertiary text-text-tertiary hover:text-text-primary focus:ring-2 focus:ring-border-tertiary' ,
14+ outline:
15+ ' border border-border-primary text-text-tertiary hover:text-text-primary hover:bg-tertiary/50' ,
16+ },
17+ size: {
18+ small: ' w-6 h-6' ,
19+ base: ' w-9 h-9 hover:scale-110' ,
20+ large: ' w-11 h-11 hover:scale-110' ,
21+ },
22+ active: {
23+ true: ' ' ,
24+ false: ' ' ,
25+ },
26+ },
27+ compoundVariants: [
28+ {
29+ variant: ' primary' ,
30+ active: true ,
31+ class: ' bg-red-400/80 hover:bg-red-500/80 focus:bg-red-500/80' ,
32+ },
33+ {
34+ variant: ' primary' ,
35+ active: false ,
36+ class: ' bg-accent-300/70 hover:bg-accent-400/70 focus:bg-accent-700' ,
37+ },
38+ ],
39+ defaultVariants: {
40+ variant: ' primary' ,
41+ size: ' base' ,
42+ active: false ,
43+ },
44+ }
45+ );
46+
47+ type TimeTrackerVariants = VariantProps <typeof timeTrackerVariants >;
448
549const emit = defineEmits ([' changed' ]);
650
751const props = withDefaults (
852 defineProps <{
9- size? : ' base' | ' large' | ' small' ;
53+ variant? : TimeTrackerVariants [' variant' ];
54+ size? : TimeTrackerVariants [' size' ];
1055 active? : boolean ;
1156 }>(),
1257 {
58+ variant: ' primary' ,
1359 size: ' base' ,
1460 active: false ,
1561 }
1662);
17- const buttonSizeClasses = {
18- small: ' w-6 h-6 bg-accent-200/40 hover:bg-accent-300/70' ,
19- base: ' w-8 h-8 bg-accent-200/40 hover:scale-110 hover:bg-accent-300/70 ring-accent-200/10 focus-visible:ring-ring ring-4 hover:ring-4' ,
20- large: ' w-11 h-11 ring-accent-200/10 focus-visible:ring-ring focus-visible:ring-2 ring-4 sm:ring-[6px] hover:scale-110' ,
21- };
63+
2264const iconClass = {
2365 small: ' w-2.5 h-2.5' ,
24- base: ' w-3.5 h-3.5 ' ,
66+ base: ' w-3 h-3' ,
2567 large: ' w-4 h-4' ,
2668};
2769
28- const buttonColorClasses = computed (() => {
29- if (props .active ) {
30- return ' bg-red-400/80 hover:bg-red-500/80 focus:bg-red-500/80' ;
31- } else {
32- return ' bg-accent-300/70 hover:bg-accent-400/70 focus:bg-accent-700' ;
33- }
34- });
35-
3670function toggleState() {
3771 emit (' changed' , ! props .active );
3872}
@@ -41,18 +75,12 @@ function toggleState() {
4175<template >
4276 <button
4377 data-testid =" timer_button"
44- :class ="
45- twMerge(
46- buttonSizeClasses[size],
47- buttonColorClasses,
48- 'flex items-center justify-center py-1 transition focus:outline-0 rounded-full text-white '
49- )
50- "
78+ :class =" cn(timeTrackerVariants({ variant, size, active }))"
5179 @click =" toggleState" >
5280 <Transition name =" fade" mode =" out-in" >
5381 <svg
5482 v-if =" props.active"
55- :class =" iconClass[size]"
83+ :class =" iconClass[size ?? 'base' ]"
5684 viewBox =" 0 0 14 14"
5785 fill =" none"
5886 xmlns =" http://www.w3.org/2000/svg" >
@@ -64,7 +92,7 @@ function toggleState() {
6492 </svg >
6593 <svg
6694 v-else
67- :class =" iconClass[size]"
95+ :class =" iconClass[size ?? 'base' ]"
6896 viewBox =" 0 0 7 8"
6997 fill =" none"
7098 xmlns =" http://www.w3.org/2000/svg" >
0 commit comments