diff --git a/package.json b/package.json index c4bbe325..e2a26cc1 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "@sentry/tracing": "6.15.0", "@sentry/vue": "6.15.0", "@vue/compat": "3.2.22", - "bulma": "0.9.3", + "@vueuse/core": "^6.8.0", + "bulma-css-variables": "^0.9.33", "camel-case": "4.1.2", "codemirror": "5.64.0", "copy-to-clipboard": "3.3.1", diff --git a/src/App.vue b/src/App.vue index af2fc690..5eacb532 100644 --- a/src/App.vue +++ b/src/App.vue @@ -33,6 +33,7 @@ import ContentNoAuth from './components/home/contentNoAuth' import {setLanguage} from './i18n' import AccountDeleteService from '@/services/accountDelete' import Ready from '@/components/misc/ready' +import {useColorScheme} from '@/composables/useColorScheme' export default defineComponent({ name: 'app', @@ -54,6 +55,9 @@ export default defineComponent({ beforeCreate() { setLanguage() }, + setup() { + useColorScheme() + }, created() { // Make sure to always load the home route when running with electron if (this.$route.fullPath.endsWith('frontend/index.html')) { diff --git a/src/assets/logo-full-pride.svg b/src/assets/logo-full-pride.svg index f7d6527f..1ecacb3e 100644 --- a/src/assets/logo-full-pride.svg +++ b/src/assets/logo-full-pride.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/assets/logo-full.svg b/src/assets/logo-full.svg index c5e728a3..20b6ae13 100644 --- a/src/assets/logo-full.svg +++ b/src/assets/logo-full.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/components/home/Logo.vue b/src/components/home/Logo.vue index cea2d0f0..5a5612b4 100644 --- a/src/components/home/Logo.vue +++ b/src/components/home/Logo.vue @@ -7,5 +7,11 @@ const Logo = computed(() => new Date().getMonth() === 5 ? LogoFullPride : LogoFu - - \ No newline at end of file + + + + \ No newline at end of file diff --git a/src/components/home/MenuButton.vue b/src/components/home/MenuButton.vue index 14a2e469..ab012c92 100644 --- a/src/components/home/MenuButton.vue +++ b/src/components/home/MenuButton.vue @@ -43,7 +43,7 @@ $size: $lineWidth + 1rem; width: $lineWidth; left: 50%; transform: $transformX; - background-color: $grey-400; + background-color: var(--grey-400); border-radius: 2px; transition: all $transition; } @@ -62,7 +62,7 @@ $size: $lineWidth + 1rem; &:focus { &::before, &::after { - background-color: $grey-600; + background-color: var(--grey-600); } &::before { diff --git a/src/components/home/PoweredByLink.vue b/src/components/home/PoweredByLink.vue index e174ba69..06ff3b11 100644 --- a/src/components/home/PoweredByLink.vue +++ b/src/components/home/PoweredByLink.vue @@ -10,7 +10,7 @@ import {POWERED_BY as poweredByUrl} from '@/urls' diff --git a/src/components/home/navigation.vue b/src/components/home/navigation.vue index 5f9d1a21..84117027 100644 --- a/src/components/home/navigation.vue +++ b/src/components/home/navigation.vue @@ -280,8 +280,8 @@ export default { \ No newline at end of file diff --git a/src/components/misc/card.vue b/src/components/misc/card.vue index a9632f7b..e5a56872 100644 --- a/src/components/misc/card.vue +++ b/src/components/misc/card.vue @@ -63,22 +63,22 @@ export default { \ No newline at end of file diff --git a/src/components/misc/legal.vue b/src/components/misc/legal.vue index ff74921a..c4e7c21e 100644 --- a/src/components/misc/legal.vue +++ b/src/components/misc/legal.vue @@ -22,7 +22,7 @@ export default { .legal-links { margin-top: 1rem; text-align: right; - color: $grey-300; + color: var(--grey-300); font-size: 1rem; } \ No newline at end of file diff --git a/src/components/misc/no-auth-wrapper.vue b/src/components/misc/no-auth-wrapper.vue index aea25daf..22832fe9 100644 --- a/src/components/misc/no-auth-wrapper.vue +++ b/src/components/misc/no-auth-wrapper.vue @@ -26,7 +26,7 @@ const motd = computed(() => store.state.config.motd) diff --git a/src/components/misc/ready.vue b/src/components/misc/ready.vue index 5f199ca8..0bc2df84 100644 --- a/src/components/misc/ready.vue +++ b/src/components/misc/ready.vue @@ -98,7 +98,7 @@ export default { left: 0; bottom: 0; right: 0; - background: $grey-100; + background: var(--grey-100); z-index: 99; } @@ -112,8 +112,8 @@ export default { margin-right: 1rem; &.is-loading::after { - border-left-color: $grey-400; - border-bottom-color: $grey-400; + border-left-color: var(--grey-400); + border-bottom-color: var(--grey-400); } } diff --git a/src/components/misc/shortcut.vue b/src/components/misc/shortcut.vue index 8c1809ea..77c7539a 100644 --- a/src/components/misc/shortcut.vue +++ b/src/components/misc/shortcut.vue @@ -35,8 +35,8 @@ export default { kbd { padding: .1rem .35rem; - border: 1px solid $grey-300; - background: $grey-100; + border: 1px solid var(--grey-300); + background: var(--grey-100); border-radius: 3px; font-size: .75rem; } diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue index b67d8816..73dedd8f 100644 --- a/src/components/notifications/notifications.vue +++ b/src/components/notifications/notifications.vue @@ -145,9 +145,9 @@ export default { width: .75rem; height: .75rem; - background: $primary; + background: var(--primary); border-radius: 100%; - border: 2px solid $white; + border: 2px solid var(--white); } .notifications-list { @@ -157,12 +157,12 @@ export default { max-height: 400px; overflow-y: auto; - background: $white; + background: var(--white); width: 350px; max-width: calc(100vw - 2rem); padding: .75rem .25rem; border-radius: $radius; - box-shadow: $shadow-sm; + box-shadow: var(--shadow-sm); font-size: .85rem; @media screen and (max-width: $tablet) { @@ -183,14 +183,14 @@ export default { transition: background-color $transition; &:hover { - background: $grey-100; + background: var(--grey-100); border-radius: $radius; } .read-indicator { width: .35rem; height: .35rem; - background: $primary; + background: var(--primary); border-radius: 100%; margin-left: .5rem; @@ -219,7 +219,7 @@ export default { } .created { - color: $grey-400; + color: var(--grey-400); } &:last-child { @@ -227,14 +227,14 @@ export default { } a { - color: $grey-800; + color: var(--grey-800); } } .nothing { text-align: center; padding: 1rem 0; - color: $grey-500; + color: var(--grey-500); .explainer { font-size: .75rem; diff --git a/src/components/quick-actions/quick-actions.vue b/src/components/quick-actions/quick-actions.vue index 3e8c38d1..0546eeb8 100644 --- a/src/components/quick-actions/quick-actions.vue +++ b/src/components/quick-actions/quick-actions.vue @@ -513,11 +513,11 @@ export default { .results { text-align: left; width: 100%; - color: $grey-800; + color: var(--grey-800); .result { &-title { - background: $grey-50; + background: var(--grey-50); padding: .5rem; display: block; font-size: .75rem; @@ -528,6 +528,7 @@ export default { font-size: .9rem; width: 100%; background: transparent; + color: var(--grey-800); text-align: left; box-shadow: none; border-radius: 0; @@ -539,12 +540,12 @@ export default { cursor: pointer; &:focus, &:hover { - background: $grey-50; + background: var(--grey-50); box-shadow: none !important; } &:active { - background: $grey-100; + background: var(--grey-100); } } } diff --git a/src/components/tasks/edit-task.vue b/src/components/tasks/edit-task.vue index 4cb8d857..90f6adb7 100644 --- a/src/components/tasks/edit-task.vue +++ b/src/components/tasks/edit-task.vue @@ -167,7 +167,7 @@ ul.assingees { a { float: right; - color: $red; + color: var(--danger); transition: all $transition; } } diff --git a/src/components/tasks/gantt-component.vue b/src/components/tasks/gantt-component.vue index 4b401e90..ca88ce15 100644 --- a/src/components/tasks/gantt-component.vue +++ b/src/components/tasks/gantt-component.vue @@ -445,12 +445,12 @@ export default { \ No newline at end of file diff --git a/src/components/tasks/partials/priorityLabel.vue b/src/components/tasks/partials/priorityLabel.vue index 11e4d017..0625412b 100644 --- a/src/components/tasks/partials/priorityLabel.vue +++ b/src/components/tasks/partials/priorityLabel.vue @@ -54,7 +54,7 @@ export default { } span.high-priority { - color: $red; + color: var(--danger); width: auto !important; // To override the width set in tasks .icon { @@ -64,7 +64,7 @@ span.high-priority { } &.not-so-high { - color: $orange; + color: var(--warning); } } \ No newline at end of file diff --git a/src/components/tasks/partials/relatedTasks.vue b/src/components/tasks/partials/relatedTasks.vue index 6e99775f..961949be 100644 --- a/src/components/tasks/partials/relatedTasks.vue +++ b/src/components/tasks/partials/relatedTasks.vue @@ -310,7 +310,7 @@ export default { } .different-list { - color: $grey-500; + color: var(--grey-500); width: auto; } @@ -332,21 +332,21 @@ export default { border-radius: $radius; &:hover { - background-color: $grey-200; + background-color: var(--grey-200); } a { - color: $text; + color: var(--text); transition: color ease $transition-duration; &:hover { - color: $grey-900; + color: var(--grey-900); } } .remove { text-align: center; - color: $red; + color: var(--danger); opacity: 0; transition: opacity $transition; } diff --git a/src/components/tasks/partials/reminders.vue b/src/components/tasks/partials/reminders.vue index 9d2a629f..45a0ceab 100644 --- a/src/components/tasks/partials/reminders.vue +++ b/src/components/tasks/partials/reminders.vue @@ -112,7 +112,7 @@ export default { align-items: center; &.overdue :deep(.datepicker a.show) { - color: $red; + color: var(--danger); } &:last-child { @@ -120,7 +120,7 @@ export default { } a.remove { - color: $red; + color: var(--danger); padding-left: .5rem; } } diff --git a/src/components/tasks/partials/singleTaskInList.vue b/src/components/tasks/partials/singleTaskInList.vue index da679bca..9e955d5c 100644 --- a/src/components/tasks/partials/singleTaskInList.vue +++ b/src/components/tasks/partials/singleTaskInList.vue @@ -227,7 +227,7 @@ export default { border: 2px solid transparent; &:hover { - background-color: $grey-100; + background-color: var(--grey-100); } .tasktext, @@ -239,13 +239,13 @@ export default { flex: 1 0 50%; .overdue { - color: $red; + color: var(--danger); } } .task-list { width: auto; - color: $grey-400; + color: var(--grey-400); font-size: .9rem; white-space: nowrap; } @@ -273,11 +273,11 @@ export default { } a { - color: $text; + color: var(--text); transition: color ease $transition-duration; &:hover { - color: $grey-900; + color: var(--grey-900); } } @@ -288,12 +288,12 @@ export default { transition: opacity $transition, color $transition; &:hover { - color: $orange; + color: var(--warning); } &.is-favorite { opacity: 1; - color: $orange; + color: var(--warning); } } @@ -324,16 +324,16 @@ export default { .tasktext.done { text-decoration: line-through; - color: $grey-500; + color: var(--grey-500); } span.parent-tasks { - color: $grey-500; + color: var(--grey-500); width: auto; } .remove { - color: $red; + color: var(--danger); } input[type="checkbox"] { @@ -351,8 +351,8 @@ export default { left: calc(50% - 1rem); width: 2rem; height: 2rem; - border-left-color: $grey-300; - border-bottom-color: $grey-300; + border-left-color: var(--grey-300); + border-bottom-color: var(--grey-300); } } \ No newline at end of file diff --git a/src/composables/useColorScheme.ts b/src/composables/useColorScheme.ts new file mode 100644 index 00000000..f4bf2b25 --- /dev/null +++ b/src/composables/useColorScheme.ts @@ -0,0 +1,48 @@ +import {computed, watch, readonly} from 'vue' +import {useStorage, createSharedComposable, ColorSchemes, usePreferredColorScheme, tryOnMounted} from '@vueuse/core' + +const STORAGE_KEY = 'color-scheme' + +const DEFAULT_COLOR_SCHEME_SETTING: ColorSchemes = 'light' + +const CLASS_DARK = 'dark' +const CLASS_LIGHT = 'light' + +// This is built upon the vueuse useDark +// Main differences: +// - usePreferredColorScheme +// - doesn't allow setting via the `isDark` ref. +// - instead the store is exposed +// - value is synced via `createSharedComposable` +// https://github.com/vueuse/vueuse/blob/main/packages/core/useDark/index.ts +export const useColorScheme = createSharedComposable(() => { + const store = useStorage(STORAGE_KEY, DEFAULT_COLOR_SCHEME_SETTING) + + const preferredColorScheme = usePreferredColorScheme() + + const isDark = computed(() => { + if (store.value !== 'auto') { + return store.value === 'dark' + } + + const autoColorScheme = preferredColorScheme.value === 'no-preference' + ? DEFAULT_COLOR_SCHEME_SETTING + : preferredColorScheme.value + return autoColorScheme === 'dark' + }) + + function onChanged(v: boolean) { + const el = window?.document.querySelector('html') + el?.classList.toggle(CLASS_DARK, v) + el?.classList.toggle(CLASS_LIGHT, !v) + } + + watch(isDark, onChanged, { flush: 'post' }) + + tryOnMounted(() => onChanged(isDark.value)) + + return { + store, + isDark: readonly(isDark), + } +}) \ No newline at end of file diff --git a/src/i18n/lang/en.json b/src/i18n/lang/en.json index 9889189b..f7bb9f74 100644 --- a/src/i18n/lang/en.json +++ b/src/i18n/lang/en.json @@ -112,6 +112,15 @@ "disabled": "Disabled", "todoist": "Todoist", "vikunja": "Vikunja" + }, + "appearance": { + "title": "Color Scheme", + "setSuccess": "Saved change of color scheme to {colorScheme}", + "colorScheme": { + "light": "Light", + "system": "System", + "dark": "Dark" + } } }, "deletion": { diff --git a/src/styles/common-imports.scss b/src/styles/common-imports.scss new file mode 100644 index 00000000..2ac71b2c --- /dev/null +++ b/src/styles/common-imports.scss @@ -0,0 +1,44 @@ +// +// IMPORTANT NOTE: +// +// The styles in this file and all imported styles should not +// create CSS output when compiled! +// Instead they should only define SCSS that gets compiled to nothing. +// +// The reason is that this file is prefixed in _every_ component style so that +// the component has access to the variables, mixins, etc. that +// are defined here. +// + +// the default values get overwritten by the definitions above +@import "bulma-css-variables/sass/utilities/_all"; + +// since $tablet is defined by bulma we can just define it after importing the utilities +$mobile: math.div($tablet, 2); + +$family-sans-serif: 'Open Sans', Helvetica, Arial, sans-serif; +$vikunja-font: 'Quicksand', sans-serif; + +$thickness: 1px; +$pagination-current-border: var(--primary); +$navbar-item-active-color: var(--primary); + +$dropdown-content-shadow: none; +$dropdown-item-hover-background-color: var(--grey-100); + +$bulmaswatch-import-font: false !default; +$site-background: var(--grey-100); + +$transition-duration: 150ms; +$transition: $transition-duration ease; + +$button-height: 34px; +$switch-view-height: 2.69rem; + +$navbar-height: 4rem; +$navbar-width: 300px; +$navbar-icon-width: 40px; + +$lists-per-row: 5; +$list-height: 150px; +$list-spacing: 1rem; \ No newline at end of file diff --git a/src/styles/components/labels.scss b/src/styles/components/labels.scss index ee06d3f2..04970265 100644 --- a/src/styles/components/labels.scss +++ b/src/styles/components/labels.scss @@ -6,7 +6,7 @@ .tag { margin: .5rem 0 .5rem .5rem; - background: $grey-200; + background: var(--grey-200); // FIXME: only used in ListLabels.vue &.disabled { diff --git a/src/styles/components/task.scss b/src/styles/components/task.scss index 3db35644..4a2b565e 100644 --- a/src/styles/components/task.scss +++ b/src/styles/components/task.scss @@ -7,8 +7,8 @@ .modal-container .task-view { border-radius: $radius; padding: 1rem; - color: $text; - background-color: $light-background !important; + color: var(--text); + background-color: var(--site-background) !important; @media screen and (max-width: 800px) { border-radius: 0; diff --git a/src/styles/components/tooltip.scss b/src/styles/components/tooltip.scss index 20acf579..a5b77b3d 100644 --- a/src/styles/components/tooltip.scss +++ b/src/styles/components/tooltip.scss @@ -5,7 +5,7 @@ z-index: 10000; font-size: 0.8rem; text-align: center; - background: $dark; + background: var(--dark); color: white; border-radius: 5px; padding: 5px 10px 5px; @@ -28,7 +28,7 @@ height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent; - border-top: 5px solid $dark; + border-top: 5px solid var(--dark); &.bottom { transform: rotate(180deg); diff --git a/src/styles/custom-properties/_index.scss b/src/styles/custom-properties/_index.scss new file mode 100644 index 00000000..72cd3ac1 --- /dev/null +++ b/src/styles/custom-properties/_index.scss @@ -0,0 +1,2 @@ +@import "colors"; +@import "shadows"; \ No newline at end of file diff --git a/src/styles/custom-properties/colors.scss b/src/styles/custom-properties/colors.scss new file mode 100644 index 00000000..6e379ded --- /dev/null +++ b/src/styles/custom-properties/colors.scss @@ -0,0 +1,122 @@ +// Vikunja colors as CSS custom properties + +:root { + // Vikunja specific variables + --grey-50: hsl(210, 20%, 98%); + --grey-100: hsl(220, 14.3%, 95.9%); + --grey-200: hsl(220, 13%, 91%); + --grey-300: hsl(216, 12.2%, 83.9%); + --grey-400: hsl(217.9, 10.6%, 64.9%); + --grey-500-hsl: 220, 8.9%, 46.1%; + --grey-500: hsl(var(--grey-500-hsl)); + --grey-600: hsl(215, 13.8%, 34.1%); + --grey-700: hsl(216.9, 19.1%, 26.7%); + --grey-800: hsl(215, 27.9%, 16.9%); + --grey-900: hsl(220.9, 39.3%, 11%); + --site-background: var(--grey-100); + --scheme-main: var(--white); + + // Overrides of Bulma defaults + --grey-darker: var(--grey-700); + --grey-dark: var(--grey-800); + --grey: var(--grey-500); + --grey-light: var(--grey-300); + --grey-lighter: var(--grey-200); + --grey-lightest: var(--grey-100); + --input-border-color: var(--grey-200); + + --white-h: 0deg; + --white-s: 0%; + --white-l: 100%; + --white-a: 1; + --white: hsla(var(--white-h), var(--white-s), var(--white-l), var(--white-a)); + --white-translucent: hsla(var(--white-h), var(--white-s), var(--white-l), 0.75); + + --black-h: 0deg; + --black-s: 0%; + --black-l: 4%; + --black-a: 1; + --black: hsla(var(--black-h), var(--black-s), var(--black-l), var(--black-a)); + + // $warning / $orange: #ff851b + --warning-h: 27.9deg; + --warning-s: 100%; + --warning-l: 55.3%; + --warning-a: 1; + --warning: hsla(var(--warning-h), var(--warning-s), var(--warning-l), var(--warning-a)); + + // $success / $green is #00db60 + --success-h: 146.3deg; + --success-s: 100%; + --success-l: 42.9%; + --success-a: 1; + --success: hsla(var(--success-h), var(--success-s), var(--success-l), var(--success-a)); + + // $danger / $red is #ff4136 + --danger-h: 3.3deg; + --danger-s: 100%; + --danger-l: 60.6%; + --danger-a: 1; + --danger: hsla(var(--danger-h), var(--danger-s), var(--danger-l), var(--danger-a)); + + // var(--primary) / $blue is #1973ff + --primary-h: 216.5deg; + --primary-s: 100%; + --primary-l: 54.9%; + --primary-a: 1; + --primary-hsl: var(--primary-h), var(--primary-s), var(--primary-l); + --primary: hsla(var(--primary-h), var(--primary-s), var(--primary-l), var(--primary-a)); + // END Overrides of Bulma defaults + + + // Define custom color variable to prevent change in dark mode + --switch-view-color: hsla(var(--white-h), var(--white-s), var(--white-l), var(--white-a)); + + // Define custom color variable to alow change in dark mode + --card-border-color: var(--grey-200); + --logo-text-color: hsl(180, 1%, 15%); + + + + &.dark { + // Light mode colours reversed for dark mode + --grey-900-hsl: 210, 20%, 98%; + --grey-900: hsl(var(--grey-900-hsl)); + --grey-800: hsl(220, 14.3%, 95.9%); + --grey-700: hsl(220, 13%, 91%); + --grey-600: hsl(216, 12.2%, 83.9%); + --grey-500-hsl: 217.9, 10.6%, 64.9%; + --grey-500: hsl(var(--grey-500-hsl)); + --grey-400: hsl(220, 8.9%, 46.1%); + --grey-300: hsl(215, 13.8%, 34.1%); + --grey-200: hsl(216.9, 19.1%, 26.7%); + --grey-100-hsl: 215, 27.9%, 16.9%; + --grey-100: hsl(var(--grey-100-hsl)); + --grey-50-hsl: 220.9, 39.3%, 11%; + --grey-50: hsl(var(--grey-50-hsl)); + + // Dark grey looks better than black + --white: var(--grey-50); + --black-l: 100%; + + // Text renders better in grey than black + --text: var(--grey-800); + --text-invert: #000; + --text-light: var(--grey-300); + --text-strong: var(--grey-900); + + // Elements that rely on Bulma defaults in light mode but + // need to be overriden in dark mode + --input-placeholder-color: hsla(var(--grey-900-hsl), 0.6); + --tag-color: var(--grey-50); + --table-row-hover-background-color: var(--grey-100); + --dropdown-item-hover-background-color: var(--grey-100); + --dropdown-item-hover-color: var(--text); + --button-text-hover-background-color: var(--grey-200); + --button-hover-color: var(--grey-600); + + // Custom color variables we need to override + --card-border-color: hsla(var(--grey-100-hsl), 0.3); + --logo-text-color: var(--grey-700); + } +} \ No newline at end of file diff --git a/src/styles/custom-properties/shadows.scss b/src/styles/custom-properties/shadows.scss new file mode 100644 index 00000000..5f040ca1 --- /dev/null +++ b/src/styles/custom-properties/shadows.scss @@ -0,0 +1,22 @@ +:root { + --shadow-xs: 0 1px 3px hsla(var(--grey-500-hsl), .12), + 0 1px 2px hsla(var(--grey-500-hsl), .24); + --shadow-sm: 0 3px 6px hsla(var(--grey-500-hsl), .12), + 0 2px 4px hsla(var(--grey-500-hsl), .10); + --shadow-md: 0 10px 20px hsla(var(--grey-500-hsl), .12), + 0 3px 6px hsla(var(--grey-500-hsl), .08); + --shadow-lg: 0 15px 25px hsla(var(--grey-500-hsl), .12), + 0 5px 10px hsla(var(--grey-500-hsl), .05); + + &.dark { + // Even darker shadows for dark mode + --shadow-xs: 0 1px 3px hsla(var(--grey-50-hsl), 0.4), + 0 1px 2px hsla(var(--grey-50-hsl), 0.8); + --shadow-sm: 0 3px 6px hsla(var(--grey-50-hsl), 0.8), + 0 2px 4px hsla(var(--grey-50-hsl), 0.6); + --shadow-md: 0 10px 20px hsla(var(--grey-50-hsl), 0.8), + 0 3px 6px hsla(var(--grey-50-hsl), 0.6); + --shadow-lg: 0 15px 25px hsla(var(--grey-50-hsl), 0.8), + 0 5px 10px hsla(var(--grey-50-hsl), 0.4); + } +} \ No newline at end of file diff --git a/src/styles/fonts.scss b/src/styles/fonts.scss index 184f777c..b8031630 100644 --- a/src/styles/fonts.scss +++ b/src/styles/fonts.scss @@ -1,6 +1,6 @@ $font-files-path: '/fonts/'; -/* quicksand-regular - latin */ +// quicksand-regular - latin @font-face { font-family: 'Quicksand'; font-style: normal; @@ -10,7 +10,7 @@ $font-files-path: '/fonts/'; } -/* quicksand-500 - latin */ +// quicksand-500 - latin @font-face { font-family: 'Quicksand'; font-style: normal; @@ -19,7 +19,7 @@ $font-files-path: '/fonts/'; src: url($font-files-path + 'quicksand-v7-latin-500.woff2') format('woff2'); } -/* quicksand-700 - latin */ +// quicksand-700 - latin @font-face { font-family: 'Quicksand'; font-style: normal; @@ -28,7 +28,7 @@ $font-files-path: '/fonts/'; src: url($font-files-path + 'quicksand-v7-latin-700.woff2') format('woff2'); } -/* open-sans-regular - latin */ +// open-sans-regular - latin @font-face { font-family: 'Open Sans'; font-style: normal; @@ -37,7 +37,7 @@ $font-files-path: '/fonts/'; src: url($font-files-path + 'open-sans-v15-latin-regular.woff2') format('woff2'); } -/* open-sans-italic - latin */ +// open-sans-italic - latin @font-face { font-family: 'Open Sans'; font-style: italic; @@ -46,7 +46,7 @@ $font-files-path: '/fonts/'; src: url($font-files-path + 'open-sans-v15-latin-italic.woff2') format('woff2'); } -/* open-sans-700 - latin */ +// open-sans-700 - latin @font-face { font-family: 'Open Sans'; font-style: normal; @@ -55,7 +55,7 @@ $font-files-path: '/fonts/'; src: url($font-files-path + 'open-sans-v15-latin-700.woff2') format('woff2'); } -/* open-sans-700italic - latin */ +// open-sans-700italic - latin @font-face { font-family: 'Open Sans'; font-style: italic; diff --git a/src/styles/global.scss b/src/styles/global.scss index 1aa66c09..6f969443 100644 --- a/src/styles/global.scss +++ b/src/styles/global.scss @@ -5,13 +5,15 @@ // This imports are the same as in "bulma/bulma.sass" // with the expeption of the bulma utilities. // They are imported globally in variables.scss -@import "bulma/sass/base/_all"; -@import "bulma/sass/elements/_all"; -@import "bulma/sass/form/_all"; -@import "bulma/sass/components/_all"; -@import "bulma/sass/grid/_all"; -@import "bulma/sass/helpers/_all"; -@import "bulma/sass/layout/_all"; +@import "bulma-css-variables/sass/base/_all"; +@import "bulma-css-variables/sass/elements/_all"; +@import "bulma-css-variables/sass/form/_all"; +@import "bulma-css-variables/sass/components/_all"; +@import "bulma-css-variables/sass/grid/_all"; +@import "bulma-css-variables/sass/helpers/_all"; +@import "bulma-css-variables/sass/layout/_all"; @import "theme"; -@import "components"; \ No newline at end of file +@import "components"; + +@import "custom-properties"; \ No newline at end of file diff --git a/src/styles/theme/background.scss b/src/styles/theme/background.scss index e57ef22c..b03b04f4 100644 --- a/src/styles/theme/background.scss +++ b/src/styles/theme/background.scss @@ -8,7 +8,7 @@ // FIXME: move to pagination component .pagination-link:not(.is-current) { - background: $light-background; + background: var(--grey-100); } .box, diff --git a/src/styles/theme/content.scss b/src/styles/theme/content.scss index 4be780b1..08eadd1c 100644 --- a/src/styles/theme/content.scss +++ b/src/styles/theme/content.scss @@ -6,7 +6,7 @@ } .table.has-actions { - border-top: 1px solid $grey-100; + border-top: 1px solid var(--grey-100); border-radius: 4px; overflow: hidden; diff --git a/src/styles/theme/scrollbars.scss b/src/styles/theme/scrollbars.scss index 29d24106..c985376e 100644 --- a/src/styles/theme/scrollbars.scss +++ b/src/styles/theme/scrollbars.scss @@ -1,7 +1,7 @@ $scrollbar-height: 8px; -$scrollbar-track-color: $grey-200; -$scrollbar-thumb-color: $grey-300; -$scrollbar-hover-color: $grey-500; +$scrollbar-track-color: var(--grey-200); +$scrollbar-thumb-color: var(--grey-300); +$scrollbar-hover-color: var(--grey-500); // Chrome ::-webkit-scrollbar { diff --git a/src/styles/theme/theme.scss b/src/styles/theme/theme.scss index b674dfae..77a9ec06 100644 --- a/src/styles/theme/theme.scss +++ b/src/styles/theme/theme.scss @@ -6,7 +6,7 @@ } :focus { - box-shadow: 0 0 0 2px rgba($primary, 0.5); + box-shadow: 0 0 0 2px hsla(var(--primary-hsl), 0.5); } :focus:not(:focus-visible) { @@ -15,11 +15,11 @@ :focus-visible, :-moz-focusring { - box-shadow: 0 0 0 2px rgba($primary, 0.5); + box-shadow: 0 0 0 2px hsla(var(--primary-hsl), 0.5); } body { - background: $light-background; + background: var(--site-background); min-height: 100vh; } @@ -45,7 +45,7 @@ h6 { &::-moz-progress-bar, &::-webkit-progress-value { - background: $grey-500; + background: var(--grey-500); } @media screen and (max-width: $tablet) { @@ -94,11 +94,11 @@ button.table { } .icon:not(.has-text-success) { - color: $grey-300 !important; + color: var(--grey-300) !important; } &.has-text-danger .icon { - color: $danger !important; + color: var(--danger) !important; } &.is-disabled { @@ -140,7 +140,7 @@ button.table { } .dropdown-menu .dropdown-content { - box-shadow: $shadow-md; + box-shadow: var(--shadow-md); } .is-strikethrough { @@ -156,6 +156,6 @@ button.table { } .box { - border: 1px solid $grey-200; - box-shadow: $shadow-sm; + border: 1px solid var(--grey-200); + box-shadow: var(--shadow-sm); } \ No newline at end of file diff --git a/src/styles/variables/_index.scss b/src/styles/variables/_index.scss deleted file mode 100644 index bef2ad0c..00000000 --- a/src/styles/variables/_index.scss +++ /dev/null @@ -1,12 +0,0 @@ -@import "colors"; -@import "shadows"; -@import "variables"; - -// the default values get overwritten by the definitions above -@import "bulma/sass/utilities/_all"; - -// this is needed so that the shared form variables are globally defined aswell -@import "bulma/sass/form/shared"; - -// since $tablet is defined by bulma we can just define it after importing the utilities -$mobile: math.div($tablet, 2); \ No newline at end of file diff --git a/src/styles/variables/colors.scss b/src/styles/variables/colors.scss deleted file mode 100644 index 09d04c1d..00000000 --- a/src/styles/variables/colors.scss +++ /dev/null @@ -1,18 +0,0 @@ -$grey-50: #F9FAFB; -$grey-100: #f3f4f6; -$grey-200: #E5E7EB; -$grey-300: #D1D5DB; -$grey-400: #9CA3AF; -$grey-500: #6B7280; -$grey-600: #4B5563; -$grey-700: #374151; -$grey-800: #1F2937; -$grey-900: #111827; - -// Bulma defaults -$grey-dark: $grey-800; -$grey-darker: $grey-700; -$grey: $grey-500; -$grey-light: $grey-300; -$grey-lighter: $grey-200; -$grey-lightest: $grey-100; diff --git a/src/styles/variables/shadows.scss b/src/styles/variables/shadows.scss deleted file mode 100644 index 5782efd9..00000000 --- a/src/styles/variables/shadows.scss +++ /dev/null @@ -1,5 +0,0 @@ -$shadow-xs: 0 1px 3px rgba($grey-500, .12), 0 1px 2px rgba($grey-500, .24); -$shadow-sm: 0 3px 6px rgba($grey-500, .12), 0 2px 4px rgba($grey-500, .10); -$shadow-md: 0 10px 20px rgba($grey-500, .12), 0 3px 6px rgba($grey-500, .08); -$shadow-lg: 0 15px 25px rgba($grey-500, .12), 0 5px 10px rgba($grey-500, .05); -$shadow-xl: 0 20px 40px rgba($grey-500, .2); diff --git a/src/styles/variables/variables.scss b/src/styles/variables/variables.scss deleted file mode 100644 index 6317d87a..00000000 --- a/src/styles/variables/variables.scss +++ /dev/null @@ -1,41 +0,0 @@ -$white: #fff; -$black: hsl(0, 0%, 4%) !default; -$orange: #ff851b; -$green: #00db60; -$red: #ff4136; -$blue: #1973ff; -$primary: $blue; - -$info-invert: $white; - -$family-sans-serif: 'Open Sans', Helvetica, Arial, sans-serif; -$vikunja-font: 'Quicksand', sans-serif; - -$thickness: 1px; -$pagination-current-border: $primary; -$navbar-item-active-color: $primary; - -$dropdown-content-shadow: none; -$dropdown-item-hover-background-color: $grey-100; - -$bulmaswatch-import-font: false !default; -$light-background: $grey-100; - -$transition-duration: 150ms; -$transition: $transition-duration ease; - -$button-height: 34px; - -$switch-view-height: 2.69rem; - -$user-dropdown-width-mobile: 5rem; -$hamburger-menu-icon-spacing: 1rem; -$hamburger-menu-icon-width: 28px; -$navbar-height: 4rem; -$navbar-width: 300px; -$navbar-icon-width: 40px; - - -$lists-per-row: 5; -$list-height: 150px; -$list-spacing: 1rem; diff --git a/src/views/list/ShowList.vue b/src/views/list/ShowList.vue index 87306923..5ed58909 100644 --- a/src/views/list/ShowList.vue +++ b/src/views/list/ShowList.vue @@ -166,11 +166,11 @@ export default { } .switch-view { - background: $white; + background: var(--white); display: inline-flex; border-radius: $radius; font-size: .75rem; - box-shadow: $shadow-sm; + box-shadow: var(--shadow-sm); height: $switch-view-height; margin-bottom: 1rem; padding: .5rem; @@ -187,18 +187,18 @@ export default { } &.is-active, - &:hover { - color: $white; + &:hover { + color: var(--switch-view-color); } &.is-active { - background: $primary; + background: var(--primary); font-weight: bold; - box-shadow: $shadow-xs; + box-shadow: var(--shadow-xs); } &:hover { - background: $primary; + background: var(--primary); } } } diff --git a/src/views/list/settings/background.vue b/src/views/list/settings/background.vue index bb3ead15..197fa001 100644 --- a/src/views/list/settings/background.vue +++ b/src/views/list/settings/background.vue @@ -167,7 +167,7 @@ export default { font-size: .8rem; a { - color: $grey-800; + color: var(--grey-800); } } @@ -224,7 +224,7 @@ export default { background: rgba(0, 0, 0, 0.5); font-size: .75rem; font-weight: bold; - color: $white; + color: var(--white); transition: opacity $transition; } diff --git a/src/views/list/views/Kanban.vue b/src/views/list/views/Kanban.vue index d2deb94f..61e5f693 100644 --- a/src/views/list/views/Kanban.vue +++ b/src/views/list/views/Kanban.vue @@ -581,7 +581,6 @@ export default { \ No newline at end of file diff --git a/src/views/namespaces/ListNamespaces.vue b/src/views/namespaces/ListNamespaces.vue index addaa596..e2b8f0dc 100644 --- a/src/views/namespaces/ListNamespaces.vue +++ b/src/views/namespaces/ListNamespaces.vue @@ -131,12 +131,12 @@ export default { .is-archived { font-size: 0.75rem; - border: 1px solid $grey-500; + border: 1px solid var(--grey-500); color: $grey !important; padding: 2px 4px; border-radius: 3px; font-family: $vikunja-font; - background: rgba($white, 0.75); + background: var(--white-translucent); margin-left: .5rem; } diff --git a/src/views/tasks/TaskDetailView.vue b/src/views/tasks/TaskDetailView.vue index 30f79e78..5f56df68 100644 --- a/src/views/tasks/TaskDetailView.vue +++ b/src/views/tasks/TaskDetailView.vue @@ -706,18 +706,18 @@ $flash-background-duration: 750ms; // This is a workaround to hide the llama background from the top on the task detail page margin-top: -1.5rem; padding: 1rem; - background-color: $light-background; + background-color: var(--site-background); @media screen and (max-width: $desktop) { padding-bottom: 0; } .subtitle { - color: $grey-500; + color: var(--grey-500); margin-bottom: 1rem; a { - color: $grey-800; + color: var(--grey-800); } } @@ -726,7 +726,7 @@ $flash-background-duration: 750ms; } .icon.is-grey { - color: $grey-400; + color: var(--grey-400); } :deep(.heading) { @@ -754,7 +754,7 @@ $flash-background-duration: 750ms; } .title.task-id { - color: $grey-400; + color: var(--grey-400); white-space: nowrap; } @@ -765,7 +765,7 @@ $flash-background-duration: 750ms; align-items: center; a.remove { - color: $red; + color: var(--danger); vertical-align: middle; padding-left: .5rem; line-height: 1; @@ -776,7 +776,7 @@ $flash-background-duration: 750ms; width: 100%; a.show { - color: $text; + color: var(--text); padding: .25rem .5rem; transition: background-color $transition; border-radius: $radius; @@ -784,7 +784,7 @@ $flash-background-duration: 750ms; margin: .1rem 0; &:hover { - background: $white; + background: var(--white); } } @@ -800,7 +800,7 @@ $flash-background-duration: 750ms; .detail-title { display: block; - color: $grey-400; + color: var(--grey-400); } .none { @@ -837,21 +837,24 @@ $flash-background-duration: 750ms; transition: all $transition-duration; &::placeholder { - color: $text-light; + color: var(--text-light); opacity: 1; font-style: italic; } &:not(:disabled) { - &:hover, &:active { - background: $input-background-color; - border-color: $input-border-color; + &:hover, + &:active, + &:focus { + background: var(--scheme-main); + border-color: var(--border); cursor: text; } - &:focus { - background: $input-background-color; - border-color: $input-focus-border-color; + &:hover, + &:active { + cursor: text; + border-color: var(--link) } } } @@ -883,18 +886,18 @@ $flash-background-duration: 750ms; .created { font-size: .75rem; - color: $grey-500; + color: var(--grey-500); text-align: right; } .checklist-summary { margin-left: .25rem; - } + } } .task-view-container { padding-bottom: 1rem; - + @media screen and (max-width: $desktop) { padding-bottom: 0; } @@ -917,6 +920,11 @@ $flash-background-duration: 750ms; } } +.task-view-container { + // simulate sass lighten($primary, 30) by increasing lightness 30% to 73% + --primary-light: hsla(var(--primary-h), var(--primary-s), 73%, var(--primary-a)); +} + .flash-background-enter-from, .flash-background-enter-active { animation: flash-background $flash-background-duration ease 1; @@ -924,7 +932,7 @@ $flash-background-duration: 750ms; @keyframes flash-background { 0% { - background: lighten($primary, 30); + background: var(--primary-light); } 100% { background: transparent; diff --git a/src/views/tasks/TaskDetailViewModal.vue b/src/views/tasks/TaskDetailViewModal.vue index 6deb7421..9b493246 100644 --- a/src/views/tasks/TaskDetailViewModal.vue +++ b/src/views/tasks/TaskDetailViewModal.vue @@ -2,6 +2,7 @@ @@ -53,11 +54,18 @@ export default { position: fixed; top: 5px; right: 26px; - color: $white; + color: var(--white); font-size: 2rem; @media screen and (max-width: $desktop) { - color: $dark; + color: var(--dark); } } + + + \ No newline at end of file diff --git a/src/views/teams/ListTeams.vue b/src/views/teams/ListTeams.vue index 2fc6f87e..503a8b3d 100644 --- a/src/views/teams/ListTeams.vue +++ b/src/views/teams/ListTeams.vue @@ -68,7 +68,7 @@ ul.teams { transition: background-color $transition; &:hover { - background: $grey-100; + background: var(--grey-100); } } } diff --git a/src/views/user/Settings.vue b/src/views/user/Settings.vue index 3cf78250..e7db1e18 100644 --- a/src/views/user/Settings.vue +++ b/src/views/user/Settings.vue @@ -83,13 +83,13 @@ const isLocalUser = computed(() => store.state.auth.info?.isLocalUser) a { display: block; padding: .5rem; - color: $dark; + color: var(--dark); width: 100%; border-left: 3px solid transparent; &:hover, &.router-link-active { - background: $white; - border-color: $primary; + background: var(--white); + border-color: var(--primary); } } } diff --git a/src/views/user/settings/Avatar.vue b/src/views/user/settings/Avatar.vue index 72e09753..2f9b74d6 100644 --- a/src/views/user/settings/Avatar.vue +++ b/src/views/user/settings/Avatar.vue @@ -149,6 +149,6 @@ export default { } .vue-advanced-cropper__background { - background: $white; + background: var(--white); } diff --git a/src/views/user/settings/General.vue b/src/views/user/settings/General.vue index db320542..347d1cc2 100644 --- a/src/views/user/settings/General.vue +++ b/src/views/user/settings/General.vue @@ -90,6 +90,21 @@ + + + + {{ $t('user.settings.appearance.title') }} + + + + + + {{ title }} + + + + +