finish basic sidebar

This commit is contained in:
SikongJueluo 2025-03-14 19:04:15 +08:00
parent 9200befaf8
commit 8f18560a38
No known key found for this signature in database
9 changed files with 215 additions and 61 deletions

View File

@ -4,7 +4,9 @@
"": {
"name": "fpga-weblab",
"dependencies": {
"log-symbols": "^7.0.0",
"pinia": "^3.0.1",
"ts-log": "^2.2.7",
"vue": "^3.5.13",
"vue-router": "4",
},
@ -413,6 +415,8 @@
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.29.2", "", { "os": "win32", "cpu": "x64" }, "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA=="],
"log-symbols": ["log-symbols@7.0.0", "", { "dependencies": { "is-unicode-supported": "^2.0.0", "yoctocolors": "^2.1.1" } }, "sha512-zrc91EDk2M+2AXo/9BTvK91pqb7qrPg2nX/Hy+u8a5qQlbaOflCKO+6SqgZ+M+xUFxGdKTgwnGiL96b1W3ikRA=="],
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
"magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
@ -501,6 +505,8 @@
"totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="],
"ts-log": ["ts-log@2.2.7", "", {}, "sha512-320x5Ggei84AxzlXp91QkIGSw5wgaLT6GeAH0KsqDmRZdVWW2OiSeVvElVoatk3f7nicwXlElXsoFkARiGE2yg=="],
"typescript": ["typescript@5.7.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw=="],
"undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],

View File

@ -11,7 +11,9 @@
"type-check": "bunx --bun vue-tsc --build"
},
"dependencies": {
"log-symbols": "^7.0.0",
"pinia": "^3.0.1",
"ts-log": "^2.2.7",
"vue": "^3.5.13",
"vue-router": "4"
},

View File

@ -1,16 +1,23 @@
<script setup lang="ts">
import { ref } from 'vue';
import LoginCard from './components/LoginCard.vue';
import { useThemeStore } from './stores/theme';
const theme = useThemeStore()
</script>
<template>
<header>
<RouterLink to="/user"> Go to User</RouterLink>
<RouterLink to="/login"> Go to Login</RouterLink>
</header>
<div :data-theme="theme.currentTheme">
<header>
<RouterLink to="/user"> Go to User</RouterLink>
<RouterLink to="/login"> Go to Login</RouterLink>
</header>
<main>
<RouterView />
</main>
<main>
<RouterView />
</main>
</div>
</template>
<style scoped>

View File

@ -1,5 +1,8 @@
@import "tailwindcss";
@plugin "daisyui" {
themes: winter --default, night;
themes: winter --default, night --prefersdark;
}
@custom-variant dark (&:where([data-theme=night], [data-theme=night] *));
@custom-variant light (&:where([data-theme=winter], [data-theme=winter] *));

View File

