Skip to content

Commit

Permalink
Merge pull request #6024 from zhyd1997/feat/ticket-2892-dark-mode-sup…
Browse files Browse the repository at this point in the history
…port

add dark mode support
  • Loading branch information
pascalgrimaud authored Jul 7, 2023
2 parents 56782f3 + f6ae430 commit 9cd3e84
Show file tree
Hide file tree
Showing 25 changed files with 304 additions and 12 deletions.
4 changes: 2 additions & 2 deletions src/main/style/atom/chip/_chip.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
margin-bottom: 5px;
border: 1px solid $jhlite-global-color-fill-primary-dark;
border-radius: 6px;
background: rgba($color: $jhlite-global-color-fill-light, $alpha: 70%);
background: var(--jhlite-chip-bg-color);
text-align: center;
color: $jhlite-global-color-text-dark;
color: var(--jhlite-global-color-text);

&--title {
padding-top: 6px;
Expand Down
4 changes: 4 additions & 0 deletions src/main/style/molecule/field/_field.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@
font-size: 0.9rem;
font-style: italic;
}

&--label {
color: var(--jhlite-global-color-text);
}
}
26 changes: 26 additions & 0 deletions src/main/style/root/_root.scss
Original file line number Diff line number Diff line change
@@ -1,8 +1,34 @@
:root {
--jhlite-brand: #045085;
--jhlite-white: #fff;
--jhlite-modules-label: #000;
--jhlite-line-color: #475569;
--jhlite-bg-color: #fff;
--jhlite-global-color-text: #1e293b;
--jhlite-chip-bg-color: rgb(255 255 255 / 70%);
--jhlite-bg-color-primary: #ebebeb;
--jhlite-bg-color-secondary: #fafafa;
--jhlite-accent-color: #cacaca;
--jhlite-text-color-primary: #222;
--jhlite-element-size: 4rem;

font-family: $jhlite-global-font-primary-family;
font-size: $jhlite-global-font-text-size;
}

:root.dark-theme {
--jhlite-brand: #153751;
--jhlite-modules-label: #fff;
--jhlite-line-color: #9da9bf;
--jhlite-bg-color: #0f172a;
--jhlite-global-color-text: #fff;
--jhlite-chip-bg-color: #121212;
--jhlite-bg-color-primary: #1e1e1e;
--jhlite-bg-color-secondary: #2d2d30;
--jhlite-accent-color: #3f3f3f;
--jhlite-text-color-primary: #ddd;
}

