Migrate to bulma-css-variables and introduce dark mode (#954)

Co-authored-by: Adrian Simmons <adrian@perlucida.co.uk>
Co-authored-by: Dominik Pschenitschni <mail@celement.de>
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/954
Reviewed-by: dpschen <dpschen@noreply.kolaente.de>
Reviewed-by: konrad <k@knt.li>
Co-authored-by: adrinux <adrian@perlucida.co.uk>
Co-committed-by: adrinux <adrian@perlucida.co.uk>
This commit is contained in:
adrinux 2021-11-22 21:12:54 +00:00 committed by konrad
parent 4ef54f1bc2
commit 46fa43d67f
73 changed files with 605 additions and 328 deletions

View file

@ -22,7 +22,8 @@
"@sentry/tracing": "6.15.0", "@sentry/tracing": "6.15.0",
"@sentry/vue": "6.15.0", "@sentry/vue": "6.15.0",
"@vue/compat": "3.2.22", "@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", "camel-case": "4.1.2",
"codemirror": "5.64.0", "codemirror": "5.64.0",
"copy-to-clipboard": "3.3.1", "copy-to-clipboard": "3.3.1",

View file

@ -33,6 +33,7 @@ import ContentNoAuth from './components/home/contentNoAuth'
import {setLanguage} from './i18n' import {setLanguage} from './i18n'
import AccountDeleteService from '@/services/accountDelete' import AccountDeleteService from '@/services/accountDelete'
import Ready from '@/components/misc/ready' import Ready from '@/components/misc/ready'
import {useColorScheme} from '@/composables/useColorScheme'
export default defineComponent({ export default defineComponent({
name: 'app', name: 'app',
@ -54,6 +55,9 @@ export default defineComponent({
beforeCreate() { beforeCreate() {
setLanguage() setLanguage()
}, },
setup() {
useColorScheme()
},
created() { created() {
// Make sure to always load the home route when running with electron // Make sure to always load the home route when running with electron
if (this.$route.fullPath.endsWith('frontend/index.html')) { if (this.$route.fullPath.endsWith('frontend/index.html')) {

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View file

@ -7,5 +7,11 @@ const Logo = computed(() => new Date().getMonth() === 5 ? LogoFullPride : LogoFu
</script> </script>
<template> <template>
<Logo alt="Vikunja" /> <Logo alt="Vikunja" class="logo" />
</template> </template>
<style lang="scss" scoped>
.logo {
color: var(--logo-text-color);
}
</style>

View file

@ -43,7 +43,7 @@ $size: $lineWidth + 1rem;
width: $lineWidth; width: $lineWidth;
left: 50%; left: 50%;
transform: $transformX; transform: $transformX;
background-color: $grey-400; background-color: var(--grey-400);
border-radius: 2px; border-radius: 2px;
transition: all $transition; transition: all $transition;
} }
@ -62,7 +62,7 @@ $size: $lineWidth + 1rem;
&:focus { &:focus {
&::before, &::before,
&::after { &::after {
background-color: $grey-600; background-color: var(--grey-600);
} }
&::before { &::before {

View file

@ -10,7 +10,7 @@ import {POWERED_BY as poweredByUrl} from '@/urls'
<style lang="scss"> <style lang="scss">
.menu-bottom-link { .menu-bottom-link {
color: $grey-300; color: var(--grey-300);
text-align: center; text-align: center;
display: block; display: block;
padding-top: 1rem; padding-top: 1rem;

View file

@ -144,7 +144,7 @@ export default {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
font-size: 2rem; font-size: 2rem;
color: $grey-400; color: var(--grey-400);
line-height: 1; line-height: 1;
transition: all $transition; transition: all $transition;
@ -155,7 +155,7 @@ export default {
&:hover, &:hover,
&:focus { &:focus {
height: 1rem; height: 1rem;
color: $grey-600; color: var(--grey-600);
} }
} }
@ -191,7 +191,7 @@ export default {
} }
.card { .card {
background: $white; background: var(--white);
} }
} }
} }
@ -220,7 +220,7 @@ export default {
right: 1rem; right: 1rem;
z-index: 4500; // The modal has a z-index of 4000 z-index: 4500; // The modal has a z-index of 4000
color: $grey-500; color: var(--grey-500);
transition: color $transition; transition: color $transition;
@media screen and (max-width: $tablet) { @media screen and (max-width: $tablet) {

View file

@ -57,11 +57,11 @@ export default {
} }
.title { .title {
text-shadow: 0 0 1rem $white; text-shadow: 0 0 1rem var(--white);
} }
// FIXME: this should be defined somewhere deep // FIXME: this should be defined somewhere deep
.link-share-view .card { .link-share-view .card {
background-color: $white; background-color: var(--white);
} }
</style> </style>

View file

@ -280,8 +280,8 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
$navbar-padding: 2rem; $navbar-padding: 2rem;
$vikunja-nav-background: $light-background; $vikunja-nav-background: var(--site-background);
$vikunja-nav-color: $grey-700; $vikunja-nav-color: var(--grey-700);
$vikunja-nav-selected-width: 0.4rem; $vikunja-nav-selected-width: 0.4rem;
.namespace-container { .namespace-container {
@ -349,12 +349,12 @@ $vikunja-nav-selected-width: 0.4rem;
opacity: 0; opacity: 0;
&:hover { &:hover {
color: $orange; color: var(--warning);
} }
&.is-favorite { &.is-favorite {
opacity: 1; opacity: 1;
color: $orange; color: var(--warning);
} }
} }
@ -436,7 +436,7 @@ $vikunja-nav-selected-width: 0.4rem;
align-items: center; align-items: center;
&:hover { &:hover {
background: $white; background: var(--white);
} }
:deep(.dropdown-trigger) { :deep(.dropdown-trigger) {
@ -456,7 +456,7 @@ $vikunja-nav-selected-width: 0.4rem;
} }
.ghost { .ghost {
background: $grey-200; background: var(--grey-200);
* { * {
opacity: 0; opacity: 0;
@ -496,16 +496,16 @@ $vikunja-nav-selected-width: 0.4rem;
} }
&.router-link-exact-active { &.router-link-exact-active {
color: $primary; color: var(--primary);
border-left: $vikunja-nav-selected-width solid $primary; border-left: $vikunja-nav-selected-width solid var(--primary);
.icon { .icon {
color: $primary; color: var(--primary);
} }
} }
&:hover { &:hover {
border-left: $vikunja-nav-selected-width solid $primary; border-left: $vikunja-nav-selected-width solid var(--primary);
} }
} }
} }
@ -526,7 +526,7 @@ $vikunja-nav-selected-width: 0.4rem;
} }
.icon { .icon {
color: $grey-400 !important; color: var(--grey-400) !important;
} }
} }

View file

@ -5,7 +5,7 @@
class="navbar main-theme is-fixed-top" class="navbar main-theme is-fixed-top"
role="navigation" role="navigation"
> >
<router-link :to="{name: 'home'}" class="navbar-item logo"> <router-link :to="{name: 'home'}" class="logo-link">
<Logo width="164" height="48"/> <Logo width="164" height="48"/>
</router-link> </router-link>
<MenuButton class="menu-button"/> <MenuButton class="menu-button"/>
@ -137,13 +137,18 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
$vikunja-nav-logo-full-width: 164px; $vikunja-nav-logo-full-width: 164px;
$user-dropdown-width-mobile: 5rem;
$hamburger-menu-icon-spacing: 1rem;
$hamburger-menu-icon-width: 28px;
.navbar { .navbar {
z-index: 4 !important; z-index: 4 !important;
} }
.logo { .logo-link {
display: none; display: none;
padding: 0.5rem 0.75rem;
@media screen and (min-width: $tablet) { @media screen and (min-width: $tablet) {
align-self: stretch; align-self: stretch;
@ -164,7 +169,7 @@ $vikunja-nav-logo-full-width: 164px;
} }
.navbar.main-theme { .navbar.main-theme {
background: $light-background; background: var(--site-background);
z-index: 5 !important; z-index: 5 !important;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
@ -219,7 +224,7 @@ $vikunja-nav-logo-full-width: 164px;
:deep() { :deep() {
.trigger-button { .trigger-button {
cursor: pointer; cursor: pointer;
color: $grey-400; color: var(--grey-400);
padding: .5rem; padding: .5rem;
font-size: 1.25rem; font-size: 1.25rem;
position: relative; position: relative;
@ -278,7 +283,7 @@ $vikunja-nav-logo-full-width: 164px;
} }
:deep(.dropdown-trigger) { :deep(.dropdown-trigger) {
color: $grey-400; color: var(--grey-400);
margin-left: 1rem; margin-left: 1rem;
height: 1rem; height: 1rem;
width: 1rem; width: 1rem;

View file

@ -57,7 +57,7 @@ export default {
padding: 0 0 0 .5rem; padding: 0 0 0 .5rem;
border-radius: $radius; border-radius: $radius;
font-size: .9rem; font-size: .9rem;
color: $grey-900; color: var(--grey-900);
justify-content: space-between; justify-content: space-between;
@media screen and (max-width: $desktop) { @media screen and (max-width: $desktop) {

View file

@ -82,11 +82,11 @@ export default {
font-size: 0.85rem; font-size: 0.85rem;
font-weight: bold; font-weight: bold;
height: $button-height; height: $button-height;
box-shadow: $shadow-sm; box-shadow: var(--shadow-sm);
&.is-hovered, &.is-hovered,
&:hover { &:hover {
box-shadow: $shadow-md; box-shadow: var(--shadow-md);
} }
&.fullheight { &.fullheight {
@ -99,11 +99,11 @@ export default {
&:active, &:active,
&:focus, &:focus,
&:focus:not(:active) { &:focus:not(:active) {
box-shadow: $shadow-xs !important; box-shadow: var(--shadow-xs) !important;
} }
&.is-primary.is-outlined:hover { &.is-primary.is-outlined:hover {
color: $white; color: var(--white);
} }
&.is-small { &.is-small {

View file

@ -134,7 +134,7 @@ export default {
height: $PICKER_SIZE; height: $PICKER_SIZE;
overflow: hidden; overflow: hidden;
border-radius: 100%; border-radius: 100%;
border: $BORDER_WIDTH solid $grey-300; border: $BORDER_WIDTH solid var(--grey-300);
box-shadow: $shadow; box-shadow: $shadow;
& > * { & > * {

View file

@ -258,7 +258,7 @@ export default {
position: absolute; position: absolute;
z-index: 99; z-index: 99;
width: 320px; width: 320px;
background: $white; background: var(--white);
border-radius: $radius; border-radius: $radius;
box-shadow: $shadow; box-shadow: $shadow;
@ -272,7 +272,7 @@ export default {
padding: 0 .5rem; padding: 0 .5rem;
width: 100%; width: 100%;
height: 2.25rem; height: 2.25rem;
color: $text; color: var(--text);
transition: all $transition; transition: all $transition;
&:first-child { &:first-child {
@ -280,7 +280,7 @@ export default {
} }
&:hover { &:hover {
background: $light; background: var(--light);
} }
.text { .text {
@ -291,7 +291,7 @@ export default {
padding-right: .25rem; padding-right: .25rem;
.weekday { .weekday {
color: $text-light; color: var(--text-light);
text-transform: capitalize; text-transform: capitalize;
} }
} }

View file

@ -338,13 +338,14 @@ $editor-border-color: #ddd;
.CodeMirror { .CodeMirror {
padding: .5rem; padding: .5rem;
border: 1px solid $editor-border-color; border: 1px solid $editor-border-color;
background: var(--white);
&-lines pre { &-lines pre {
margin: 0 !important; margin: 0 !important;
} }
&-placeholder { &-placeholder {
color: $grey-400 !important; color: var(--grey-400) !important;
font-style: italic; font-style: italic;
} }
} }
@ -383,7 +384,7 @@ $editor-border-color: #ddd;
pre.CodeMirror-line { pre.CodeMirror-line {
margin-bottom: 0 !important; margin-bottom: 0 !important;
color: $grey-700 !important; color: var(--grey-700) !important;
} }
.cm-header { .cm-header {
@ -409,10 +410,10 @@ ul.actions {
} }
&, a { &, a {
color: $grey-500; color: var(--grey-500);
&.done-edit { &.done-edit {
color: $primary; color: var(--primary);
} }
} }

View file

@ -106,7 +106,7 @@ svg {
} }
.check:hover svg { .check:hover svg {
stroke: $primary; stroke: var(--primary);
} }
.is-disabled .check:hover svg { .is-disabled .check:hover svg {
@ -125,7 +125,7 @@ polyline {
input[type=checkbox]:checked + .check { input[type=checkbox]:checked + .check {
svg { svg {
stroke: $primary; stroke: var(--primary);
} }
path { path {

View file

@ -380,23 +380,23 @@ export default {
&.has-search-results .input-wrapper { &.has-search-results .input-wrapper {
border-radius: $radius $radius 0 0; border-radius: $radius $radius 0 0;
border-color: $primary !important; border-color: var(--primary) !important;
background: $white !important; background: var(--white) !important;
&, &:focus-within { &, &:focus-within {
border-bottom-color: $grey-200 !important; border-bottom-color: var(--grey-200) !important;
} }
} }
.input-wrapper { .input-wrapper {
padding: 0; padding: 0;
background: $white !important; background: var(--white) !important;
border-color: $grey-200 !important; border-color: var(--grey-200) !important;
flex-wrap: wrap; flex-wrap: wrap;
height: auto; height: auto;
&:hover { &:hover {
border-color: $grey-300 !important; border-color: var(--grey-300) !important;
} }
.input { .input {
@ -422,8 +422,8 @@ export default {
} }
&:focus-within { &:focus-within {
border-color: $primary !important; border-color: var(--primary) !important;
background: $white !important; background: var(--white) !important;
} }
.loader { .loader {
@ -432,9 +432,9 @@ export default {
} }
.search-results { .search-results {
background: $white; background: var(--white);
border-radius: 0 0 $radius $radius; border-radius: 0 0 $radius $radius;
border: 1px solid $primary; border: 1px solid var(--primary);
border-top: none; border-top: none;
max-height: 50vh; max-height: 50vh;
@ -481,16 +481,16 @@ export default {
} }
&:focus, &:hover { &:focus, &:hover {
background: $grey-100; background: var(--grey-100);
box-shadow: none !important; box-shadow: none !important;
.hint-text { .hint-text {
color: $text; color: var(--text);
} }
} }
&:active { &:active {
background: $grey-200; background: var(--grey-200);
} }
} }
} }

View file

@ -86,11 +86,11 @@ export default {
cursor: pointer; cursor: pointer;
width: calc((100% - #{($lists-per-row - 1) * 1rem}) / #{$lists-per-row}); width: calc((100% - #{($lists-per-row - 1) * 1rem}) / #{$lists-per-row});
height: $list-height; height: $list-height;
background: $white; background: var(--white);
margin: 0 $list-spacing $list-spacing 0; margin: 0 $list-spacing $list-spacing 0;
padding: 1rem; padding: 1rem;
border-radius: $radius; border-radius: $radius;
box-shadow: $shadow-sm; box-shadow: var(--shadow-sm);
transition: box-shadow $transition; transition: box-shadow $transition;
display: flex; display: flex;
@ -98,13 +98,13 @@ export default {
flex-wrap: wrap; flex-wrap: wrap;
&:hover { &:hover {
box-shadow: $shadow-md; box-shadow: var(--shadow-md);
} }
&:active, &:active,
&:focus, &:focus,
&:focus:not(:active) { &:focus:not(:active) {
box-shadow: $shadow-xs !important; box-shadow: var(--shadow-xs) !important;
} }
@media screen and (min-width: $widescreen) { @media screen and (min-width: $widescreen) {
@ -158,7 +158,7 @@ export default {
font-family: $vikunja-font; font-family: $vikunja-font;
font-weight: 400; font-weight: 400;
font-size: 1.5rem; font-size: 1.5rem;
color: $text; color: var(--text);
width: 100%; width: 100%;
margin-bottom: 0; margin-bottom: 0;
max-height: calc(100% - 2rem); // 1rem padding, 1rem height of the "is archived" badge max-height: calc(100% - 2rem); // 1rem padding, 1rem height of the "is archived" badge
@ -171,7 +171,7 @@ export default {
} }
&.has-light-text .title { &.has-light-text .title {
color: $light; color: var(--light);
} }
&.has-background { &.has-background {
@ -180,8 +180,8 @@ export default {
background-position: center; background-position: center;
.title { .title {
text-shadow: 0 0 10px $black, 1px 1px 5px $grey-700, -1px -1px 5px $grey-700; text-shadow: 0 0 10px var(--black), 1px 1px 5px var(--grey-700), -1px -1px 5px var(--grey-700);
color: $white; color: var(--white);
} }
} }
@ -190,7 +190,7 @@ export default {
opacity: 0; opacity: 0;
&:hover { &:hover {
color: $orange; color: var(--warning);
} }
&.is-archived { &.is-archived {
@ -200,7 +200,7 @@ export default {
&.is-favorite { &.is-favorite {
display: inline-block; display: inline-block;
opacity: 1; opacity: 1;
color: $orange; color: var(--warning);
} }
} }

View file

@ -40,8 +40,8 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.is-done { .is-done {
background: $green; background: var(--success);
color: $white; color: var(--white);
padding: .5rem; padding: .5rem;
font-weight: bold; font-weight: bold;
line-height: 1; line-height: 1;

View file

@ -128,6 +128,6 @@ export default {
} }
.url { .url {
border-bottom: 1px dashed $primary; border-bottom: 1px dashed var(--primary);
} }
</style> </style>

View file

@ -63,22 +63,22 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.card { .card {
background-color: $white; background-color: var(--white);
border-radius: $radius; border-radius: $radius;
margin-bottom: 1rem; margin-bottom: 1rem;
border: 1px solid $grey-200; border: 1px solid var(--card-border-color);
box-shadow: $shadow-sm; box-shadow: var(--shadow-sm);
} }
.card-header { .card-header {
box-shadow: none; box-shadow: none;
border-bottom: 1px solid $grey-200; border-bottom: 1px solid var(--card-border-color);
border-radius: $radius $radius 0 0; border-radius: $radius $radius 0 0;
} }
// FIXME: should maybe be merged somehow with modal // FIXME: should maybe be merged somehow with modal
:deep(.modal-card-foot) { :deep(.modal-card-foot) {
background-color: $grey-50; background-color: var(--grey-50);
border-top: 0; border-top: 0;
} }
</style> </style>

View file

@ -22,7 +22,7 @@ export default {
.legal-links { .legal-links {
margin-top: 1rem; margin-top: 1rem;
text-align: right; text-align: right;
color: $grey-300; color: var(--grey-300);
font-size: 1rem; font-size: 1rem;
} }
</style> </style>

View file

@ -26,7 +26,7 @@ const motd = computed(() => store.state.config.motd)
<style lang="scss" scoped> <style lang="scss" scoped>
.no-auth-wrapper { .no-auth-wrapper {
background: url('@/assets/llama.svg') no-repeat bottom left fixed $light-background; background: url('@/assets/llama.svg') no-repeat bottom left fixed var(--site-background);
min-height: 100vh; min-height: 100vh;
} }
@ -38,6 +38,6 @@ const motd = computed(() => store.state.config.motd)
} }
.logo { .logo {
max-width: 100%; color: var(--logo-text-color);
} }
</style> </style>

View file

@ -98,7 +98,7 @@ export default {
left: 0; left: 0;
bottom: 0; bottom: 0;
right: 0; right: 0;
background: $grey-100; background: var(--grey-100);
z-index: 99; z-index: 99;
} }
@ -112,8 +112,8 @@ export default {
margin-right: 1rem; margin-right: 1rem;
&.is-loading::after { &.is-loading::after {
border-left-color: $grey-400; border-left-color: var(--grey-400);
border-bottom-color: $grey-400; border-bottom-color: var(--grey-400);
} }
} }

View file

@ -35,8 +35,8 @@ export default {
kbd { kbd {
padding: .1rem .35rem; padding: .1rem .35rem;
border: 1px solid $grey-300; border: 1px solid var(--grey-300);
background: $grey-100; background: var(--grey-100);
border-radius: 3px; border-radius: 3px;
font-size: .75rem; font-size: .75rem;
} }

View file

@ -145,9 +145,9 @@ export default {
width: .75rem; width: .75rem;
height: .75rem; height: .75rem;
background: $primary; background: var(--primary);
border-radius: 100%; border-radius: 100%;
border: 2px solid $white; border: 2px solid var(--white);
} }
.notifications-list { .notifications-list {
@ -157,12 +157,12 @@ export default {
max-height: 400px; max-height: 400px;
overflow-y: auto; overflow-y: auto;
background: $white; background: var(--white);
width: 350px; width: 350px;
max-width: calc(100vw - 2rem); max-width: calc(100vw - 2rem);
padding: .75rem .25rem; padding: .75rem .25rem;
border-radius: $radius; border-radius: $radius;
box-shadow: $shadow-sm; box-shadow: var(--shadow-sm);
font-size: .85rem; font-size: .85rem;
@media screen and (max-width: $tablet) { @media screen and (max-width: $tablet) {
@ -183,14 +183,14 @@ export default {
transition: background-color $transition; transition: background-color $transition;
&:hover { &:hover {
background: $grey-100; background: var(--grey-100);
border-radius: $radius; border-radius: $radius;
} }
.read-indicator { .read-indicator {
width: .35rem; width: .35rem;
height: .35rem; height: .35rem;
background: $primary; background: var(--primary);
border-radius: 100%; border-radius: 100%;
margin-left: .5rem; margin-left: .5rem;
@ -219,7 +219,7 @@ export default {
} }
.created { .created {
color: $grey-400; color: var(--grey-400);
} }
&:last-child { &:last-child {
@ -227,14 +227,14 @@ export default {
} }
a { a {
color: $grey-800; color: var(--grey-800);
} }
} }
.nothing { .nothing {
text-align: center; text-align: center;
padding: 1rem 0; padding: 1rem 0;
color: $grey-500; color: var(--grey-500);
.explainer { .explainer {
font-size: .75rem; font-size: .75rem;

View file

@ -513,11 +513,11 @@ export default {
.results { .results {
text-align: left; text-align: left;
width: 100%; width: 100%;
color: $grey-800; color: var(--grey-800);
.result { .result {
&-title { &-title {
background: $grey-50; background: var(--grey-50);
padding: .5rem; padding: .5rem;
display: block; display: block;
font-size: .75rem; font-size: .75rem;
@ -528,6 +528,7 @@ export default {
font-size: .9rem; font-size: .9rem;
width: 100%; width: 100%;
background: transparent; background: transparent;
color: var(--grey-800);
text-align: left; text-align: left;
box-shadow: none; box-shadow: none;
border-radius: 0; border-radius: 0;
@ -539,12 +540,12 @@ export default {
cursor: pointer; cursor: pointer;
&:focus, &:hover { &:focus, &:hover {
background: $grey-50; background: var(--grey-50);
box-shadow: none !important; box-shadow: none !important;
} }
&:active { &:active {
background: $grey-100; background: var(--grey-100);
} }
} }
} }

View file

@ -167,7 +167,7 @@ ul.assingees {
a { a {
float: right; float: right;
color: $red; color: var(--danger);
transition: all $transition; transition: all $transition;
} }
} }

View file

@ -445,12 +445,12 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
$gantt-border: 1px solid $grey-200; $gantt-border: 1px solid var(--grey-200);
$gantt-vertical-border-color: $grey-100; $gantt-vertical-border-color: var(--grey-100);
.gantt-chart { .gantt-chart {
overflow-x: auto; overflow-x: auto;
border-top: 1px solid $grey-200; border-top: 1px solid var(--grey-200);
.dates { .dates {
display: flex; display: flex;
@ -477,8 +477,8 @@ $gantt-vertical-border-color: $grey-100;
font-weight: normal; font-weight: normal;
&.today { &.today {
background: $primary; background: var(--primary);
color: $white; color: var(--white);
border-radius: 5px 5px 0 0; border-radius: 5px 5px 0 0;
font-weight: bold; font-weight: bold;
} }
@ -507,7 +507,7 @@ $gantt-vertical-border-color: $grey-100;
.task { .task {
display: inline-block; display: inline-block;
border: 2px solid $primary; border: 2px solid var(--primary);
font-size: 0.85rem; font-size: 0.85rem;
margin: 0.5rem; margin: 0.5rem;
border-radius: 6px; border-radius: 6px;
@ -520,30 +520,30 @@ $gantt-vertical-border-color: $grey-100;
user-select: none; // Non-prefixed version user-select: none; // Non-prefixed version
&.is-current-edit { &.is-current-edit {
border-color: $orange !important; border-color: var(--warning) !important;
} }
&.has-light-text { &.has-light-text {
color: $light; color: var(--light);
&.done span:after { &.done span:after {
border-top: 1px solid $light; border-top: 1px solid var(--light);
} }
.edit-toggle { .edit-toggle {
color: $light; color: var(--light);
} }
} }
&.has-dark-text { &.has-dark-text {
color: $text; color: var(--text);
&.done span:after { &.done span:after {
border-top: 1px solid $dark; border-top: 1px solid var(--dark);
} }
.edit-toggle { .edit-toggle {
color: $text; color: var(--text);
} }
} }
@ -596,8 +596,8 @@ $gantt-vertical-border-color: $grey-100;
} }
&.nodate { &.nodate {
border: 2px dashed $grey-300; border: 2px dashed var(--grey-300);
background: $grey-100; background: var(--grey-100);
} }
&:active { &:active {

View file

@ -267,17 +267,17 @@ export default {
padding: .5rem; padding: .5rem;
&:hover { &:hover {
background-color: $grey-200; background-color: var(--grey-200);
} }
.filename { .filename {
font-weight: bold; font-weight: bold;
margin-bottom: .25rem; margin-bottom: .25rem;
color: $text; color: var(--text);
} }
.info { .info {
color: $grey-500; color: var(--grey-500);
font-size: .9rem; font-size: .9rem;
p { p {
@ -339,17 +339,17 @@ export default {
width: 100%; width: 100%;
font-size: 5rem; font-size: 5rem;
height: auto; height: auto;
text-shadow: $shadow-md; text-shadow: var(--shadow-md);
animation: bounce 2s infinite; animation: bounce 2s infinite;
} }
.hint { .hint {
margin: .5rem auto 2rem; margin: .5rem auto 2rem;
border-radius: 2px; border-radius: 2px;
box-shadow: $shadow-md; box-shadow: var(--shadow-md);
background: $primary; background: var(--primary);
padding: 1rem; padding: 1rem;
color: $white; color: var(--white);
width: 100%; width: 100%;
max-width: 300px; max-width: 300px;
} }

View file

@ -39,7 +39,7 @@ export default {
<style scoped lang="scss"> <style scoped lang="scss">
.checklist-summary { .checklist-summary {
color: $grey-500; color: var(--grey-500);
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
@ -49,10 +49,10 @@ export default {
margin-right: .25rem; margin-right: .25rem;
circle { circle {
stroke: $grey-400; stroke: var(--grey-400);
&:last-child { &:last-child {
stroke: $primary; stroke: var(--primary);
} }
} }
} }

View file

@ -141,14 +141,14 @@ $defer-task-max-width: 350px + 100px;
width: 100%; width: 100%;
max-width: $defer-task-max-width; max-width: $defer-task-max-width;
border-radius: $radius; border-radius: $radius;
border: 1px solid $grey-200; border: 1px solid var(--grey-200);
padding: 1rem; padding: 1rem;
margin: 1rem; margin: 1rem;
background: $white; background: var(--white);
color: $text; color: var(--text);
cursor: default; cursor: default;
z-index: 10; z-index: 10;
box-shadow: $shadow-lg; box-shadow: var(--shadow-lg);
@media screen and (max-width: ($defer-task-max-width)) { @media screen and (max-width: ($defer-task-max-width)) {
left: .5rem; left: .5rem;

View file

@ -127,7 +127,7 @@ export default {
} }
:deep(.user img) { :deep(.user img) {
border: 2px solid $white; border: 2px solid var(--white);
margin-right: 0; margin-right: 0;
} }
@ -135,8 +135,8 @@ export default {
position: absolute; position: absolute;
top: 4px; top: 4px;
left: 2px; left: 2px;
color: $red; color: var(--danger);
background: $white; background: var(--white);
padding: 0 4px; padding: 0 4px;
display: block; display: block;
border-radius: 100%; border-radius: 100%;

View file

@ -117,13 +117,13 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
$task-background: $white; $task-background: var(--white);
.task { .task {
-webkit-touch-callout: none; // iOS Safari -webkit-touch-callout: none; // iOS Safari
user-select: none; user-select: none;
cursor: pointer; cursor: pointer;
box-shadow: $shadow-xs; box-shadow: var(--shadow-xs);
display: block; display: block;
border: 3px solid transparent; border: 3px solid transparent;
@ -163,7 +163,7 @@ $task-background: $white;
} }
&.overdue { &.overdue {
color: $red; color: var(--danger);
} }
} }
@ -219,7 +219,7 @@ $task-background: $white;
.footer .icon, .footer .icon,
.due-date, .due-date,
.priority-label { .priority-label {
background: $grey-100; background: var(--grey-100);
border-radius: $radius; border-radius: $radius;
padding: 0 .5rem; padding: 0 .5rem;
} }
@ -229,7 +229,7 @@ $task-background: $white;
} }
.task-id { .task-id {
color: $grey-500; color: var(--grey-500);
font-size: .8rem; font-size: .8rem;
margin-bottom: .25rem; margin-bottom: .25rem;
display: flex; display: flex;
@ -244,21 +244,21 @@ $task-background: $white;
} }
&.has-light-text { &.has-light-text {
color: $white; color: var(--white);
.task-id { .task-id {
color: $grey-200; color: var(--grey-200);
} }
.footer .icon, .footer .icon,
.due-date, .due-date,
.priority-label { .priority-label {
background: $grey-800; background: var(--grey-800);
} }
.footer { .footer {
.icon svg { .icon svg {
fill: $white; fill: var(--white);
} }
} }
} }

View file

@ -70,6 +70,6 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.list-namespace-title { .list-namespace-title {
color: $grey-500; color: var(--grey-500);
} }
</style> </style>

View file

@ -54,7 +54,7 @@ export default {
} }
span.high-priority { span.high-priority {
color: $red; color: var(--danger);
width: auto !important; // To override the width set in tasks width: auto !important; // To override the width set in tasks
.icon { .icon {
@ -64,7 +64,7 @@ span.high-priority {
} }
&.not-so-high { &.not-so-high {
color: $orange; color: var(--warning);
} }
} }
</style> </style>

View file

@ -310,7 +310,7 @@ export default {
} }
.different-list { .different-list {
color: $grey-500; color: var(--grey-500);
width: auto; width: auto;
} }
@ -332,21 +332,21 @@ export default {
border-radius: $radius; border-radius: $radius;
&:hover { &:hover {
background-color: $grey-200; background-color: var(--grey-200);
} }
a { a {
color: $text; color: var(--text);
transition: color ease $transition-duration; transition: color ease $transition-duration;
&:hover { &:hover {
color: $grey-900; color: var(--grey-900);
} }
} }
.remove { .remove {
text-align: center; text-align: center;
color: $red; color: var(--danger);
opacity: 0; opacity: 0;
transition: opacity $transition; transition: opacity $transition;
} }

View file

@ -112,7 +112,7 @@ export default {
align-items: center; align-items: center;
&.overdue :deep(.datepicker a.show) { &.overdue :deep(.datepicker a.show) {
color: $red; color: var(--danger);
} }
&:last-child { &:last-child {
@ -120,7 +120,7 @@ export default {
} }
a.remove { a.remove {
color: $red; color: var(--danger);
padding-left: .5rem; padding-left: .5rem;
} }
} }

View file

@ -227,7 +227,7 @@ export default {
border: 2px solid transparent; border: 2px solid transparent;
&:hover { &:hover {
background-color: $grey-100; background-color: var(--grey-100);
} }
.tasktext, .tasktext,
@ -239,13 +239,13 @@ export default {
flex: 1 0 50%; flex: 1 0 50%;
.overdue { .overdue {
color: $red; color: var(--danger);
} }
} }
.task-list { .task-list {
width: auto; width: auto;
color: $grey-400; color: var(--grey-400);
font-size: .9rem; font-size: .9rem;
white-space: nowrap; white-space: nowrap;
} }
@ -273,11 +273,11 @@ export default {
} }
a { a {
color: $text; color: var(--text);
transition: color ease $transition-duration; transition: color ease $transition-duration;
&:hover { &:hover {
color: $grey-900; color: var(--grey-900);
} }
} }
@ -288,12 +288,12 @@ export default {
transition: opacity $transition, color $transition; transition: opacity $transition, color $transition;
&:hover { &:hover {
color: $orange; color: var(--warning);
} }
&.is-favorite { &.is-favorite {
opacity: 1; opacity: 1;
color: $orange; color: var(--warning);
} }
} }
@ -324,16 +324,16 @@ export default {
.tasktext.done { .tasktext.done {
text-decoration: line-through; text-decoration: line-through;
color: $grey-500; color: var(--grey-500);
} }
span.parent-tasks { span.parent-tasks {
color: $grey-500; color: var(--grey-500);
width: auto; width: auto;
} }
.remove { .remove {
color: $red; color: var(--danger);
} }
input[type="checkbox"] { input[type="checkbox"] {
@ -351,8 +351,8 @@ export default {
left: calc(50% - 1rem); left: calc(50% - 1rem);
width: 2rem; width: 2rem;
height: 2rem; height: 2rem;
border-left-color: $grey-300; border-left-color: var(--grey-300);
border-bottom-color: $grey-300; border-bottom-color: var(--grey-300);
} }
} }
</style> </style>

View file

@ -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<ColorSchemes>(STORAGE_KEY, DEFAULT_COLOR_SCHEME_SETTING)
const preferredColorScheme = usePreferredColorScheme()
const isDark = computed<boolean>(() => {
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),
}
})

View file

@ -112,6 +112,15 @@
"disabled": "Disabled", "disabled": "Disabled",
"todoist": "Todoist", "todoist": "Todoist",
"vikunja": "Vikunja" "vikunja": "Vikunja"
},
"appearance": {
"title": "Color Scheme",
"setSuccess": "Saved change of color scheme to {colorScheme}",
"colorScheme": {
"light": "Light",
"system": "System",
"dark": "Dark"
}
} }
}, },
"deletion": { "deletion": {

View file

@ -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;

View file

@ -6,7 +6,7 @@
.tag { .tag {
margin: .5rem 0 .5rem .5rem; margin: .5rem 0 .5rem .5rem;
background: $grey-200; background: var(--grey-200);
// FIXME: only used in ListLabels.vue // FIXME: only used in ListLabels.vue
&.disabled { &.disabled {

View file

@ -7,8 +7,8 @@
.modal-container .task-view { .modal-container .task-view {
border-radius: $radius; border-radius: $radius;
padding: 1rem; padding: 1rem;
color: $text; color: var(--text);
background-color: $light-background !important; background-color: var(--site-background) !important;
@media screen and (max-width: 800px) { @media screen and (max-width: 800px) {
border-radius: 0; border-radius: 0;

View file

@ -5,7 +5,7 @@
z-index: 10000; z-index: 10000;
font-size: 0.8rem; font-size: 0.8rem;
text-align: center; text-align: center;
background: $dark; background: var(--dark);
color: white; color: white;
border-radius: 5px; border-radius: 5px;
padding: 5px 10px 5px; padding: 5px 10px 5px;
@ -28,7 +28,7 @@
height: 0; height: 0;
border-left: 5px solid transparent; border-left: 5px solid transparent;
border-right: 5px solid transparent; border-right: 5px solid transparent;
border-top: 5px solid $dark; border-top: 5px solid var(--dark);
&.bottom { &.bottom {
transform: rotate(180deg); transform: rotate(180deg);

View file

@ -0,0 +1,2 @@
@import "colors";
@import "shadows";

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -1,6 +1,6 @@
$font-files-path: '/fonts/'; $font-files-path: '/fonts/';
/* quicksand-regular - latin */ // quicksand-regular - latin
@font-face { @font-face {
font-family: 'Quicksand'; font-family: 'Quicksand';
font-style: normal; font-style: normal;
@ -10,7 +10,7 @@ $font-files-path: '/fonts/';
} }
/* quicksand-500 - latin */ // quicksand-500 - latin
@font-face { @font-face {
font-family: 'Quicksand'; font-family: 'Quicksand';
font-style: normal; font-style: normal;
@ -19,7 +19,7 @@ $font-files-path: '/fonts/';
src: url($font-files-path + 'quicksand-v7-latin-500.woff2') format('woff2'); src: url($font-files-path + 'quicksand-v7-latin-500.woff2') format('woff2');
} }
/* quicksand-700 - latin */ // quicksand-700 - latin
@font-face { @font-face {
font-family: 'Quicksand'; font-family: 'Quicksand';
font-style: normal; font-style: normal;
@ -28,7 +28,7 @@ $font-files-path: '/fonts/';
src: url($font-files-path + 'quicksand-v7-latin-700.woff2') format('woff2'); src: url($font-files-path + 'quicksand-v7-latin-700.woff2') format('woff2');
} }
/* open-sans-regular - latin */ // open-sans-regular - latin
@font-face { @font-face {
font-family: 'Open Sans'; font-family: 'Open Sans';
font-style: normal; font-style: normal;
@ -37,7 +37,7 @@ $font-files-path: '/fonts/';
src: url($font-files-path + 'open-sans-v15-latin-regular.woff2') format('woff2'); src: url($font-files-path + 'open-sans-v15-latin-regular.woff2') format('woff2');
} }
/* open-sans-italic - latin */ // open-sans-italic - latin
@font-face { @font-face {
font-family: 'Open Sans'; font-family: 'Open Sans';
font-style: italic; font-style: italic;
@ -46,7 +46,7 @@ $font-files-path: '/fonts/';
src: url($font-files-path + 'open-sans-v15-latin-italic.woff2') format('woff2'); src: url($font-files-path + 'open-sans-v15-latin-italic.woff2') format('woff2');
} }
/* open-sans-700 - latin */ // open-sans-700 - latin
@font-face { @font-face {
font-family: 'Open Sans'; font-family: 'Open Sans';
font-style: normal; font-style: normal;
@ -55,7 +55,7 @@ $font-files-path: '/fonts/';
src: url($font-files-path + 'open-sans-v15-latin-700.woff2') format('woff2'); src: url($font-files-path + 'open-sans-v15-latin-700.woff2') format('woff2');
} }
/* open-sans-700italic - latin */ // open-sans-700italic - latin
@font-face { @font-face {
font-family: 'Open Sans'; font-family: 'Open Sans';
font-style: italic; font-style: italic;

View file

@ -5,13 +5,15 @@
// This imports are the same as in "bulma/bulma.sass" // This imports are the same as in "bulma/bulma.sass"
// with the expeption of the bulma utilities. // with the expeption of the bulma utilities.
// They are imported globally in variables.scss // They are imported globally in variables.scss
@import "bulma/sass/base/_all"; @import "bulma-css-variables/sass/base/_all";
@import "bulma/sass/elements/_all"; @import "bulma-css-variables/sass/elements/_all";
@import "bulma/sass/form/_all"; @import "bulma-css-variables/sass/form/_all";
@import "bulma/sass/components/_all"; @import "bulma-css-variables/sass/components/_all";
@import "bulma/sass/grid/_all"; @import "bulma-css-variables/sass/grid/_all";
@import "bulma/sass/helpers/_all"; @import "bulma-css-variables/sass/helpers/_all";
@import "bulma/sass/layout/_all"; @import "bulma-css-variables/sass/layout/_all";
@import "theme"; @import "theme";
@import "components"; @import "components";
@import "custom-properties";

View file

@ -8,7 +8,7 @@
// FIXME: move to pagination component // FIXME: move to pagination component
.pagination-link:not(.is-current) { .pagination-link:not(.is-current) {
background: $light-background; background: var(--grey-100);
} }
.box, .box,

View file

@ -6,7 +6,7 @@
} }
.table.has-actions { .table.has-actions {
border-top: 1px solid $grey-100; border-top: 1px solid var(--grey-100);
border-radius: 4px; border-radius: 4px;
overflow: hidden; overflow: hidden;

View file

@ -1,7 +1,7 @@
$scrollbar-height: 8px; $scrollbar-height: 8px;
$scrollbar-track-color: $grey-200; $scrollbar-track-color: var(--grey-200);
$scrollbar-thumb-color: $grey-300; $scrollbar-thumb-color: var(--grey-300);
$scrollbar-hover-color: $grey-500; $scrollbar-hover-color: var(--grey-500);
// Chrome // Chrome
::-webkit-scrollbar { ::-webkit-scrollbar {

View file

@ -6,7 +6,7 @@
} }
:focus { :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) { :focus:not(:focus-visible) {
@ -15,11 +15,11 @@
:focus-visible, :focus-visible,
:-moz-focusring { :-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 { body {
background: $light-background; background: var(--site-background);
min-height: 100vh; min-height: 100vh;
} }
@ -45,7 +45,7 @@ h6 {
&::-moz-progress-bar, &::-moz-progress-bar,
&::-webkit-progress-value { &::-webkit-progress-value {
background: $grey-500; background: var(--grey-500);
} }
@media screen and (max-width: $tablet) { @media screen and (max-width: $tablet) {
@ -94,11 +94,11 @@ button.table {
} }
.icon:not(.has-text-success) { .icon:not(.has-text-success) {
color: $grey-300 !important; color: var(--grey-300) !important;
} }
&.has-text-danger .icon { &.has-text-danger .icon {
color: $danger !important; color: var(--danger) !important;
} }
&.is-disabled { &.is-disabled {
@ -140,7 +140,7 @@ button.table {
} }
.dropdown-menu .dropdown-content { .dropdown-menu .dropdown-content {
box-shadow: $shadow-md; box-shadow: var(--shadow-md);
} }
.is-strikethrough { .is-strikethrough {
@ -156,6 +156,6 @@ button.table {
} }
.box { .box {
border: 1px solid $grey-200; border: 1px solid var(--grey-200);
box-shadow: $shadow-sm; box-shadow: var(--shadow-sm);
} }

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -166,11 +166,11 @@ export default {
} }
.switch-view { .switch-view {
background: $white; background: var(--white);
display: inline-flex; display: inline-flex;
border-radius: $radius; border-radius: $radius;
font-size: .75rem; font-size: .75rem;
box-shadow: $shadow-sm; box-shadow: var(--shadow-sm);
height: $switch-view-height; height: $switch-view-height;
margin-bottom: 1rem; margin-bottom: 1rem;
padding: .5rem; padding: .5rem;
@ -187,18 +187,18 @@ export default {
} }
&.is-active, &.is-active,
&:hover { &:hover {
color: $white; color: var(--switch-view-color);
} }
&.is-active { &.is-active {
background: $primary; background: var(--primary);
font-weight: bold; font-weight: bold;
box-shadow: $shadow-xs; box-shadow: var(--shadow-xs);
} }
&:hover { &:hover {
background: $primary; background: var(--primary);
} }
} }
} }

View file

@ -167,7 +167,7 @@ export default {
font-size: .8rem; font-size: .8rem;
a { a {
color: $grey-800; color: var(--grey-800);
} }
} }
@ -224,7 +224,7 @@ export default {
background: rgba(0, 0, 0, 0.5); background: rgba(0, 0, 0, 0.5);
font-size: .75rem; font-size: .75rem;
font-weight: bold; font-weight: bold;
color: $white; color: var(--white);
transition: opacity $transition; transition: opacity $transition;
} }

View file

@ -581,7 +581,6 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
$bucket-background: $grey-100;
$ease-out: all .3s cubic-bezier(0.23, 1, 0.32, 1); $ease-out: all .3s cubic-bezier(0.23, 1, 0.32, 1);
$bucket-width: 300px; $bucket-width: 300px;
$bucket-header-height: 60px; $bucket-header-height: 60px;
@ -615,7 +614,7 @@ $filter-container-height: '1rem - #{$switch-view-height}';
.ghost { .ghost {
background: transparent !important; background: transparent !important;
border: 3px dashed $grey-300 !important; border: 3px dashed var(--grey-300) !important;
box-shadow: none !important; box-shadow: none !important;
* { * {
@ -624,7 +623,7 @@ $filter-container-height: '1rem - #{$switch-view-height}';
} }
.bucket { .bucket {
background-color: $bucket-background; background-color: var(--grey-100);
border-radius: $radius; border-radius: $radius;
position: relative; position: relative;
@ -672,7 +671,7 @@ $filter-container-height: '1rem - #{$switch-view-height}';
padding-right: 1rem; padding-right: 1rem;
.button { .button {
background: $bucket-background; background: var(--grey-100);
width: 100%; width: 100%;
} }
} }
@ -706,7 +705,7 @@ $filter-container-height: '1rem - #{$switch-view-height}';
font-weight: bold; font-weight: bold;
&.is-max { &.is-max {
color: $red; color: var(--danger);
} }
} }
@ -730,7 +729,7 @@ $filter-container-height: '1rem - #{$switch-view-height}';
background-color: transparent; background-color: transparent;
&:hover { &:hover {
background-color: $white; background-color: var(--white);
} }
} }
} }

View file

@ -327,8 +327,8 @@ export default {
.ghost { .ghost {
border-radius: $radius; border-radius: $radius;
background: $grey-100; background: var(--grey-100);
border: 2px dashed $grey-300; border: 2px dashed var(--grey-300);
* { * {
opacity: 0; opacity: 0;

View file

@ -200,7 +200,7 @@ export default {
span { span {
transition: all 500ms ease; transition: all 500ms ease;
background: $grey-500; background: var(--grey-500);
height: 10px; height: 10px;
width: 10px; width: 10px;
display: inline-block; display: inline-block;
@ -245,11 +245,11 @@ export default {
@keyframes wave { @keyframes wave {
0%, 40%, 100% { 0%, 40%, 100% {
transform: translate(0, 0); transform: translate(0, 0);
background-color: $primary; background-color: var(--primary);
} }
10% { 10% {
transform: translate(0, -15px); transform: translate(0, -15px);
background-color: $primary-dark; background-color: var(--primary-dark);
} }
} }
</style> </style>

View file

@ -131,12 +131,12 @@ export default {
.is-archived { .is-archived {
font-size: 0.75rem; font-size: 0.75rem;
border: 1px solid $grey-500; border: 1px solid var(--grey-500);
color: $grey !important; color: $grey !important;
padding: 2px 4px; padding: 2px 4px;
border-radius: 3px; border-radius: 3px;
font-family: $vikunja-font; font-family: $vikunja-font;
background: rgba($white, 0.75); background: var(--white-translucent);
margin-left: .5rem; margin-left: .5rem;
} }

View file

@ -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 // This is a workaround to hide the llama background from the top on the task detail page
margin-top: -1.5rem; margin-top: -1.5rem;
padding: 1rem; padding: 1rem;
background-color: $light-background; background-color: var(--site-background);
@media screen and (max-width: $desktop) { @media screen and (max-width: $desktop) {
padding-bottom: 0; padding-bottom: 0;
} }
.subtitle { .subtitle {
color: $grey-500; color: var(--grey-500);
margin-bottom: 1rem; margin-bottom: 1rem;
a { a {
color: $grey-800; color: var(--grey-800);
} }
} }
@ -726,7 +726,7 @@ $flash-background-duration: 750ms;
} }
.icon.is-grey { .icon.is-grey {
color: $grey-400; color: var(--grey-400);
} }
:deep(.heading) { :deep(.heading) {
@ -754,7 +754,7 @@ $flash-background-duration: 750ms;
} }
.title.task-id { .title.task-id {
color: $grey-400; color: var(--grey-400);
white-space: nowrap; white-space: nowrap;
} }
@ -765,7 +765,7 @@ $flash-background-duration: 750ms;
align-items: center; align-items: center;
a.remove { a.remove {
color: $red; color: var(--danger);
vertical-align: middle; vertical-align: middle;
padding-left: .5rem; padding-left: .5rem;
line-height: 1; line-height: 1;
@ -776,7 +776,7 @@ $flash-background-duration: 750ms;
width: 100%; width: 100%;
a.show { a.show {
color: $text; color: var(--text);
padding: .25rem .5rem; padding: .25rem .5rem;
transition: background-color $transition; transition: background-color $transition;
border-radius: $radius; border-radius: $radius;
@ -784,7 +784,7 @@ $flash-background-duration: 750ms;
margin: .1rem 0; margin: .1rem 0;
&:hover { &:hover {
background: $white; background: var(--white);
} }
} }
@ -800,7 +800,7 @@ $flash-background-duration: 750ms;
.detail-title { .detail-title {
display: block; display: block;
color: $grey-400; color: var(--grey-400);
} }
.none { .none {
@ -837,21 +837,24 @@ $flash-background-duration: 750ms;
transition: all $transition-duration; transition: all $transition-duration;
&::placeholder { &::placeholder {
color: $text-light; color: var(--text-light);
opacity: 1; opacity: 1;
font-style: italic; font-style: italic;
} }
&:not(:disabled) { &:not(:disabled) {
&:hover, &:active { &:hover,
background: $input-background-color; &:active,
border-color: $input-border-color; &:focus {
background: var(--scheme-main);
border-color: var(--border);
cursor: text; cursor: text;
} }
&:focus { &:hover,
background: $input-background-color; &:active {
border-color: $input-focus-border-color; cursor: text;
border-color: var(--link)
} }
} }
} }
@ -883,7 +886,7 @@ $flash-background-duration: 750ms;
.created { .created {
font-size: .75rem; font-size: .75rem;
color: $grey-500; color: var(--grey-500);
text-align: right; text-align: right;
} }
@ -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-from,
.flash-background-enter-active { .flash-background-enter-active {
animation: flash-background $flash-background-duration ease 1; animation: flash-background $flash-background-duration ease 1;
@ -924,7 +932,7 @@ $flash-background-duration: 750ms;
@keyframes flash-background { @keyframes flash-background {
0% { 0% {
background: lighten($primary, 30); background: var(--primary-light);
} }
100% { 100% {
background: transparent; background: transparent;

View file

@ -2,6 +2,7 @@
<modal <modal
@close="close()" @close="close()"
variant="scrolling" variant="scrolling"
class="task-detail-view-modal"
> >
<a @click="close()" class="close"> <a @click="close()" class="close">
<icon icon="times"/> <icon icon="times"/>
@ -53,11 +54,18 @@ export default {
position: fixed; position: fixed;
top: 5px; top: 5px;
right: 26px; right: 26px;
color: $white; color: var(--white);
font-size: 2rem; font-size: 2rem;
@media screen and (max-width: $desktop) { @media screen and (max-width: $desktop) {
color: $dark; color: var(--dark);
} }
} }
</style> </style>
<style lang="scss">
// Close icon SVG uses currentColor, change the color to keep it visible
.dark .task-detail-view-modal .close {
color: var(--grey-900);
}
</style>

View file

@ -68,7 +68,7 @@ ul.teams {
transition: background-color $transition; transition: background-color $transition;
&:hover { &:hover {
background: $grey-100; background: var(--grey-100);
} }
} }
} }

View file

@ -83,13 +83,13 @@ const isLocalUser = computed(() => store.state.auth.info?.isLocalUser)
a { a {
display: block; display: block;
padding: .5rem; padding: .5rem;
color: $dark; color: var(--dark);
width: 100%; width: 100%;
border-left: 3px solid transparent; border-left: 3px solid transparent;
&:hover, &.router-link-active { &:hover, &.router-link-active {
background: $white; background: var(--white);
border-color: $primary; border-color: var(--primary);
} }
} }
} }

View file

@ -149,6 +149,6 @@ export default {
} }
.vue-advanced-cropper__background { .vue-advanced-cropper__background {
background: $white; background: var(--white);
} }
</style> </style>

View file

@ -90,6 +90,21 @@
</div> </div>
</label> </label>
</div> </div>
<div class="field">
<label class="is-flex is-align-items-center">
<span>
{{ $t('user.settings.appearance.title') }}
</span>
<div class="select ml-2">
<select v-model="activeColorSchemeSetting">
<!-- TODO: use the Vikunja logo in color scheme as option buttons -->
<option v-for="(title, schemeId) in colorSchemeSettings" :key="schemeId" :value="schemeId">
{{ title }}
</option>
</select>
</div>
</label>
</div>
<x-button <x-button
:loading="userSettingsService.loading" :loading="userSettingsService.loading"
@ -102,6 +117,9 @@
</template> </template>
<script> <script>
import {computed, watch} from 'vue'
import {useI18n} from 'vue-i18n'
import {playSoundWhenDoneKey} from '@/helpers/playPop' import {playSoundWhenDoneKey} from '@/helpers/playPop'
import {availableLanguages, saveLanguage, getCurrentLanguage} from '@/i18n' import {availableLanguages, saveLanguage, getCurrentLanguage} from '@/i18n'
import {getQuickAddMagicMode, setQuickAddMagicMode} from '@/helpers/quickAddMagicMode' import {getQuickAddMagicMode, setQuickAddMagicMode} from '@/helpers/quickAddMagicMode'
@ -110,6 +128,29 @@ import {PrefixMode} from '@/modules/parseTaskText'
import ListSearch from '@/components/tasks/partials/listSearch' import ListSearch from '@/components/tasks/partials/listSearch'
import {createRandomID} from '@/helpers/randomId' import {createRandomID} from '@/helpers/randomId'
import {playPop} from '@/helpers/playPop' import {playPop} from '@/helpers/playPop'
import {useColorScheme} from '@/composables/useColorScheme'
import {success} from '@/message'
function useColorSchemeSetting() {
const { t } = useI18n()
const colorSchemeSettings = computed(() => ({
light: t('user.settings.appearance.colorScheme.light'),
auto: t('user.settings.appearance.colorScheme.system'),
dark: t('user.settings.appearance.colorScheme.dark'),
}))
const {store} = useColorScheme()
watch(store, (schemeId) => {
success({message: t('user.settings.appearance.setSuccess', {
colorScheme: colorSchemeSettings.value[schemeId],
})})
})
return {
colorSchemeSettings,
activeColorSchemeSetting: store,
}
}
function getPlaySoundWhenDoneSetting() { function getPlaySoundWhenDoneSetting() {
return localStorage.getItem(playSoundWhenDoneKey) === 'true' || localStorage.getItem(playSoundWhenDoneKey) === null return localStorage.getItem(playSoundWhenDoneKey) === 'true' || localStorage.getItem(playSoundWhenDoneKey) === null
@ -141,6 +182,13 @@ export default {
return this.$store.getters['lists/getListById'](this.settings.defaultListId) return this.$store.getters['lists/getListById'](this.settings.defaultListId)
}, },
}, },
setup() {
return {
...useColorSchemeSetting(),
}
},
mounted() { mounted() {
this.setTitle(`${this.$t('user.settings.general.title')} - ${this.$t('user.settings.title')}`) this.setTitle(`${this.$t('user.settings.general.title')} - ${this.$t('user.settings.title')}`)
}, },

View file

@ -9,8 +9,8 @@ import svgLoader from 'vite-svg-loader'
const pathSrc = path.resolve(__dirname, './src') const pathSrc = path.resolve(__dirname, './src')
// the @use rules have to be the first in the compiled stylesheets // the @use rules have to be the first in the compiled stylesheets
const SCSS_IMPORT_PREFIX = `@use "sass:math"; const PREFIXED_SCSS_STYLES = `@use "sass:math";
@import "${pathSrc}/styles/variables";` @import "${pathSrc}/styles/common-imports";`
const isModernBuild = Boolean(process.env.BUILD_MODERN_ONLY) const isModernBuild = Boolean(process.env.BUILD_MODERN_ONLY)
const legacy = isModernBuild const legacy = isModernBuild
@ -29,7 +29,10 @@ if (isModernBuild) {
export default defineConfig({ export default defineConfig({
css: { css: {
preprocessorOptions: { preprocessorOptions: {
scss: { additionalData: SCSS_IMPORT_PREFIX }, scss: {
additionalData: PREFIXED_SCSS_STYLES,
charset: false, // fixes "@charset" must be the first rule in the file" warnings
},
}, },
}, },
plugins: [ plugins: [

View file

@ -3727,6 +3727,21 @@
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.22.tgz#26dcbe5e530f6c1f2de5ca9aeab92ab00f523b41" resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.22.tgz#26dcbe5e530f6c1f2de5ca9aeab92ab00f523b41"
integrity sha512-qWVav014mpjEtbWbEgl0q9pEyrrIySKum8UVYjwhC6njrKzknLZPvfuYdQyVbApsqr94tf/3dP4pCuZmmjdCWQ== integrity sha512-qWVav014mpjEtbWbEgl0q9pEyrrIySKum8UVYjwhC6njrKzknLZPvfuYdQyVbApsqr94tf/3dP4pCuZmmjdCWQ==
"@vueuse/core@^6.8.0":
version "6.9.2"
resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-6.9.2.tgz#76b16d01f33cf367dd1a2d7f2e31d106443ceb8a"
integrity sha512-FRwl4ccSFuHZBHLGgS9TMv/+Dd6XFaL4o9nph2qtgQIV+z29RBFokw08XjHfykiENRzB01MjYHJ7iRUnsIFQXg==
dependencies:
"@vueuse/shared" "6.9.2"
vue-demi "*"
"@vueuse/shared@6.9.2":
version "6.9.2"
resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-6.9.2.tgz#97e4369fa7262ebc96fe1d6e210268f30b037005"
integrity sha512-lAiMh6XROs0kSKVd0Yb/6GKoQMxC1fYrFDi6opvQWISPtcqRNluRrQxLUZ3WTI78ovtoKRLktjhkFAtydcfFDg==
dependencies:
vue-demi "*"
abab@^2.0.3, abab@^2.0.5: abab@^2.0.3, abab@^2.0.5:
version "2.0.5" version "2.0.5"
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a"
@ -4631,10 +4646,10 @@ builtins@^1.0.3:
resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88"
integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og= integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og=
bulma@0.9.3: bulma-css-variables@^0.9.33:
version "0.9.3" version "0.9.33"
resolved "https://registry.yarnpkg.com/bulma/-/bulma-0.9.3.tgz#ddccb7436ebe3e21bf47afe01d3c43a296b70243" resolved "https://registry.yarnpkg.com/bulma-css-variables/-/bulma-css-variables-0.9.33.tgz#b249c3410e9edcfa7a5ce8ca96049b6939fe92de"
integrity sha512-0d7GNW1PY4ud8TWxdNcP6Cc8Bu7MxcntD/RRLGWuiw/s0a9P+XlH/6QoOIrmbj6o8WWJzJYhytiu9nFjTszk1g== integrity sha512-D85dXLyLOBBDCuSSOeASc0kN2IknJqo5hzkZ22hxDHobxko/qay0nD+zNl2CJtF8v/7iwvQXqzVSDRnFVRSg9A==
byline@^5.0.0: byline@^5.0.0:
version "5.0.0" version "5.0.0"
@ -13970,6 +13985,11 @@ vue-advanced-cropper@2.7.0:
debounce "^1.2.0" debounce "^1.2.0"
easy-bem "^1.0.2" easy-bem "^1.0.2"
vue-demi@*:
version "0.12.1"
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.12.1.tgz#f7e18efbecffd11ab069d1472d7a06e319b4174c"
integrity sha512-QL3ny+wX8c6Xm1/EZylbgzdoDolye+VpCXRhI2hug9dJTP3OUJ3lmiKN3CsVV3mOJKwFi0nsstbgob0vG7aoIw==
vue-drag-resize@2.0.3: vue-drag-resize@2.0.3:
version "2.0.3" version "2.0.3"
resolved "https://registry.yarnpkg.com/vue-drag-resize/-/vue-drag-resize-2.0.3.tgz#1faf0813f43304205bb355fbb3dacc548dd9398a" resolved "https://registry.yarnpkg.com/vue-drag-resize/-/vue-drag-resize-2.0.3.tgz#1faf0813f43304205bb355fbb3dacc548dd9398a"