Skip to content

Commit

Permalink
Merge pull request #262 from letehaha/feat/theme-switcher
Browse files Browse the repository at this point in the history
feat: Dark/light mode switcher
  • Loading branch information
letehaha authored Sep 16, 2023
2 parents befed70 + b680893 commit fefb046
Show file tree
Hide file tree
Showing 9 changed files with 1,482 additions and 1,069 deletions.
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
18.14.0
18.17.1
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:18.14.0 as build-stage
FROM node:18.17.1 as build-stage
WORKDIR /app
COPY . .
RUN npm ci
Expand Down
2,422 changes: 1,386 additions & 1,036 deletions package-lock.json

Large diffs are not rendered by default.

21 changes: 11 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@
"not dead"
],
"dependencies": {
"@tanstack/vue-query": "^4.34.0",
"@heroicons/vue": "^2.0.18",
"@tanstack/vue-query": "^4.35.3",
"@vuelidate/core": "^2.0.3",
"@vuelidate/validators": "^2.0.3",
"core-js": "^3.32.0",
"@vuelidate/validators": "^2.0.4",
"core-js": "^3.32.2",
"date-fns": "^2.30.0",
"highcharts": "^11.1.0",
"highcharts-vue": "^1.4.3",
Expand All @@ -48,14 +49,14 @@
"@storybook/cli": "^7.2.3",
"@storybook/vue3": "^7.2.3",
"@storybook/vue3-vite": "^7.2.3",
"@types/lodash-es": "^4.17.8",
"@vitejs/plugin-vue": "^4.2.3",
"@types/lodash-es": "^4.17.9",
"@vitejs/plugin-vue": "^4.3.4",
"@vue/compiler-sfc": "^3.3.4",
"@vue/eslint-config-airbnb": "^7.0.0",
"@vue/eslint-config-typescript": "^11.0.3",
"@vue/test-utils": "^2.4.1",
"css-loader": "^6.8.1",
"cypress": "^12.17.4",
"cypress": "^13.2.0",
"dotenv": "^16.3.1",
"eslint": "^8.47.0",
"eslint-friendly-formatter": "^4.0.1",
Expand All @@ -65,14 +66,14 @@
"jsdom": "^22.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"sass": "^1.65.1",
"sass": "^1.67",
"storybook": "^7.2.3",
"storybook-dark-mode": "^3.0.1",
"typescript": "^5.1.6",
"typescript": "^5.2.2",
"vite": "^4.4.9",
"vite-svg-loader": "^4.0.0",
"vitest": "^0.34.1",
"vitest": "^0.34.4",
"vue-style-loader": "^4.1.3",
"vue-tsc": "^1.8.8"
"vue-tsc": "^1.8.11"
}
}
35 changes: 35 additions & 0 deletions src/common/utils/color-theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { ref } from 'vue';

const THEME_LS_KEY = 'preferred-theme';

export enum Themes {
dark = 'dark',
light = 'light'
}

export const currentTheme = ref<Themes>(Themes.dark);

export const setTheme = (theme: Themes, save = false) => {
currentTheme.value = theme;
document.body.classList.remove(Themes.dark);
document.body.classList.remove(Themes.light);
document.body.classList.add(theme);

if (save) localStorage.setItem(THEME_LS_KEY, theme);
};

export const toggleTheme = () => {
setTheme(currentTheme.value === Themes.dark ? Themes.light : Themes.dark, true);
};

export const identifyCurrentTheme = () => {
const preferredTheme = localStorage.getItem(THEME_LS_KEY) as Themes;

if (Object.values(Themes).includes(preferredTheme)) {
setTheme(preferredTheme);
} else {
const matched = window.matchMedia('(prefers-color-scheme: dark)').matches;

setTheme(matched ? Themes.dark : Themes.light);
}
};
1 change: 1 addition & 0 deletions src/common/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './color-theme';
63 changes: 44 additions & 19 deletions src/components/ui-header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,42 +8,59 @@
</div>
</div>

