样式优化
This commit is contained in:
+67
-47
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, computed } from 'vue'
|
import { ref, onMounted, computed, nextTick } from 'vue'
|
||||||
import PromptEditor from './components/PromptEditor.vue'
|
import PromptEditor from './components/PromptEditor.vue'
|
||||||
import PromptManager from './components/PromptManager.vue'
|
import PromptManager from './components/PromptManager.vue'
|
||||||
import PresetManager from './components/PresetManager.vue'
|
import PresetManager from './components/PresetManager.vue'
|
||||||
@@ -9,6 +9,14 @@ import GridBackground from './components/Background/GridBackground.vue'
|
|||||||
import DevtoolsBanner from './components/DevtoolsBanner.vue'
|
import DevtoolsBanner from './components/DevtoolsBanner.vue'
|
||||||
import { usePromptStore } from './stores/promptStore'
|
import { usePromptStore } from './stores/promptStore'
|
||||||
|
|
||||||
|
// Icons
|
||||||
|
import IconEditor from './components/icons/IconEditor.vue'
|
||||||
|
import IconPresets from './components/icons/IconPresets.vue'
|
||||||
|
import IconManager from './components/icons/IconManager.vue'
|
||||||
|
import IconTheme from './components/icons/IconTheme.vue'
|
||||||
|
import IconBackground from './components/icons/IconBackground.vue'
|
||||||
|
import IconGithub from './components/icons/IconGithub.vue'
|
||||||
|
|
||||||
const currentView = ref<'editor' | 'manager' | 'presets'>('editor')
|
const currentView = ref<'editor' | 'manager' | 'presets'>('editor')
|
||||||
const isDark = ref(false)
|
const isDark = ref(false)
|
||||||
const bgModes = ['particles', 'grid', 'gradient', 'off'] as const
|
const bgModes = ['particles', 'grid', 'gradient', 'off'] as const
|
||||||
@@ -39,10 +47,47 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
function toggleTheme() {
|
function toggleTheme(event: MouseEvent) {
|
||||||
|
const isAppearanceTransition = 'startViewTransition' in document
|
||||||
|
&& !window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||||
|
|
||||||
|
if (!isAppearanceTransition) {
|
||||||
isDark.value = !isDark.value
|
isDark.value = !isDark.value
|
||||||
localStorage.setItem('theme', isDark.value ? 'dark' : 'light')
|
localStorage.setItem('theme', isDark.value ? 'dark' : 'light')
|
||||||
updateTheme()
|
updateTheme()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const x = event.clientX
|
||||||
|
const y = event.clientY
|
||||||
|
const endRadius = Math.hypot(
|
||||||
|
Math.max(x, innerWidth - x),
|
||||||
|
Math.max(y, innerHeight - y)
|
||||||
|
)
|
||||||
|
|
||||||
|
const transition = document.startViewTransition(async () => {
|
||||||
|
isDark.value = !isDark.value
|
||||||
|
localStorage.setItem('theme', isDark.value ? 'dark' : 'light')
|
||||||
|
updateTheme()
|
||||||
|
await nextTick()
|
||||||
|
})
|
||||||
|
|
||||||
|
transition.ready.then(() => {
|
||||||
|
const clipPath = [
|
||||||
|
`circle(0px at ${x}px ${y}px)`,
|
||||||
|
`circle(${endRadius}px at ${x}px ${y}px)`
|
||||||
|
]
|
||||||
|
document.documentElement.animate(
|
||||||
|
{
|
||||||
|
clipPath: clipPath,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
duration: 400,
|
||||||
|
easing: 'ease-out',
|
||||||
|
pseudoElement: '::view-transition-new(root)',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateTheme() {
|
function updateTheme() {
|
||||||
@@ -92,9 +137,7 @@ const bgModeLabel = computed(() => {
|
|||||||
title="打开 GitHub 仓库"
|
title="打开 GitHub 仓库"
|
||||||
>
|
>
|
||||||
<!-- GitHub 标志 -->
|
<!-- GitHub 标志 -->
|
||||||
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
<IconGithub />
|
||||||
<path fill="currentColor" fill-rule="evenodd" clip-rule="evenodd" d="M12 2C6.477 2 2 6.477 2 12c0 4.418 2.865 8.166 6.839 9.49.5.09.682-.217.682-.483 0-.237-.009-.868-.013-1.705-2.782.604-3.37-1.342-3.37-1.342-.455-1.157-1.111-1.466-1.111-1.466-.908-.62.069-.607.069-.607 1.003.07 1.53 1.03 1.53 1.03.892 1.528 2.341 1.087 2.91.832.092-.646.35-1.087.637-1.338-2.221-.253-4.558-1.11-4.558-4.941 0-1.091.39-1.984 1.029-2.682-.104-.254-.446-1.274.098-2.656 0 0 .84-.269 2.753 1.025.798-.222 1.653-.333 2.504-.337.85.004 1.706.115 2.504.337 1.911-1.294 2.75-1.025 2.75-1.025.546 1.382.203 2.402.1 2.656.64.698 1.028 1.591 1.028 2.682 0 3.84-2.34 4.685-4.566 4.934.359.309.679.919.679 1.853 0 1.337-.012 2.415-.012 2.744 0 .268.18.577.688.479C19.137 20.163 22 16.416 22 12c0-5.523-4.477-10-10-10z"/>
|
|
||||||
</svg>
|
|
||||||
<span class="app-title">提示词编辑器</span>
|
<span class="app-title">提示词编辑器</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -105,10 +148,7 @@ const bgModeLabel = computed(() => {
|
|||||||
:class="{ active: currentView === 'editor' }"
|
:class="{ active: currentView === 'editor' }"
|
||||||
@click="switchView('editor')"
|
@click="switchView('editor')"
|
||||||
>
|
>
|
||||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<IconEditor width="16" height="16" />
|
||||||
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
||||||
<path d="m18.5 2.5 3 3L12 15l-4 1 1-4 9.5-9.5z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
||||||
</svg>
|
|
||||||
<span>编辑器</span>
|
<span>编辑器</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@@ -116,11 +156,7 @@ const bgModeLabel = computed(() => {
|
|||||||
:class="{ active: currentView === 'presets' }"
|
:class="{ active: currentView === 'presets' }"
|
||||||
@click="switchView('presets')"
|
@click="switchView('presets')"
|
||||||
>
|
>
|
||||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<IconPresets width="16" height="16" />
|
||||||
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z" stroke="currentColor" stroke-width="2"/>
|
|
||||||
<polyline points="17,21 17,13 7,13 7,21" stroke="currentColor" stroke-width="2"/>
|
|
||||||
<polyline points="7,3 7,8 15,8" stroke="currentColor" stroke-width="2"/>
|
|
||||||
</svg>
|
|
||||||
<span>预设管理</span>
|
<span>预设管理</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@@ -128,46 +164,17 @@ const bgModeLabel = computed(() => {
|
|||||||
:class="{ active: currentView === 'manager' }"
|
:class="{ active: currentView === 'manager' }"
|
||||||
@click="switchView('manager')"
|
@click="switchView('manager')"
|
||||||
>
|
>
|
||||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<IconManager width="16" height="16" />
|
||||||
<path d="M3 3h18v18H3zM9 9h6v6H9z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
||||||
</svg>
|
|
||||||
<span>词库管理</span>
|
<span>词库管理</span>
|
||||||
</button>
|
</button>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<button class="theme-toggle" @click="toggleTheme" title="切换主题">
|
<button class="theme-toggle" @click="toggleTheme" title="切换主题">
|
||||||
<svg v-if="!isDark" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<IconTheme :is-dark="isDark" />
|
||||||
<circle cx="12" cy="12" r="5" stroke="currentColor" stroke-width="2"/>
|
|
||||||
<path d="m12 1 0 2m0 18 0 2M4.22 4.22l1.42 1.42m12.72 12.72 1.42 1.42M1 12l2 0m18 0 2 0M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
|
||||||
</svg>
|
|
||||||
<svg v-else width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
</button>
|
||||||
<button class="bg-toggle" :class="{ active: currentBgMode !== 'off' }" @click="cycleBackground" :title="bgModeLabel">
|
<button class="bg-toggle" :class="{ active: currentBgMode !== 'off' }" @click="cycleBackground" :title="bgModeLabel">
|
||||||
<!-- Particles Icon -->
|
<IconBackground :mode="currentBgMode" />
|
||||||
<svg v-if="currentBgMode === 'particles'" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<circle cx="6" cy="12" r="1.5" fill="currentColor"/>
|
|
||||||
<circle cx="12" cy="9" r="1.5" fill="currentColor"/>
|
|
||||||
<circle cx="18" cy="13" r="1.5" fill="currentColor"/>
|
|
||||||
<path d="M4 16c4-2 8-2 12 0" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
|
||||||
</svg>
|
|
||||||
<!-- Grid Icon -->
|
|
||||||
<svg v-else-if="currentBgMode === 'grid'" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M3 3h18v18H3z" stroke="currentColor" stroke-width="2"/>
|
|
||||||
<path d="M3 9h18M3 15h18M9 3v18M15 3v18" stroke="currentColor" stroke-width="2"/>
|
|
||||||
</svg>
|
|
||||||
<!-- Gradient Icon -->
|
|
||||||
<svg v-else-if="currentBgMode === 'gradient'" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/>
|
|
||||||
<path d="M8 12s1.5-2 4-2 4 2 4 2" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
|
||||||
</svg>
|
|
||||||
<!-- Off Icon -->
|
|
||||||
<svg v-else width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M5 5l14 14" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
|
||||||
<circle cx="12" cy="12" r="6" stroke="currentColor" stroke-width="2"/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -185,7 +192,20 @@ const bgModeLabel = computed(() => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* 全局样式重置和变量定义 */
|
/* View Transitions API styles */
|
||||||
|
::view-transition-old(root),
|
||||||
|
::view-transition-new(root) {
|
||||||
|
animation: none;
|
||||||
|
mix-blend-mode: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
::view-transition-old(root) {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
::view-transition-new(root) {
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
/* 亮色主题 */
|
/* 亮色主题 */
|
||||||
--color-bg-primary: #ffffff;
|
--color-bg-primary: #ffffff;
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
mode: 'particles' | 'grid' | 'gradient' | 'off'
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const iconName = computed(() => {
|
||||||
|
switch (props.mode) {
|
||||||
|
case 'particles': return 'icon-particles'
|
||||||
|
case 'grid': return 'icon-grid'
|
||||||
|
case 'gradient': return 'icon-gradient'
|
||||||
|
default: return 'icon-off'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="icon-bg-container">
|
||||||
|
<Transition name="icon-fade" mode="out-in">
|
||||||
|
<svg v-if="mode === 'particles'" key="particles" width="24" height="24" viewBox="0 0 24 24" fill="none" class="icon-particles">
|
||||||
|
<circle cx="6" cy="12" r="1.5" fill="currentColor" class="dot-1"/>
|
||||||
|
<circle cx="12" cy="9" r="1.5" fill="currentColor" class="dot-2"/>
|
||||||
|
<circle cx="18" cy="13" r="1.5" fill="currentColor" class="dot-3"/>
|
||||||
|
<path d="M4 16c4-2 8-2 12 0" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" class="wave"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<svg v-else-if="mode === 'grid'" key="grid" width="24" height="24" viewBox="0 0 24 24" fill="none" class="icon-grid">
|
||||||
|
<path d="M3 3h18v18H3z" stroke="currentColor" stroke-width="2" class="grid-border"/>
|
||||||
|
<path d="M3 9h18M3 15h18M9 3v18M15 3v18" stroke="currentColor" stroke-width="2" class="grid-lines"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<svg v-else-if="mode === 'gradient'" key="gradient" width="24" height="24" viewBox="0 0 24 24" fill="none" class="icon-gradient">
|
||||||
|
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" class="gradient-circle"/>
|
||||||
|
<path d="M8 12s1.5-2 4-2 4 2 4 2" stroke="currentColor" stroke-width="2" stroke-linecap="round" class="gradient-wave"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<svg v-else key="off" width="24" height="24" viewBox="0 0 24 24" fill="none" class="icon-off">
|
||||||
|
<path d="M5 5l14 14" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<circle cx="12" cy="12" r="6" stroke="currentColor" stroke-width="2"/>
|
||||||
|
</svg>
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.icon-bg-container {
|
||||||
|
width: 1.25rem;
|
||||||
|
height: 1.25rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-fade-enter-active,
|
||||||
|
.icon-fade-leave-active {
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-fade-enter-from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.8) rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.8) rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Animations */
|
||||||
|
.dot-1, .dot-2, .dot-3 {
|
||||||
|
animation: float 3s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
.dot-2 { animation-delay: 0.5s; }
|
||||||
|
.dot-3 { animation-delay: 1s; }
|
||||||
|
|
||||||
|
.grid-lines {
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
}
|
||||||
|
.icon-grid:hover .grid-lines {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gradient-circle {
|
||||||
|
transition: stroke-dasharray 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes float {
|
||||||
|
0%, 100% { transform: translateY(0); }
|
||||||
|
50% { transform: translateY(-2px); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-bg-container:hover .wave {
|
||||||
|
animation: wave 2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes wave {
|
||||||
|
0% { d: path("M4 16c4-2 8-2 12 0"); }
|
||||||
|
50% { d: path("M4 16c4 2 8 2 12 0"); }
|
||||||
|
100% { d: path("M4 16c4-2 8-2 12 0"); }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="icon-editor"
|
||||||
|
>
|
||||||
|
<path class="paper" d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" />
|
||||||
|
<path class="pencil" d="m18.5 2.5 3 3L12 15l-4 1 1-4 9.5-9.5z" />
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.icon-editor {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pencil {
|
||||||
|
transform-origin: center;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.paper {
|
||||||
|
transition: stroke-dashoffset 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hover effect handled by parent class usually, or we can use :hover if the svg itself is the target */
|
||||||
|
:deep(.nav-btn:hover) .pencil,
|
||||||
|
svg:hover .pencil {
|
||||||
|
transform: translate(2px, -2px) rotate(5deg);
|
||||||
|
animation: write 1s ease-in-out infinite alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes write {
|
||||||
|
0% { transform: translate(0, 0) rotate(0); }
|
||||||
|
100% { transform: translate(2px, -2px) rotate(10deg); }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<template>
|
||||||
|
<svg
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
aria-hidden="true"
|
||||||
|
class="icon-github"
|
||||||
|
>
|
||||||
|
<path fill="currentColor" fill-rule="evenodd" clip-rule="evenodd" d="M12 2C6.477 2 2 6.477 2 12c0 4.418 2.865 8.166 6.839 9.49.5.09.682-.217.682-.483 0-.237-.009-.868-.013-1.705-2.782.604-3.37-1.342-3.37-1.342-.455-1.157-1.111-1.466-1.111-1.466-.908-.62.069-.607.069-.607 1.003.07 1.53 1.03 1.53 1.03.892 1.528 2.341 1.087 2.91.832.092-.646.35-1.087.637-1.338-2.221-.253-4.558-1.11-4.558-4.941 0-1.091.39-1.984 1.029-2.682-.104-.254-.446-1.274.098-2.656 0 0 .84-.269 2.753 1.025.798-.222 1.653-.333 2.504-.337.85.004 1.706.115 2.504.337 1.911-1.294 2.75-1.025 2.75-1.025.546 1.382.203 2.402.1 2.656.64.698 1.028 1.591 1.028 2.682 0 3.84-2.34 4.685-4.566 4.934.359.309.679.919.679 1.853 0 1.337-.012 2.415-.012 2.744 0 .268.18.577.688.479C19.137 20.163 22 16.416 22 12c0-5.523-4.477-10-10-10z"/>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.icon-github {
|
||||||
|
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-github:hover {
|
||||||
|
transform: scale(1.1) rotate(5deg);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<template>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="icon-manager"
|
||||||
|
>
|
||||||
|
<path class="disk-top" d="M21 5c0 1.66-4 3-9 3s-9-1.34-9-3 4-3 9-3 9 1.34 9 3z" />
|
||||||
|
<path class="disk-middle" d="M3 5v6c0 1.66 4 3 9 3s9-1.34 9-3V5" />
|
||||||
|
<path class="disk-bottom" d="M3 11v6c0 1.66 4 3 9 3s9-1.34 9-3v-6" />
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.disk-top, .disk-middle, .disk-bottom {
|
||||||
|
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.nav-btn:hover) .disk-top,
|
||||||
|
svg:hover .disk-top {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.nav-btn:hover) .disk-bottom,
|
||||||
|
svg:hover .disk-bottom {
|
||||||
|
transform: translateY(1px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<template>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="icon-presets"
|
||||||
|
>
|
||||||
|
<path class="layout-main" d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z" />
|
||||||
|
<polyline class="layout-line-1" points="17 21 17 13 7 13 7 21" />
|
||||||
|
<polyline class="layout-line-2" points="7 3 7 8 15 8" />
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.layout-main, .layout-line-1, .layout-line-2 {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
transform-origin: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.nav-btn:hover) .layout-line-1,
|
||||||
|
svg:hover .layout-line-1 {
|
||||||
|
transform: scaleY(0.9) translateY(1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.nav-btn:hover) .layout-line-2,
|
||||||
|
svg:hover .layout-line-2 {
|
||||||
|
transform: translateX(1px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
defineProps<{
|
||||||
|
isDark: boolean
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="icon-theme-container">
|
||||||
|
<svg
|
||||||
|
class="icon-sun"
|
||||||
|
:class="{ 'is-hidden': isDark }"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<circle cx="12" cy="12" r="5" />
|
||||||
|
<line x1="12" y1="1" x2="12" y2="3" />
|
||||||
|
<line x1="12" y1="21" x2="12" y2="23" />
|
||||||
|
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
|
||||||
|
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
|
||||||
|
<line x1="1" y1="12" x2="3" y2="12" />
|
||||||
|
<line x1="21" y1="12" x2="23" y2="12" />
|
||||||
|
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
|
||||||
|
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<svg
|
||||||
|
class="icon-moon"
|
||||||
|
:class="{ 'is-visible': isDark }"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.icon-theme-container {
|
||||||
|
position: relative;
|
||||||
|
width: 1.25rem;
|
||||||
|
height: 1.25rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-sun {
|
||||||
|
opacity: 1;
|
||||||
|
transform: rotate(0) scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-sun.is-hidden {
|
||||||
|
opacity: 0;
|
||||||
|
transform: rotate(90deg) scale(0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-moon {
|
||||||
|
opacity: 0;
|
||||||
|
transform: rotate(-90deg) scale(0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-moon.is-visible {
|
||||||
|
opacity: 1;
|
||||||
|
transform: rotate(0) scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hover effects */
|
||||||
|
.icon-theme-container:hover .icon-sun:not(.is-hidden) {
|
||||||
|
animation: spin 4s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-theme-container:hover .icon-moon.is-visible {
|
||||||
|
animation: swing 2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
from { transform: rotate(0); }
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes swing {
|
||||||
|
0%, 100% { transform: rotate(0) scale(1); }
|
||||||
|
50% { transform: rotate(-15deg) scale(1.1); }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+1
-1
@@ -39,7 +39,7 @@ body {
|
|||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
}
|
}
|
||||||
a:hover {
|
a:hover {
|
||||||
color: #747bff;
|
color: #2da44e;
|
||||||
}
|
}
|
||||||
button {
|
button {
|
||||||
background-color: #f9f9f9;
|
background-color: #f9f9f9;
|
||||||
|
|||||||
Reference in New Issue
Block a user