@media screen and (min-width: $jhlite-global-breakpoint-small-medium) {
:root {
font-size: $jhlite-global-font-text-desktop-size;
Expand Down
1 change: 1 addition & 0 deletions src/main/style/template/layout/_layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
&--body {
flex-basis: 0;
flex-grow: 1;
background-color: var(--jhlite-bg-color);
min-width: 0;
overflow: auto;
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/style/token/color/_brand.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ $jhlite-color-brand-400: #59a5da;
$jhlite-color-brand-500: #3e8abf;
$jhlite-color-brand-600: #236fa4;
$jhlite-color-brand-700: #0f5b90;
$jhlite-color-brand-800: #045085;
$jhlite-color-brand-800: var(--jhlite-brand);
$jhlite-color-brand-900: #004677;
2 changes: 1 addition & 1 deletion src/main/webapp/app/assets/global.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
$jhipster-lite-primary-color: #0f5b90;
$jhipster-lite-primary-alternative-color: #3e8abf;
$jhipster-lite-secondary-color: #0f172a;
$jhipster-lite-line-color: #475569;
$jhipster-lite-line-color: var(--jhlite-line-color);
$jhipster-lite-primary-text-color: #ddeffc;
$jhipster-lite-disabled-color: #6d6d6d;
$jhipster-lite-primary-input-color: #fff;
Expand Down
2 changes: 2 additions & 0 deletions src/main/webapp/app/common/primary/header/Header.component.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { defineComponent } from 'vue';
import { IconVue } from '@/common/primary/icon';
import { ThemeButtonVue } from '@/common/primary/theme-button';

export default defineComponent({
name: 'Header',

components: {
IconVue,
ThemeButtonVue,
},

setup() {
Expand Down
11 changes: 10 additions & 1 deletion src/main/webapp/app/common/primary/header/Header.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<template>
<header class="jhlite-header">
<div class="jhlite-header--slot">
<div class="jhlite-header--slot jhlite-with-theme-switch">
<router-link class="jhlite-logo" to="/">
<img class="jhlite-logo--icon" src="../../../../content/JHipster-Lite-neon-blue.png" alt="JHipster bow tie" width="48" />
<span class="jhlite-logo--text">JHipster lite</span>
</router-link>
<ThemeButtonVue />
</div>
<div class="jhlite-header--slot -expand"></div>
<div class="jhlite-header--slot">
Expand Down Expand Up @@ -87,3 +88,11 @@
</template>

<script lang="ts" src="./Header.component.ts"></script>

<style lang="scss">
.jhlite-with-theme-switch {
display: flex;
align-items: center;
gap: 16px;
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { ThemeRepository } from '@/module/domain/ThemeRepository';
import { ThemePreference as Theme } from '@/module/secondary/GetMediaPreference';
import { defineComponent, ref, onMounted, inject } from 'vue';

/**
* ThemeSwitchButton
*
* 1. use localStorage saved theme first.
* 2. if no value set, use `prefer-color-scheme` defined.
* 3. can change theme by toggle button.
* 4. the change must be saved in localStorage for later theme decision.
*/
export default defineComponent({
name: 'ThemeButton',

setup() {
const isDarkTheme = ref<boolean>(true);

const theme = ref<Theme>('dark-theme');

const themeRepository = inject('themeRepository') as ThemeRepository;

onMounted(() => {
const initUserTheme = themeRepository.get();
isDarkTheme.value = initUserTheme === 'dark-theme';
theme.value = initUserTheme;
themeRepository.choose(initUserTheme);
});

const toggleTheme = () => {
isDarkTheme.value = !isDarkTheme.value;
theme.value = isDarkTheme.value ? 'dark-theme' : 'light-theme';
themeRepository.choose(theme.value);
};

return {
isDarkTheme,
toggleTheme,
theme,
};
},
});
65 changes: 65 additions & 0 deletions src/main/webapp/app/common/primary/theme-button/ThemeButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<template>
<div class="jhlite-container">
<input
id="switch"
class="jhlite-container_toggle"
type="checkbox"
name="mode"
:checked="!isDarkTheme"
data-selector="theme-switch-button"
@change="toggleTheme"
/>
<label for="switch" class="jhlite-theme-switch_label" :aria-label="theme">
<span>🌙</span>
<span>☀️</span>
<div class="jhlite-theme-switch_toggle" :class="{ 'jhlite-theme-switch_toggle-checked': theme === 'dark-theme' }"></div>
</label>
</div>
</template>

<script lang="ts" src="./ThemeButton.component.ts"></script>

<style lang="scss">
.jhlite-container {
display: flex;
}
.jhlite-container_toggle {
height: 0;
width: 0;
visibility: hidden;
}
.jhlite-theme-switch_label {
align-items: center;
background: var(--jhlite-text-color-primary);
border: calc(var(--jhlite-element-size) * 0.025) solid var(--jhlite-accent-color);
border-radius: var(--jhlite-element-size);
cursor: pointer;
display: flex;
font-size: calc(var(--jhlite-element-size) * 0.3);
height: calc(var(--jhlite-element-size) * 0.35);
position: relative;
padding: calc(var(--jhlite-element-size) * 0.1);
transition: background 0.5s ease;
justify-content: space-between;
width: var(--jhlite-element-size);
z-index: 1;
}
.jhlite-theme-switch_toggle {
position: absolute;
background-color: var(--jhlite-bg-color-primary);
border-radius: 50%;
top: calc(var(--jhlite-element-size) * 0.07);
left: calc(var(--jhlite-element-size) * 0.07);
height: calc(var(--jhlite-element-size) * 0.4);
width: calc(var(--jhlite-element-size) * 0.4);
transform: translateX(0);
transition: transform 0.3s ease, background-color 0.5s ease;
}
.jhlite-theme-switch_toggle-checked {
transform: translateX(calc(var(--jhlite-element-size) * 0.6)) !important;
}
</style>
4 changes: 4 additions & 0 deletions src/main/webapp/app/common/primary/theme-button/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import ThemeButtonComponent from './ThemeButton.component';
import ThemeButtonVue from './ThemeButton.vue';

export { ThemeButtonComponent, ThemeButtonVue };
3 changes: 3 additions & 0 deletions src/main/webapp/app/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { WindowApplicationListener } from './common/primary/applicationlistener/
import { Timeout } from '@/common/primary/timeout/Timeout';
import { BodyCursorUpdater } from '@/common/primary/cursor/BodyCursorUpdater';
import { LandscapeScroller } from '@/module/primary/landscape/LandscapeScroller';
import { LocalWindowThemeRepository } from './module/secondary/LocalWindowThemeRepository';
import { LocalStorageModuleParametersRepository } from './module/secondary/LocalStorageModuleParametersRepository';

const app = createApp(App);
Expand All @@ -29,6 +30,7 @@ const landscapeScroller = new LandscapeScroller();
const modulesRepository = new RestModulesRepository(axiosHttp);
const projectFoldersRepository = new RestProjectFoldersRepository(axiosHttp);
const applicationListener = new WindowApplicationListener(window);
const localWindowThemeRepository = new LocalWindowThemeRepository(window, localStorage);
const moduleParametersRepository = new LocalStorageModuleParametersRepository(localStorage);
const timeout = () => new Timeout();

Expand All @@ -41,6 +43,7 @@ app.provide('landscapeScroller', landscapeScroller);
app.provide('modules', modulesRepository);
app.provide('projectFolders', projectFoldersRepository);
app.provide('applicationListener', applicationListener);
app.provide('themeRepository', localWindowThemeRepository);
app.provide('moduleParameters', moduleParametersRepository);
app.provide('timeout', timeout);
app.use(router);
Expand Down
6 changes: 6 additions & 0 deletions src/main/webapp/app/module/domain/ThemeRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { ThemePreference as Theme } from '@/module/secondary/GetMediaPreference';

export interface ThemeRepository {
get(): Theme;
choose(theme: Theme): void;
}
5 changes: 3 additions & 2 deletions src/main/webapp/app/module/primary/landscape/Landscape.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ $jhipster-landscape-padding: 20px;
left: $jhipster-landscape-padding;
position: absolute;
z-index: 3;
background: rgba($color: $jhipster-lite-color-fill-light, $alpha: 0.7);
background: var(--jhlite-chip-bg-color);
padding: 10px;
border: 1px dotted $jhipster-lite-line-color;
border-radius: $jhipster-lite-box-radius;
Expand All @@ -33,7 +33,7 @@ $jhipster-landscape-padding: 20px;
background-color: transparent;
border: 0;
border-radius: 1.5em;
color: $jhipster-lite-color-text-dark;
color: var(--jhlite-global-color-text);
padding: 7px 15px;
cursor: pointer;
Expand Down Expand Up @@ -112,6 +112,7 @@ $jhipster-landscape-padding: 20px;
text-align: center;
font-size: 1em;
font-weight: bold;
color: var(--jhlite-global-color-text);
&.-extended {
margin: 5px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ $jhipster-lite-invalid-optional-parameters-color: #90670f;
}
&--type-stats.not-selected {
color: var(--jhlite-white);
margin-left: 7px;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<style lang="scss">
.jhipster-modules-properties-form {
&--properties-title {
color: var(--jhlite-global-color-text);
font-size: 1.4em;
margin-top: 15px;
}
Expand All @@ -16,6 +17,7 @@
&--commit-modules-label {
margin-left: 10px;
cursor: pointer;
color: var(--jhlite-modules-label);
}
&--field {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

<style lang="scss">
.jhipster-modules {
background-color: $jhipster-lite-secondary-color;
color: $jhipster-lite-primary-text-color;
color: var(--jhlite-global-color-text);
}
.jhipster-modules-list {
Expand Down Expand Up @@ -33,8 +32,6 @@
&--filter {
font-size: 1.4em;
background-color: $jhipster-lite-secondary-color;
color: $jhipster-lite-primary-input-color;
border: 1px solid $jhipster-lite-line-color;
border-radius: $jhipster-lite-box-radius;
padding: 0 10px;
Expand All @@ -46,6 +43,7 @@
background-color: $jhipster-lite-primary-color;
padding: 3px 1em;
border-radius: 1em;
color: #ffffff;
}
}
Expand All @@ -64,6 +62,7 @@
&.selected {
background-color: $jhipster-lite-primary-color;
color: var(--jhlite-white);
}
&--content {
Expand Down
3 changes: 2 additions & 1 deletion src/main/webapp/app/module/primary/tag-filter/TagFilter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
.jhipster-modules-tags-filter {
border: 1px solid $jhipster-lite-line-color;
border-radius: 1.5em;
color: $jhipster-lite-primary-input-color;
color: var(--jhlite-global-color-text);
background-color: transparent;
padding: 7px 15px;
&.selected {
background-color: $jhipster-lite-primary-color;
color: #ffffff;
}
}
</style>
8 changes: 8 additions & 0 deletions src/main/webapp/app/module/secondary/GetMediaPreference.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export type ThemePreference = 'light-theme' | 'dark-theme';

export const getMediaPreference = (win: Window): ThemePreference => {
if (typeof win !== 'undefined' && win.matchMedia) {
return win.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark-theme' : 'light-theme';
}
return 'light-theme';
};
17 changes: 17 additions & 0 deletions src/main/webapp/app/module/secondary/LocalWindowThemeRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ThemeRepository } from '../domain/ThemeRepository';
import { ThemePreference as Theme, getMediaPreference } from './GetMediaPreference';

const THEME_STORAGE_KEY = 'theme';

export class LocalWindowThemeRepository implements ThemeRepository {
constructor(private readonly win: Window, private readonly storage: Storage) {}

get(): Theme {
return (this.storage.getItem(THEME_STORAGE_KEY) as Theme) || getMediaPreference(this.win);
}

choose(theme: Theme): void {
this.storage.setItem(THEME_STORAGE_KEY, theme);
this.win.document.documentElement.className = theme;
}
}
Loading

0 comments on commit 9cd3e84

Please sign in to comment.