<ui-tooltip
:content="!isAllowedToSyncFinancialData ? 'You can sync data only once in 30 mins' : ''"
position="bottom"
class="layout-header__sync-status-wrapper"
>
<div class="layout-header__to-left">
<button
class="button-style-reset layout-header__sync-status"
type="button"
:class="{
'layout-header__sync-status--syncing': isSyncing,
}"
:disabled="!isAllowedToSyncFinancialData"
@click="syncFinancialDataHandler"
class="layout-header__toggle-theme"
@click="toggleTheme"
>
<template v-if="isSyncing">
<refresh-icon />
<span class="layout-header__sync-status-text">Synchronizing...</span>
<template v-if="currentTheme === Themes.dark">
<moon-icon />
</template>
<template v-else>
<checkmark-in-circle-icon />
<span class="layout-header__sync-status-text">Synchronized</span>
<sun-icon />
</template>
</button>
</ui-tooltip>

<ui-tooltip
:content="!isAllowedToSyncFinancialData ? 'You can sync data only once in 30 mins' : ''"
position="bottom"
class="layout-header__sync-status-wrapper"
>
<button
class="layout-header__sync-status"
type="button"
:class="{
'layout-header__sync-status--syncing': isSyncing,
}"
:disabled="!isAllowedToSyncFinancialData"
@click="syncFinancialDataHandler"
>
<template v-if="isSyncing">
<refresh-icon />
<span class="layout-header__sync-status-text">Synchronizing...</span>
</template>
<template v-else>
<checkmark-in-circle-icon />
<span class="layout-header__sync-status-text">Synchronized</span>
</template>
</button>
</ui-tooltip>
</div>
</div>
</template>

<script setup lang="ts">
import { computed } from 'vue';
import { storeToRefs } from 'pinia';
import { SunIcon, MoonIcon } from '@heroicons/vue/24/solid';
import { useRootStore } from '@/stores';
import { MODAL_TYPES, useModalCenter } from '@/components/modal-center/index';
import UiButton from '@/components/common/ui-button.vue';
import CheckmarkInCircleIcon from '@/assets/icons/checkmark-in-circle.svg?component';
import RefreshIcon from '@/assets/icons/refresh.svg?component';
import UiTooltip from '@/components/common/tooltip.vue';
import { toggleTheme, currentTheme, Themes } from '@/common/utils';
const { addModal } = useModalCenter();
const rootStore = useRootStore();
Expand Down Expand Up @@ -82,9 +99,11 @@ const syncFinancialDataHandler = () => {
.layout-header__action {
margin-right: 16px;
}
.layout-header__sync-status-wrapper {
.layout-header__to-left {
margin-left: auto;
display: flex;
}
.layout-header__sync-status-wrapper {
.ui-tooltip__content-wrapper {
left: 30%
}
Expand Down Expand Up @@ -128,4 +147,10 @@ const syncFinancialDataHandler = () => {
.layout-header__sync-status-text {
font-weight: 500;
}
.layout-header__toggle-theme {
width: 32px;
height: 32px;
border-radius: 4px;
padding: 4px;
}
</style>
4 changes: 2 additions & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import { clickOutside, nodeResizeObserver } from '@/directives';
import { initApiCaller } from '@/api';
import { store } from '@/stores/setup';
import { useAuthStore } from '@/stores';
import { identifyCurrentTheme } from '@/common/utils';
import App from './app.vue';
import '@/styles/index.scss';
import './registerServiceWorker';

const matched = window.matchMedia('(prefers-color-scheme: dark)').matches;
document.body.classList.add(matched ? 'dark' : 'light');
identifyCurrentTheme();

const app = createApp(App);

Expand Down
1 change: 1 addition & 0 deletions src/styles/global.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ body {

background-color: var(--app-bg-page);
color: var(--app-text-base);
transition: color .3s ease-out, background-color .3s ease-out;
}

button, a, input, select, textarea {
Expand Down

0 comments on commit fefb046

Please sign in to comment.