@ -1,17 +1,21 @@
<template>
<div class="card card-dash sidebar-base">
<div :class="themeSidebar">
<div class="card-body flex">
<!-- Avatar and Name -->
<div class="flex items-center">
<!-- Img -->
<div class="avatar h-10">
<div class="rounded-full">
<img src="../assets/user.svg" alt="User" />
</div>
</div>
<div class="mx-5 grow">
<label class="text-2xl">User Name</label>
<!-- Text -->
<div v-if="!isClose" class="mx-5 grow">
<label class="text-2xl">用户名</label>
</div>
<button class="btn btn-square rounded-lg p-2">
<!-- Toggle Button -->
<button class="btn btn-square rounded-lg p-2" @click="toggleSidebar">
<img src="../assets/left.svg" alt="Menu Button" class="opacity-50">
</button>
</div>
@ -21,8 +25,8 @@
<ul class="menu h-full w-full">
<li v-for="item in items" class="text-lg my-1">
<a>
<img class="h-[1em] opacity-50 mx-1" :src="item.icon" alt="An icon" />
{{ item.msg }}
<img class="h-[1.5em] opacity-50 mx-1" :src="item.icon" alt="An icon" />
<p v-if="!isClose">{{ item.msg }}</p>
</a>
</li>
@ -30,49 +34,15 @@
<div class="divider"></div>
<div class="mb-5">
<label class="swap swap-rotate">
<!-- this hidden checkbox controls the state -->
<input type="checkbox" class="theme-controller" value="synthwave" />
<!-- sun icon -->
<svg class="swap-off h-10 w-10 fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z" />
</svg>
<!-- moon icon -->
<svg class="swap-on h-10 w-10 fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z" />
</svg>
</label>
<label class="toggle text-base-content">
<input type="checkbox" value="synthwave" class="theme-controller">
<svg aria-label="sun" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<g stroke-linejoin="round" stroke-linecap="round" stroke-width="2" fill="none" stroke="currentColor">
<circle cx="12" cy="12" r="4"></circle>
<path d="M12 2v2"></path>
<path d="M12 20v2"></path>
<path d="m4.93 4.93 1.41 1.41"></path>
<path d="m17.66 17.66 1.41 1.41"></path>
<path d="M2 12h2"></path>
<path d="M20 12h2"></path>
<path d="m6.34 17.66-1.41 1.41"></path>
<path d="m19.07 4.93-1.41 1.41"></path>
</g>
</svg>
<svg aria-label="moon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<g stroke-linejoin="round" stroke-linecap="round" stroke-width="2" fill="none" stroke="currentColor">
<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path>
</g>
</svg>
</label>
</div>
<ul class="menu w-full">
<li class="mb-5">
<a @click="theme.toggleTheme" class="text-xl">
<ThemeControlButton />
<p v-if="!isClose">改变主题</p>
<ThemeControlToggle v-if="!isClose" />
</a>
</li>
</ul>
</div>
</div>
@ -80,6 +50,13 @@
<script setup lang="ts">
import iconMenu from "../assets/menu.svg"
import { useThemeStore } from "@/stores/theme";
import { ref } from "vue";
import ThemeControlButton from "./ThemeControlButton.vue";
import ThemeControlToggle from "./ThemeControlToggle.vue";
const theme = useThemeStore()
const isClose = ref(false)
const items = [
{ id: 1, icon: iconMenu, msg: "btn1" },
@ -87,16 +64,46 @@ const items = [
{ id: 3, icon: iconMenu, msg: "btn3" },
{ id: 4, icon: iconMenu, msg: "btn4" },
]
const themeSidebar = ref("")
function closeSidebar() {
isClose.value = true;
console.info("Close sidebar")
}
function openSidebar() {
isClose.value = false;
console.info("Open sidebar")
}
function toggleSidebar() {
if (isClose.value) {
openSidebar()
themeSidebar.value = "card-dash sidebar-base sidebar-open"
}
else {
closeSidebar()
themeSidebar.value = "card-dash sidebar-base sidebar-close"
}
}
</script>
<style scoped lang="postcss">
@import "../assets/main.css";
@reference "../assets/main.css";
.sidebar-base {
@apply shadow-xl w-80 h-screen
@apply card shadow-xl h-screen;
}
.sidebar-open {}
.sidebar-open {
@apply w-80
}
.sidebar-close {}
.sidebar-close {
@apply w-31
}
@custom-variant
</style>

View File

@ -0,0 +1,36 @@
<template>
<div>
<label class="swap swap-rotate">
<!-- this hidden checkbox controls the state -->
<input type="checkbox" value="synthwave" @click="theme.toggleTheme" :checked="checkState" />
<!-- sun icon -->
<svg class="swap-off h-10 w-10 fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z" />
</svg>
<!-- moon icon -->
<svg class="swap-on h-10 w-10 fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z" />
</svg>
</label>
</div>
</template>
<script setup lang="ts">
import { useThemeStore } from '@/stores/theme';
import { computed } from 'vue';
const theme = useThemeStore();
const checkState = computed(() => {
return theme.isDarkTheme()
})
</script>
<style scoped lang="postcss">
@import "../assets/main.css"
</style>

View File

@ -0,0 +1,45 @@
<template>
<div>
<label class="toggle text-base-content">
<input type="checkbox" value="synthwave" class="theme-controller" @click="theme.toggleTheme"
:checked="checkState">
<svg aria-label="sun" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<g stroke-linejoin="round" stroke-linecap="round" stroke-width="2" fill="none" stroke="currentColor">
<circle cx="12" cy="12" r="4"></circle>
<path d="M12 2v2"></path>
<path d="M12 20v2"></path>
<path d="m4.93 4.93 1.41 1.41"></path>
<path d="m17.66 17.66 1.41 1.41"></path>
<path d="M2 12h2"></path>
<path d="M20 12h2"></path>
<path d="m6.34 17.66-1.41 1.41"></path>
<path d="m19.07 4.93-1.41 1.41"></path>
</g>
</svg>
<svg aria-label="moon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<g stroke-linejoin="round" stroke-linecap="round" stroke-width="2" fill="none" stroke="currentColor">
<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path>
</g>
</svg>
</label>
</div>
</template>
<script setup lang="ts">
import { useThemeStore } from '@/stores/theme';
import { computed } from 'vue';
const theme = useThemeStore();
const checkState = computed(() => {
return theme.isDarkTheme()
})
</script>
<style scoped lang="postcss">
@import "../assets/main.css"
</style>

View File

@ -10,3 +10,4 @@ export const useCounterStore = defineStore('counter', () => {
return { count, doubleCount, increment }
})

47
src/stores/theme.ts Normal file
View File

@ -0,0 +1,47 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useThemeStore = defineStore('theme', () => {
const allTheme = ["winter", "night"]
const darkTheme = "night";
const lightTheme = "winter";
const currentTheme = ref("night")
function setTheme(theme: string) {
const isContained: boolean = allTheme.includes(theme)
if (isContained) {
currentTheme.value = theme
}
else {
console.error('Not have such theme: ${theme}')
}
}
function toggleTheme() {
if (currentTheme.value == darkTheme) {
currentTheme.value = lightTheme;
} else if (currentTheme.value == lightTheme) {
currentTheme.value = darkTheme;
} else {
currentTheme.value = lightTheme;
}
}
function isDarkTheme(): boolean {
return currentTheme.value == darkTheme
}
function isLightTheme(): boolean {
return currentTheme.value == lightTheme
}
return {
allTheme,
currentTheme,
setTheme,
toggleTheme,
isDarkTheme,
isLightTheme
}
})