add light mode

This commit is contained in:
Gregor Vostrak
2025-03-28 14:00:19 +01:00
parent 7339b79e35
commit df2fe1da1e
124 changed files with 579 additions and 369 deletions

View File

@@ -47,7 +47,7 @@ const tagClasses = computed(() => {
tagClasses,
badgeClasses[size],
borderClasses,
'rounded transition inline-flex items-center font-semibold text-white disabled:text-text-quaternary outline-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
'rounded transition inline-flex items-center font-semibold text-text-primary disabled:text-text-quaternary outline-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
props.class
)
">

View File

@@ -21,7 +21,7 @@ const props = withDefaults(
<button
:type="type"
:disabled="loading"
class="inline-flex items-center px-2 sm:px-3 py-1 sm:py-2 bg-accent-300/10 border border-accent-300/20 rounded-md font-medium text-xs sm:text-sm text-white hover:bg-accent-300/20 active:bg-accent-300/20 focus:outline-none focus-visible:ring-2 focus-visible:border-transparent focus-visible:ring-ring transition ease-in-out duration-150">
class="inline-flex items-center px-2 sm:px-3 py-1 sm:py-2 bg-button-primary-background border border-button-primary-border rounded-md font-medium text-xs sm:text-sm text-button-primary-text hover:bg-button-primary-background-hover active:bg-button-primary-background-hover focus:outline-none focus-visible:ring-2 focus-visible:border-transparent focus-visible:ring-ring transition ease-in-out duration-150">
<span
:class="
twMerge('flex items-center ', props.icon ? 'space-x-1.5' : '')

View File

@@ -31,7 +31,7 @@ const sizeClasses = {
:disabled="loading"
:class="
twMerge(
'bg-button-secondary-background border border-button-secondary-border hover:bg-button-secondary-background-hover shadow-sm transition text-white rounded-lg font-semibold inline-flex items-center space-x-1.5 focus-visible:outline-none focus-visible:border-transparent focus-visible:ring-2 focus-visible:ring-ring focus:border-transparent disabled:opacity-25 ease-in-out',
'bg-button-secondary-background border border-button-secondary-border hover:bg-button-secondary-background-hover shadow-sm transition text-text-primary rounded-lg font-semibold inline-flex items-center space-x-1.5 focus-visible:outline-none focus-visible:border-transparent focus-visible:ring-2 focus-visible:ring-ring focus:border-transparent disabled:opacity-25 ease-in-out',
sizeClasses[props.size],
props.class
)

View File

@@ -10,7 +10,7 @@ defineProps<{
<template>
<div class="flex w-full items-center justify-between pb-2.5 lg:pb-4">
<h3
class="text-white font-bold text-sm lg:text-base flex items-center space-x-2 lg:space-x-2.5">
class="text-text-primary font-semibold text-sm lg:text-base flex items-center space-x-2 lg:space-x-2.5">
<component
:is="icon"
v-if="icon"

View File

@@ -136,7 +136,7 @@ const highlightedItem = computed(() => {
ref="searchInput"
:value="searchValue"
data-testid="client_dropdown_search"
class="bg-card-background border-0 placeholder-muted text-sm text-white py-2.5 focus:ring-0 border-b border-card-background-separator focus:border-card-background-separator w-full"
class="bg-card-background border-0 placeholder-muted text-sm text-text-primary py-2.5 focus:ring-0 border-b border-card-background-separator focus:border-card-background-separator w-full"
placeholder="Search for a client..."
@input="updateSearchValue"
@keydown.enter="addClientIfNoneExists"
@@ -150,7 +150,7 @@ const highlightedItem = computed(() => {
class="bg-card-background-active"
@click="addClientIfNoneExists">
<div
class="flex space-x-3 items-center px-4 py-3 text-xs text-white font-medium border-t rounded-b-lg border-card-background-separator">
class="flex space-x-3 items-center px-4 py-3 text-xs text-text-primary font-medium border-t rounded-b-lg border-card-background-separator">
<PlusCircleIcon
class="w-5 flex-shrink-0"></PlusCircleIcon>
<span>Add "{{ searchValue }}" as a new Client</span>

View File

@@ -19,7 +19,7 @@ const iconClasses = computed(() => {
<template>
<div
class="flex items-center space-x-3 w-full px-3 py-2.5 text-start text-sm font-medium leading-5 text-white hover:bg-card-background-active focus:outline-none focus:bg-card-background-active transition duration-150 ease-in-out">
class="flex items-center space-x-3 w-full px-3 py-2.5 text-start text-sm font-medium leading-5 text-text-primary hover:bg-card-background-active focus:outline-none focus:bg-card-background-active transition duration-150 ease-in-out">
<CheckCircleIcon :class="twMerge(iconClasses, 'w-5')"></CheckCircleIcon>
<span>{{ name }}</span>
</div>

View File

@@ -30,7 +30,7 @@ const close = () => {
:closeable="closeable"
@close="close">
<div class="px-6 py-4">
<div class="text-lg font-medium text-white" role="heading">
<div class="text-lg font-medium text-text-primary" role="heading">
<slot name="title" />
</div>

View File

@@ -15,7 +15,7 @@ const props = withDefaults(
const expandedStatusClasses = computed(() => {
if (props.expanded) {
return 'border-card-border border bg-card-background-active text-white';
return 'border-card-border border bg-card-background-active text-text-primary';
}
return 'border-card-border border bg-card-background hover:bg-card-background-active hover:text-text-primary transition text-muted';
});

View File

@@ -20,7 +20,7 @@ const props = withDefaults(
const iconColorClasses = computed(() => {
if (active.value) {
return 'text-accent-300 focus:text-accent-200 hover:text-accent-200';
return 'text-input-select-active focus:text-input-select-active-hover hover:text-input-select-active-hover';
} else {
return 'text-icon-default focus:text-icon-active hover:text-icon-active';
}

View File

@@ -54,7 +54,7 @@ const emit = defineEmits(['changed']);
:tabindex="tabindex"
:class="
twMerge(
'bg-input-background border text-white border-input-border focus-visible:outline-0 focus-visible:border-input-border-active focus-visible:ring-0 rounded-md',
'bg-input-background border text-text-primary border-input-border focus-visible:outline-0 focus-visible:border-input-border-active focus-visible:ring-0 rounded-md',
props.class
)
"

View File

@@ -107,7 +107,7 @@ function setLastYear() {
<button
class="px-2 py-1 bg-input-background border border-input-border font-medium rounded-lg flex items-center space-x-2">
<CalendarIcon class="w-5"></CalendarIcon>
<div class="text-white">
<div class="text-text-primary">
{{ formatDateLocalized(start) }}
<span class="px-1.5 text-muted">-</span>
{{ formatDateLocalized(end) }}
@@ -119,7 +119,7 @@ function setLastYear() {
<div
class="flex divide-x divide-border-secondary justify-between">
<div
class="text-white text-sm flex flex-col space-y-0.5 items-start py-2 [&_button:hover]:bg-tertiary [&_button]:rounded [&_button]:px-2 [&_button]:py-1">
class="text-text-primary text-sm flex flex-col space-y-0.5 items-start py-2 [&_button:hover]:bg-tertiary [&_button]:rounded [&_button]:px-2 [&_button]:py-1">
<button @click="setToday">Today</button>
<button @click="setThisWeek">This Week</button>
<button @click="setLastWeek">Last Week</button>

View File

@@ -118,7 +118,7 @@ const { floatingStyles } = useFloating(reference, floating, {
:style="floatingStyles"
@click="onContentClick">
<div
class="rounded-lg ring-1 relative ring-black ring-opacity-5 border border-card-border overflow-none shadow-dropdown bg-card-background">
class="rounded-lg overflow-hidden relative border border-card-border overflow-none shadow-dropdown bg-card-background">
<slot name="content" />
</div>
</div>

View File

@@ -9,7 +9,7 @@ const props = defineProps<{
<template>
<label
:class="twMerge('block font-medium text-sm text-white', props.class)">
:class="twMerge('block font-medium text-sm text-text-primary', props.class)">
<span v-if="value">{{ value }}</span>
<span v-else><slot /></span>
</label>

View File

@@ -159,7 +159,7 @@ const highlightedItem = computed(() => {
<input
ref="searchInput"
:value="searchValue"
class="bg-card-background border-0 placeholder-muted text-sm text-white py-2.5 focus:ring-0 border-b border-card-background-separator focus:border-card-background-separator w-full"
class="bg-card-background border-0 placeholder-muted text-sm text-text-primary py-2.5 focus:ring-0 border-b border-card-background-separator focus:border-card-background-separator w-full"
:placeholder="searchPlaceholder"
@input="updateSearchValue"
@keydown.up.prevent="moveHighlightUp"

View File

@@ -10,16 +10,16 @@ const props = defineProps<{
const iconClasses = computed(() => {
if (props.selected) {
return 'text-accent-200';
return 'text-input-select-active';
} else {
return 'text-white/10';
return 'text-text-quaternary opacity-50';
}
});
</script>
<template>
<div
class="flex items-center space-x-3 w-full px-3 py-2.5 text-start text-sm font-medium leading-5 text-white hover:bg-card-background-active focus:outline-none focus:bg-card-background-active transition duration-150 ease-in-out">
class="flex items-center space-x-3 w-full px-3 py-2.5 text-start text-sm font-medium leading-5 text-text-primary hover:bg-card-background-active focus:outline-none focus:bg-card-background-active transition duration-150 ease-in-out">
<CheckCircleIcon :class="twMerge(iconClasses, 'w-5')"></CheckCircleIcon>
<span class="flex-1 min-w-0 overflow-ellipsis overflow-hidden">{{
name

View File

@@ -13,7 +13,7 @@ const props = defineProps<{
<div
:class="
twMerge(
'flex items-center space-x-3 w-full px-1.5 py-1.5 rounded text-start text-sm font-medium leading-5 text-white focus:outline-none focus:bg-card-background-active transition duration-150 ease-in-out cursor-pointer ',
'flex items-center space-x-3 w-full px-1.5 py-1.5 rounded text-start text-sm font-medium leading-5 text-text-primary focus:outline-none focus:bg-card-background-active transition duration-150 ease-in-out cursor-pointer ',
props.highlighted && 'bg-card-background-active',
props.selected
? 'bg-accent-300/20'

View File

@@ -25,7 +25,7 @@ const model = defineModel();
v-model="model"
:class="
twMerge(
'border-input-border border bg-input-background text-white focus-visible:ring-2 focus-visible:ring-ring focus-visible:border-transparent rounded-md shadow-sm',
'border-input-border border bg-input-background text-text-primary focus-visible:ring-2 focus-visible:ring-ring focus-visible:border-transparent rounded-md shadow-sm',
props.class
)
"

View File

@@ -141,7 +141,7 @@ const closestValue = computed({
</script>
<template>
<div class="flex min-w-0 items-center justify-center text-white">
<div class="flex min-w-0 items-center justify-center text-text-primary">
<SelectDropdown
v-model="closestValue"
v-model:open="open"

View File

@@ -58,7 +58,7 @@ watch(focused, (newValue, oldValue) => {
<div
class="px-2"
@keydown.enter.prevent="nextTick(() => emit('close'))">
<div class="font-bold text-white text-sm pb-2">Start</div>
<div class="font-semibold text-text-primary text-sm pb-2">Start</div>
<div class="space-y-2">
<TimePickerSimple
v-model="tempStart"
@@ -75,7 +75,7 @@ watch(focused, (newValue, oldValue) => {
</div>
</div>
<div class="px-2">
<div class="font-bold text-white text-sm pb-2">End</div>
<div class="font-semibold text-text-primary text-sm pb-2">End</div>
<div v-if="tempEnd !== null" class="space-y-2">
<TimePickerSimple
v-model="tempEnd"

View File

@@ -9,7 +9,7 @@ const props = defineProps<{
<template>
<svg
:class="
twMerge('animate-spin -ml-1 mr-3 h-5 w-5 text-white', props.class)
twMerge('animate-spin -ml-1 mr-3 h-5 w-5 text-text-primary', props.class)
"
xmlns="http://www.w3.org/2000/svg"
fill="none"

View File

@@ -19,7 +19,7 @@ const model = defineModel<string>({ default: '' });
</button>
</template>
<template #content>
<div class="text-white grid grid-cols-6 gap-3 px-3 py-3">
<div class="text-text-primary grid grid-cols-6 gap-3 px-3 py-3">
<div
v-for="color in colors"
:key="color"

View File

@@ -8,7 +8,7 @@ defineProps<{
<template>
<div
class="flex justify-between items-center w-full text-start text-sm font-medium leading-5 text-white hover:bg-card-background-active focus:outline-none focus:bg-card-background-active transition duration-150 ease-in-out">
class="flex justify-between items-center w-full text-start text-sm font-medium leading-5 text-text-primary hover:bg-card-background-active focus:outline-none focus:bg-card-background-active transition duration-150 ease-in-out">
<div class="flex space-x-3 items-center px-3 py-1.5">
<div
:style="{ backgroundColor: color }"

View File

@@ -185,7 +185,7 @@ const showCreateTagModal = ref(false);
ref="searchInput"
:value="searchValue"
data-testid="tag_dropdown_search"
class="bg-card-background border-0 placeholder-muted text-sm text-white py-2.5 focus:ring-0 border-b border-card-background-separator focus:border-card-background-separator w-full"
class="bg-card-background border-0 placeholder-muted text-sm text-text-primary py-2.5 focus:ring-0 border-b border-card-background-separator focus:border-card-background-separator w-full"
placeholder="Search for a Tag..."
@input="updateSearchValue"
@keydown.enter="addTagIfNoneExists"
@@ -211,7 +211,7 @@ const showCreateTagModal = ref(false);
</div>
<div class="hover:bg-card-background-active rounded-b-lg">
<button
class="text-white w-full flex space-x-3 items-center px-4 py-3 text-xs font-semibold border-t border-card-background-separator"
class="text-text-primary w-full flex space-x-3 items-center px-4 py-3 text-xs font-semibold border-t border-card-background-separator"
@click="
open = false;
showCreateTagModal = true;

View File

@@ -90,7 +90,7 @@ function onSelectChange(event: Event) {
<template>
<div
class="border-b border-default-background-separator min-w-0 transition"
class="border-b border-default-background-separator bg-row-background min-w-0 transition"
data-testid="time_entry_row">
<MainContainer class="min-w-0">
<div
@@ -156,7 +156,7 @@ function onSelectChange(event: Event) {
</button>
</div>
<button
class="text-white min-w-[90px] px-2 py-1.5 bg-transparent text-center hover:bg-card-background rounded-lg border border-transparent hover:border-card-border text-sm font-semibold focus-visible:outline-none focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:bg-tertiary"
class="text-text-primary min-w-[90px] px-2 py-1.5 bg-transparent text-center hover:bg-card-background rounded-lg border border-transparent hover:border-card-border text-sm font-semibold focus-visible:outline-none focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:bg-tertiary"
@click="expanded = !expanded">
{{
formatHumanReadableDuration(timeEntry.duration ?? 0)

View File

@@ -45,7 +45,7 @@ const displaysPlaceholder = computed(() => {
data-testid="time_entry_description"
:value="liveDataValue"
placeholder="Add a description"
class="absolute px-0 h-full min-w-0 pl-3 pr-1 left-0 top-0 w-full text-sm text-white font-medium bg-transparent focus-visible:ring-0 rounded-lg border-0"
class="absolute px-0 h-full min-w-0 pl-3 pr-1 left-0 top-0 w-full text-sm text-text-primary font-medium bg-transparent focus-visible:ring-0 rounded-lg border-0"
@blur="onChange"
@input="onInput"
@keydown.enter="onChange" />

View File

@@ -65,7 +65,7 @@ const showMassUpdateModal = ref(false);
:class="
twMerge(
props.class,
'text-sm py-1.5 font-medium border-b border-t border-border-secondary flex items-center space-x-3'
'text-sm py-1.5 font-medium border-t border-b bg-secondary border-border-secondary flex items-center space-x-3'
)
">
<Checkbox

View File

@@ -11,7 +11,7 @@ const emit = defineEmits<{
<MoreOptionsDropdown label="Actions for the time entry">
<button
data-testid="time_entry_delete"
class="flex items-center space-x-3 w-full px-3 py-2.5 text-start text-sm font-medium leading-5 text-white hover:bg-card-background-active focus:outline-none focus:bg-card-background-active transition duration-150 ease-in-out"
class="flex items-center space-x-3 w-full px-3 py-2.5 text-start text-sm font-medium leading-5 text-text-primary hover:bg-card-background-active focus:outline-none focus:bg-card-background-active transition duration-150 ease-in-out"
@click="emit('delete')">
<TrashIcon class="w-5 text-icon-active"></TrashIcon>
<span>Delete</span>

View File

@@ -93,7 +93,7 @@ function onSelectChange(event: Event) {
<template>
<div
class="border-b border-default-background-separator transition min-w-0"
class="border-b border-default-background-separator transition min-w-0 bg-row-background"
data-testid="time_entry_row">
<MainContainer class="min-w-0">
<div

View File

@@ -64,7 +64,7 @@ function selectInput(event: Event) {
<input
v-model="currentTime"
data-testid="time_entry_duration_input"
class="text-white w-[90px] px-2 py-1.5 bg-transparent text-center hover:bg-card-background rounded-lg border border-transparent hover:border-card-border text-sm font-semibold focus-visible:bg-tertiary focus-visible:border-transparent focus-visible:ring-2 focus-visible:ring-ring"
class="text-text-primary w-[90px] px-2 py-1.5 bg-transparent text-center hover:bg-card-background rounded-lg border border-transparent hover:border-card-border text-sm font-semibold focus-visible:bg-tertiary focus-visible:border-transparent focus-visible:ring-2 focus-visible:ring-ring"
@focus="selectInput"
@keydown.tab="open = false"
@blur="updateTimerAndStartLiveTimerUpdate"

View File

@@ -27,13 +27,13 @@ function selectUnselectAll(value: boolean) {
<template>
<div
class="bg-card-background border-t border-b border-card-border py-1 text-xs sm:text-sm">
class="bg-row-heading-background border-t border-b border-row-heading-border py-1 text-xs sm:text-sm">
<MainContainer>
<div class="flex group justify-between items-center">
<div class="flex items-center space-x-2">
<div class="w-5">
<svg
class="w-4 sm:w-5 text-muted group-hover:hidden block"
class="w-4 sm:w-5 text-icon-default group-hover:hidden block"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<g fill="none">
@@ -49,7 +49,7 @@ function selectUnselectAll(value: boolean) {
class="group-hover:block hidden"
@update:checked="selectUnselectAll"></Checkbox>
</div>
<span class="font-semibold text-white">
<span class="font-semibold text-text-primary">
{{ formatWeekday(date) }}
</span>
<span class="font-semibold text-muted">

View File

@@ -211,7 +211,7 @@ useSelectEvents(filteredRecentlyTrackedTimeEntries,
v-model="tempDescription"
placeholder="What are you working on?"
data-testid="time_entry_description"
class="w-full rounded-l-lg py-4 sm:py-2.5 px-3.5 border-b border-b-card-background-separator @2xl:px-4 text-base @4xl:text-lg text-white font-medium bg-transparent border-none placeholder-muted focus:ring-0 transition"
class="w-full rounded-l-lg py-4 sm:py-2.5 px-3.5 border-b border-b-card-background-separator @2xl:px-4 text-base @4xl:text-lg text-text-primary font-medium bg-transparent border-none placeholder-muted focus:ring-0 transition"
type="text"
@keydown.enter="startTimerIfNotActive"
@keydown.esc="showDropdown = false"
@@ -222,7 +222,7 @@ useSelectEvents(filteredRecentlyTrackedTimeEntries,
class="z-50 w-full max-w-2xl"
:style="floatingStyles">
<div
class="rounded-lg ring-1 w-full fixed min-w-xl top-0 left-0 ring-black ring-opacity-5 border border-card-border overflow-none shadow-dropdown bg-card-background">
class="rounded-lg w-full fixed min-w-xl top-0 left-0 border border-card-border overflow-none shadow-dropdown bg-card-background">
<div
class="text-text-tertiary text-xs font-semibold border-b border-border-tertiary px-2 py-1.5">
Recently Tracked Time Entries

View File

@@ -594,7 +594,7 @@ const showCreateProject = ref(false);
ref="searchInput"
:value="searchValue"
data-testid="client_dropdown_search"
class="bg-card-background border-0 placeholder-muted text-sm text-white py-2.5 focus:ring-0 border-b border-card-background-separator focus:border-card-background-separator w-full"
class="bg-card-background border-0 placeholder-muted text-sm text-text-primary py-2.5 focus:ring-0 border-b border-card-background-separator focus:border-card-background-separator w-full"
placeholder="Search for a project or task..."
@input="updateSearchValue"
@keydown.enter.prevent="addClientIfNoneExists"
@@ -694,7 +694,7 @@ const showCreateProject = ref(false);
'bg-card-background-active':
task.id === highlightedItemId,
}"
class="flex items-center space-x-2 w-full px-5 py-1.5 text-start text-xs font-semibold leading-5 text-white focus:outline-none focus:bg-card-background-active transition duration-150 ease-in-out"
class="flex items-center space-x-2 w-full px-5 py-1.5 text-start text-xs font-semibold leading-5 text-text-primary focus:outline-none focus:bg-card-background-active transition duration-150 ease-in-out"
@click="selectTask(task.id)"
@mouseenter="setHighlightItemId(task.id)">
<MinusIcon
@@ -709,7 +709,7 @@ const showCreateProject = ref(false);
v-if="canCreateProject"
class="hover:bg-card-background-active rounded-b-lg">
<button
class="text-white flex space-x-3 items-center px-4 py-3 text-xs font-semibold border-t border-card-background-separator"
class="text-text-primary flex space-x-3 items-center px-4 py-3 text-xs font-semibold border-t border-card-background-separator"
@click="
open = false;
showCreateProject = true;

View File

@@ -179,7 +179,7 @@ function closeAndFocusInput() {
v-model="currentTime"
placeholder="00:00:00"
data-testid="time_entry_time"
class="w-[110px] lg:w-[130px] h-full text-white py-2.5 rounded-lg border-border-secondary border text-center px-4 text-base lg:text-lg font-bold bg-card-background border-none placeholder-muted focus:ring-0 transition"
class="w-[110px] lg:w-[130px] h-full text-text-primary py-2.5 rounded-lg border-border-secondary border text-center px-4 text-base lg:text-lg font-semibold bg-card-background border-none placeholder-muted focus:ring-0 transition"
type="text"
@focus="pauseLiveTimerUpdate"
@focusin="openModalOnTab"

View File

@@ -12,7 +12,7 @@ defineEmits<{
<div
class="w-full h-[calc(100%+10px)] absolute bg-default-background opacity-75 backdrop-blur-sm"></div>
<div class="flex space-x-3 items-center w-full z-20 justify-center">
<span class="text-sm text-white">
<span class="text-sm text-text-primary">
The Timer is running in a different organization.
</span>
<SecondaryButton @click="$emit('switchOrganization')"

View File

@@ -14,7 +14,7 @@ const model = defineModel<string[]>({
});
const iconColorClasses = computed(() => {
if (model.value.length > 0) {
return 'text-accent-200/80 focus:text-accent-200 hover:text-accent-200';
return 'text-input-select-active focus:text-input-select-active-hover hover:text-input-select-active-hover';
} else {
return 'text-icon-default hover:text-icon-active focus:text-icon-active';
}