mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-02-21 22:41:05 +08:00
feat(ui): add theme manager and dark mode
This commit is contained in:
@@ -5,19 +5,36 @@
|
||||
--header-height: 60px;
|
||||
--header-background-color: white;
|
||||
--header-border-color: lightgray;
|
||||
--header-text-color: black;
|
||||
--menu-background-color: white;
|
||||
--menu-border-color: lightgray;
|
||||
--menu-selected-background-color: rgba(208, 250, 255, 0.659);
|
||||
--menu-text-color: black;
|
||||
--scroller-background-color: rgba(130, 175, 180, 0.5);
|
||||
--normal-background-color: rgb(241, 241, 241);
|
||||
--text-color: black;
|
||||
--menu-width: 200px;
|
||||
--page-max-width: 1200px;
|
||||
}
|
||||
|
||||
[data-theme='dark'] {
|
||||
--header-background-color: #2b2b2b;
|
||||
--header-border-color: #555;
|
||||
--header-text-color: white;
|
||||
--menu-background-color: #333;
|
||||
--menu-border-color: #555;
|
||||
--menu-selected-background-color: rgba(255, 255, 255, 0.1);
|
||||
--menu-text-color: white;
|
||||
--normal-background-color: #121212;
|
||||
--text-color: #eee;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
background-color: var(--normal-background-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
</div>
|
||||
|
||||
<div class="menu-footer">
|
||||
<div class="menu-footer-btn" @click="$emit('toggle-dark-mode')">
|
||||
<i class="fas fa-moon"></i>
|
||||
<div class="menu-footer-btn" @click="cycleTheme">
|
||||
<i :class="iconClass"></i>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -30,6 +30,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { themeState, cycleTheme, ThemeMode } from '../utils/theme'
|
||||
export default {
|
||||
name: 'MenuComponent',
|
||||
props: {
|
||||
@@ -37,7 +38,20 @@ export default {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
iconClass() {
|
||||
switch (themeState.mode) {
|
||||
case ThemeMode.DARK:
|
||||
return 'fas fa-moon'
|
||||
case ThemeMode.LIGHT:
|
||||
return 'fas fa-sun'
|
||||
default:
|
||||
return 'fas fa-desktop'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: { cycleTheme }
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import Toast, { POSITION } from 'vue-toastification'
|
||||
import 'vue-toastification/dist/index.css'
|
||||
import { useToast } from 'vue-toastification'
|
||||
import { checkToken, clearToken } from './utils/auth'
|
||||
import { initTheme } from './utils/theme'
|
||||
|
||||
// Configurable API domain and port
|
||||
export const API_DOMAIN = 'http://127.0.0.1'
|
||||
@@ -14,6 +15,8 @@ export const API_BASE_URL = API_PORT ? `${API_DOMAIN}:${API_PORT}` : API_DOMAIN
|
||||
export const GOOGLE_CLIENT_ID = '777830451304-nt8afkkap18gui4f9entcha99unal744.apps.googleusercontent.com'
|
||||
export const toast = useToast()
|
||||
|
||||
initTheme()
|
||||
|
||||
const app = createApp(App)
|
||||
app.use(router)
|
||||
app.use(Toast, { position: POSITION.TOP_RIGHT })
|
||||
|
||||
52
open-isle-cli/src/utils/theme.js
Normal file
52
open-isle-cli/src/utils/theme.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import { reactive } from 'vue'
|
||||
|
||||
export const ThemeMode = {
|
||||
SYSTEM: 'system',
|
||||
LIGHT: 'light',
|
||||
DARK: 'dark'
|
||||
}
|
||||
|
||||
const THEME_KEY = 'theme-mode'
|
||||
|
||||
export const themeState = reactive({
|
||||
mode: ThemeMode.SYSTEM
|
||||
})
|
||||
|
||||
function apply(mode) {
|
||||
const root = document.documentElement
|
||||
if (mode === ThemeMode.SYSTEM) {
|
||||
root.dataset.theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
||||
} else {
|
||||
root.dataset.theme = mode
|
||||
}
|
||||
}
|
||||
|
||||
export function initTheme() {
|
||||
const saved = localStorage.getItem(THEME_KEY)
|
||||
if (saved && Object.values(ThemeMode).includes(saved)) {
|
||||
themeState.mode = saved
|
||||
}
|
||||
apply(themeState.mode)
|
||||
}
|
||||
|
||||
export function setTheme(mode) {
|
||||
if (!Object.values(ThemeMode).includes(mode)) return
|
||||
themeState.mode = mode
|
||||
localStorage.setItem(THEME_KEY, mode)
|
||||
apply(mode)
|
||||
}
|
||||
|
||||
export function cycleTheme() {
|
||||
const modes = [ThemeMode.SYSTEM, ThemeMode.LIGHT, ThemeMode.DARK]
|
||||
const index = modes.indexOf(themeState.mode)
|
||||
const next = modes[(index + 1) % modes.length]
|
||||
setTheme(next)
|
||||
}
|
||||
|
||||
if (window.matchMedia) {
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
|
||||
if (themeState.mode === ThemeMode.SYSTEM) {
|
||||
apply(ThemeMode.SYSTEM)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user