mirror of
https://github.com/LifeArchiveProject/WeChatDataAnalysis.git
synced 2026-02-19 22:30:49 +08:00
improvement(wrapped-ui): 移除 VHS 主题并优化 DOS/CRT 视觉效果
- 主题系统收敛为 Modern/Game Boy/DOS(快捷键改为 F1-F3) - 删除 VHS 切换器与相关样式(卡片/控件/年份选择/图表等) - DOS 主题统一使用像素字体,减弱发光强度并细化扫描线/闪烁参数 - DOS 闪烁光标改由 WrappedCRTOverlay 渲染,避免全局样式副作用 - 移除热力图 vhs 配色分支
This commit is contained in:
@@ -264,8 +264,8 @@
|
|||||||
|
|
||||||
/* CRT 闪烁 - 亮度波动 */
|
/* CRT 闪烁 - 亮度波动 */
|
||||||
.crt-flicker {
|
.crt-flicker {
|
||||||
background-color: rgba(255, 255, 255, 0.015);
|
background-color: rgba(255, 255, 255, 0.01);
|
||||||
animation: crt-flicker 0.08s infinite alternate;
|
animation: crt-flicker 0.15s infinite alternate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CRT 暗角 - 边缘渐暗(更强) */
|
/* CRT 暗角 - 边缘渐暗(更强) */
|
||||||
@@ -1113,7 +1113,7 @@
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
50% {
|
50% {
|
||||||
opacity: 0.98;
|
opacity: 0.985;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1149,7 +1149,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================
|
/* ============================================
|
||||||
Wrapped 三主题系统 - Game Boy / DOS / VHS
|
Wrapped 主题系统 - Game Boy / DOS
|
||||||
============================================ */
|
============================================ */
|
||||||
|
|
||||||
/* 复古模式共享基础样式 */
|
/* 复古模式共享基础样式 */
|
||||||
@@ -1225,7 +1225,10 @@
|
|||||||
--wrapped-warning: #ffaa00; /* 琥珀警告色 */
|
--wrapped-warning: #ffaa00; /* 琥珀警告色 */
|
||||||
|
|
||||||
background-color: #000000 !important;
|
background-color: #000000 !important;
|
||||||
font-family: 'Courier New', 'Consolas', monospace !important;
|
/* 使用现有 Fusion Pixel 10px 字体 */
|
||||||
|
font-family: var(--font-pixel-10), 'Courier New', monospace !important;
|
||||||
|
-webkit-font-smoothing: none;
|
||||||
|
image-rendering: pixelated;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* DOS 文字发光效果 */
|
/* DOS 文字发光效果 */
|
||||||
@@ -1234,34 +1237,14 @@
|
|||||||
.wrapped-theme-dos .wrapped-label,
|
.wrapped-theme-dos .wrapped-label,
|
||||||
.wrapped-theme-dos .wrapped-number {
|
.wrapped-theme-dos .wrapped-number {
|
||||||
color: #33ff33 !important;
|
color: #33ff33 !important;
|
||||||
|
/* 从 4 层减少到 2 层,降低发光强度 */
|
||||||
text-shadow:
|
text-shadow:
|
||||||
0 0 5px #33ff33,
|
0 0 4px rgba(51, 255, 51, 0.8),
|
||||||
0 0 10px #33ff33,
|
0 0 8px rgba(34, 170, 34, 0.4);
|
||||||
0 0 20px #33ff33,
|
font-family: var(--font-pixel-10), 'Courier New', monospace !important;
|
||||||
0 0 40px #22aa22;
|
|
||||||
font-family: 'Courier New', 'Consolas', monospace !important;
|
|
||||||
-webkit-font-smoothing: none;
|
-webkit-font-smoothing: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* DOS 闪烁光标 */
|
|
||||||
.wrapped-theme-dos::after {
|
|
||||||
content: '█';
|
|
||||||
color: #33ff33;
|
|
||||||
animation: dos-cursor-blink 530ms steps(1) infinite;
|
|
||||||
position: fixed;
|
|
||||||
bottom: 20px;
|
|
||||||
right: 20px;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
text-shadow: 0 0 10px #33ff33;
|
|
||||||
z-index: 100;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes dos-cursor-blink {
|
|
||||||
0%, 50% { opacity: 1; }
|
|
||||||
51%, 100% { opacity: 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* DOS ASCII 边框 */
|
/* DOS ASCII 边框 */
|
||||||
.wrapped-theme-dos .wrapped-card-shell,
|
.wrapped-theme-dos .wrapped-card-shell,
|
||||||
.wrapped-theme-dos [class*="border"] {
|
.wrapped-theme-dos [class*="border"] {
|
||||||
@@ -1277,16 +1260,16 @@
|
|||||||
transition: text-shadow 0.1s ease-out !important;
|
transition: text-shadow 0.1s ease-out !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* DOS 扫描线(更明显) */
|
/* DOS 扫描线(细化) */
|
||||||
.wrapped-theme-dos .crt-scanlines {
|
.wrapped-theme-dos .crt-scanlines {
|
||||||
background: repeating-linear-gradient(
|
background: repeating-linear-gradient(
|
||||||
to bottom,
|
to bottom,
|
||||||
transparent 0px,
|
transparent 0px,
|
||||||
transparent 2px,
|
transparent 1px,
|
||||||
rgba(0, 0, 0, 0.4) 2px,
|
rgba(0, 0, 0, 0.15) 1px,
|
||||||
rgba(0, 0, 0, 0.4) 4px
|
rgba(0, 0, 0, 0.15) 2px
|
||||||
) !important;
|
) !important;
|
||||||
opacity: 0.8;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* DOS 按钮样式 */
|
/* DOS 按钮样式 */
|
||||||
@@ -1304,205 +1287,3 @@
|
|||||||
color: #000000 !important;
|
color: #000000 !important;
|
||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================
|
|
||||||
Theme 3: VHS Tape - 色彩溢出与信号干扰
|
|
||||||
============================================ */
|
|
||||||
.wrapped-theme-vhs {
|
|
||||||
--wrapped-bg: #1a1a2e;
|
|
||||||
--wrapped-card-bg: #16213e;
|
|
||||||
--wrapped-text: #eaeaea;
|
|
||||||
--wrapped-text-secondary: #a0a0a0;
|
|
||||||
--wrapped-accent: #e94560;
|
|
||||||
--wrapped-border: #0f3460;
|
|
||||||
--wrapped-warning: #f39c12;
|
|
||||||
|
|
||||||
background-color: #1a1a2e !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* VHS 色彩溢出(Chromatic Aberration) */
|
|
||||||
.wrapped-theme-vhs .wrapped-title,
|
|
||||||
.wrapped-theme-vhs .wrapped-number {
|
|
||||||
position: relative;
|
|
||||||
color: #eaeaea !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .wrapped-title::before,
|
|
||||||
.wrapped-theme-vhs .wrapped-number::before {
|
|
||||||
content: attr(data-text);
|
|
||||||
position: absolute;
|
|
||||||
left: -2px;
|
|
||||||
top: 0;
|
|
||||||
color: #00fff7;
|
|
||||||
opacity: 0.7;
|
|
||||||
z-index: -1;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .wrapped-title::after,
|
|
||||||
.wrapped-theme-vhs .wrapped-number::after {
|
|
||||||
content: attr(data-text);
|
|
||||||
position: absolute;
|
|
||||||
left: 2px;
|
|
||||||
top: 0;
|
|
||||||
color: #ff00ff;
|
|
||||||
opacity: 0.7;
|
|
||||||
z-index: -1;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* VHS 水平条纹滚动 */
|
|
||||||
.wrapped-theme-vhs::before {
|
|
||||||
content: '';
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background: repeating-linear-gradient(
|
|
||||||
to bottom,
|
|
||||||
transparent 0px,
|
|
||||||
transparent 4px,
|
|
||||||
rgba(255, 255, 255, 0.03) 4px,
|
|
||||||
rgba(255, 255, 255, 0.03) 8px
|
|
||||||
);
|
|
||||||
animation: vhs-scanlines 8s linear infinite;
|
|
||||||
pointer-events: none;
|
|
||||||
z-index: 50;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes vhs-scanlines {
|
|
||||||
0% { transform: translateY(0); }
|
|
||||||
100% { transform: translateY(100px); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* VHS 信号干扰/故障动画 */
|
|
||||||
.wrapped-theme-vhs .wrapped-card-shell {
|
|
||||||
animation: vhs-glitch 3s infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes vhs-glitch {
|
|
||||||
0%, 95%, 100% {
|
|
||||||
transform: translate(0);
|
|
||||||
filter: none;
|
|
||||||
}
|
|
||||||
96% {
|
|
||||||
transform: translate(-2px, 1px);
|
|
||||||
filter: hue-rotate(90deg);
|
|
||||||
}
|
|
||||||
97% {
|
|
||||||
transform: translate(2px, -1px);
|
|
||||||
filter: hue-rotate(-90deg) saturate(1.5);
|
|
||||||
}
|
|
||||||
98% {
|
|
||||||
transform: translate(-1px, 2px);
|
|
||||||
filter: brightness(1.2);
|
|
||||||
}
|
|
||||||
99% {
|
|
||||||
transform: translate(1px, -2px);
|
|
||||||
filter: contrast(1.2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* VHS 降低对比度和饱和度 */
|
|
||||||
.wrapped-theme-vhs img,
|
|
||||||
.wrapped-theme-vhs svg {
|
|
||||||
filter: saturate(0.8) contrast(0.9);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* VHS 时间戳样式 */
|
|
||||||
.wrapped-theme-vhs .vhs-timestamp {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 20px;
|
|
||||||
right: 20px;
|
|
||||||
font-family: 'VCR OSD Mono', 'Courier New', monospace;
|
|
||||||
font-size: 1rem;
|
|
||||||
color: #ffffff;
|
|
||||||
background: rgba(0, 0, 0, 0.6);
|
|
||||||
padding: 4px 8px;
|
|
||||||
text-shadow: 2px 2px 0 #ff0000, -2px -2px 0 #00ffff;
|
|
||||||
z-index: 100;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* VHS 跟踪线效果 */
|
|
||||||
.wrapped-theme-vhs .vhs-tracking {
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
height: 3px;
|
|
||||||
background: linear-gradient(
|
|
||||||
to right,
|
|
||||||
transparent 0%,
|
|
||||||
rgba(255, 255, 255, 0.8) 50%,
|
|
||||||
transparent 100%
|
|
||||||
);
|
|
||||||
animation: vhs-tracking 2s ease-in-out infinite;
|
|
||||||
pointer-events: none;
|
|
||||||
z-index: 60;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes vhs-tracking {
|
|
||||||
0%, 100% {
|
|
||||||
top: -10px;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
10% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
90% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
95% {
|
|
||||||
top: calc(100vh + 10px);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* VHS 边框样式 */
|
|
||||||
.wrapped-theme-vhs [class*="border"] {
|
|
||||||
border-color: #0f3460 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs [class*="rounded"] {
|
|
||||||
border-radius: 2px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* VHS 按钮样式 */
|
|
||||||
.wrapped-theme-vhs button {
|
|
||||||
background: linear-gradient(135deg, #e94560 0%, #0f3460 100%) !important;
|
|
||||||
border: none !important;
|
|
||||||
color: #ffffff !important;
|
|
||||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
|
|
||||||
box-shadow: 0 2px 10px rgba(233, 69, 96, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs button:hover {
|
|
||||||
filter: brightness(1.1);
|
|
||||||
box-shadow: 0 4px 15px rgba(233, 69, 96, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* VHS REC 指示器 */
|
|
||||||
.wrapped-theme-vhs .vhs-rec {
|
|
||||||
position: fixed;
|
|
||||||
top: 20px;
|
|
||||||
left: 20px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
font-family: 'VCR OSD Mono', 'Courier New', monospace;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
color: #ff0000;
|
|
||||||
z-index: 100;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .vhs-rec::before {
|
|
||||||
content: '●';
|
|
||||||
animation: vhs-rec-blink 1s steps(1) infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes vhs-rec-blink {
|
|
||||||
0%, 50% { opacity: 1; }
|
|
||||||
51%, 100% { opacity: 0; }
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,62 +1,38 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- CRT/VHS 滤镜叠加层 - 根据主题切换效果 -->
|
<!-- CRT 滤镜叠加层 - 复古主题使用 -->
|
||||||
<div class="absolute inset-0 pointer-events-none select-none z-30" aria-hidden="true">
|
<div class="absolute inset-0 pointer-events-none select-none z-30" aria-hidden="true">
|
||||||
<!-- Game Boy / DOS: 扫描线层 -->
|
<!-- 扫描线 / RGB 子像素 / 闪烁 / 暗角 / 曲率 -->
|
||||||
<div v-if="theme !== 'vhs'" class="absolute inset-0 crt-scanlines"></div>
|
<div class="absolute inset-0 crt-scanlines"></div>
|
||||||
|
<div class="absolute inset-0 crt-rgb-pixels"></div>
|
||||||
<!-- Game Boy / DOS: RGB 子像素层 -->
|
<div class="absolute inset-0 crt-flicker"></div>
|
||||||
<div v-if="theme !== 'vhs'" class="absolute inset-0 crt-rgb-pixels"></div>
|
|
||||||
|
|
||||||
<!-- Game Boy / DOS: 闪烁层 -->
|
|
||||||
<div v-if="theme !== 'vhs'" class="absolute inset-0 crt-flicker"></div>
|
|
||||||
|
|
||||||
<!-- 共享: 暗角层 -->
|
|
||||||
<div class="absolute inset-0 crt-vignette"></div>
|
<div class="absolute inset-0 crt-vignette"></div>
|
||||||
|
<div class="absolute inset-0 crt-curvature"></div>
|
||||||
|
|
||||||
<!-- Game Boy / DOS: 屏幕曲率层 -->
|
<!-- DOS: 语义化光标 -->
|
||||||
<div v-if="theme !== 'vhs'" class="absolute inset-0 crt-curvature"></div>
|
<div v-if="theme === 'dos'" class="dos-cursor">█</div>
|
||||||
|
|
||||||
<!-- VHS: 跟踪线效果 -->
|
|
||||||
<div v-if="theme === 'vhs'" class="vhs-tracking"></div>
|
|
||||||
|
|
||||||
<!-- VHS: REC 指示器 -->
|
|
||||||
<div v-if="theme === 'vhs'" class="vhs-rec">REC</div>
|
|
||||||
|
|
||||||
<!-- VHS: 时间戳 -->
|
|
||||||
<div v-if="theme === 'vhs'" class="vhs-timestamp">{{ vhsTimestamp }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
// CRT/VHS 滤镜叠加层组件
|
|
||||||
// 根据当前主题切换不同的视觉效果
|
|
||||||
|
|
||||||
const { theme } = useWrappedTheme()
|
const { theme } = useWrappedTheme()
|
||||||
|
</script>
|
||||||
|
|
||||||
// VHS 时间戳(实时更新)
|
<style scoped>
|
||||||
const vhsTimestamp = ref('')
|
/* DOS 语义化光标 */
|
||||||
|
.dos-cursor {
|
||||||
const updateTimestamp = () => {
|
position: fixed;
|
||||||
const now = new Date()
|
bottom: 20px;
|
||||||
const month = String(now.getMonth() + 1).padStart(2, '0')
|
right: 20px;
|
||||||
const day = String(now.getDate()).padStart(2, '0')
|
color: #33ff33;
|
||||||
const year = now.getFullYear()
|
font-size: 1.5rem;
|
||||||
const hours = String(now.getHours()).padStart(2, '0')
|
font-family: var(--font-pixel-10), 'Courier New', monospace;
|
||||||
const minutes = String(now.getMinutes()).padStart(2, '0')
|
text-shadow: 0 0 8px rgba(51, 255, 51, 0.6);
|
||||||
const seconds = String(now.getSeconds()).padStart(2, '0')
|
animation: dos-cursor-blink 530ms steps(1) infinite;
|
||||||
vhsTimestamp.value = `${month}/${day}/${year} ${hours}:${minutes}:${seconds}`
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
let timestampInterval = null
|
@keyframes dos-cursor-blink {
|
||||||
|
0%, 50% { opacity: 1; }
|
||||||
onMounted(() => {
|
51%, 100% { opacity: 0; }
|
||||||
updateTimestamp()
|
}
|
||||||
timestampInterval = setInterval(updateTimestamp, 1000)
|
</style>
|
||||||
})
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
if (timestampInterval) {
|
|
||||||
clearInterval(timestampInterval)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|||||||
@@ -118,39 +118,4 @@ defineProps({
|
|||||||
.wrapped-theme-dos .border-\[\#F3F3F3\] {
|
.wrapped-theme-dos .border-\[\#F3F3F3\] {
|
||||||
border-color: #33ff33 !important;
|
border-color: #33ff33 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========== VHS 主题 ========== */
|
|
||||||
|
|
||||||
/* 卡片背景 */
|
|
||||||
.wrapped-theme-vhs .bg-white {
|
|
||||||
background: #16213e !important;
|
|
||||||
border-color: #0f3460 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 标题 */
|
|
||||||
.wrapped-theme-vhs .wrapped-title {
|
|
||||||
color: #eaeaea !important;
|
|
||||||
text-shadow:
|
|
||||||
-1px 0 rgba(0, 255, 247, 0.4),
|
|
||||||
1px 0 rgba(255, 0, 255, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 描述文字 */
|
|
||||||
.wrapped-theme-vhs .wrapped-body {
|
|
||||||
color: #a0a0a0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 数字高亮 */
|
|
||||||
.wrapped-theme-vhs .wrapped-number {
|
|
||||||
color: #e94560 !important;
|
|
||||||
text-shadow:
|
|
||||||
-1px 0 rgba(0, 255, 247, 0.5),
|
|
||||||
1px 0 rgba(255, 0, 255, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 边框 */
|
|
||||||
.wrapped-theme-vhs .border-\[\#EDEDED\],
|
|
||||||
.wrapped-theme-vhs .border-\[\#F3F3F3\] {
|
|
||||||
border-color: #0f3460 !important;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -154,28 +154,4 @@ const yearOptions = computed(() => {
|
|||||||
.wrapped-theme-dos .controls-btn:hover:not(:disabled) {
|
.wrapped-theme-dos .controls-btn:hover:not(:disabled) {
|
||||||
background-color: #44ff44;
|
background-color: #44ff44;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* VHS 特殊样式 */
|
|
||||||
.wrapped-theme-vhs .controls-panel {
|
|
||||||
border-radius: 4px;
|
|
||||||
background: linear-gradient(180deg, #16213e 0%, #1a1a2e 100%);
|
|
||||||
border-color: #0f3460;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .controls-select {
|
|
||||||
border-radius: 2px;
|
|
||||||
background: #1a1a2e;
|
|
||||||
border-color: #0f3460;
|
|
||||||
color: #eaeaea;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .controls-btn {
|
|
||||||
border-radius: 4px;
|
|
||||||
background: linear-gradient(135deg, #e94560 0%, #0f3460 100%);
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .controls-btn:hover:not(:disabled) {
|
|
||||||
box-shadow: 0 4px 15px rgba(233, 69, 96, 0.5);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -10,8 +10,7 @@ const themeSwitcherComponent = computed(() => {
|
|||||||
const map = {
|
const map = {
|
||||||
off: resolveComponent('WrappedThemeSwitcherModern'),
|
off: resolveComponent('WrappedThemeSwitcherModern'),
|
||||||
gameboy: resolveComponent('WrappedThemeSwitcherGameboy'),
|
gameboy: resolveComponent('WrappedThemeSwitcherGameboy'),
|
||||||
dos: resolveComponent('WrappedThemeSwitcherDos'),
|
dos: resolveComponent('WrappedThemeSwitcherDos')
|
||||||
vhs: resolveComponent('WrappedThemeSwitcherVhs')
|
|
||||||
}
|
}
|
||||||
return map[theme.value] || map.off
|
return map[theme.value] || map.off
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- 状态提示 -->
|
<!-- 状态提示 -->
|
||||||
<div class="dos-status">
|
<div class="dos-status">
|
||||||
Press F1-F4 to switch theme
|
Press F1-F3 to switch theme
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -26,8 +26,7 @@ const { theme, setTheme } = useWrappedTheme()
|
|||||||
const themes = [
|
const themes = [
|
||||||
{ value: 'off', label: 'Modern' },
|
{ value: 'off', label: 'Modern' },
|
||||||
{ value: 'gameboy', label: 'GameBoy' },
|
{ value: 'gameboy', label: 'GameBoy' },
|
||||||
{ value: 'dos', label: 'DOS' },
|
{ value: 'dos', label: 'DOS' }
|
||||||
{ value: 'vhs', label: 'VHS' }
|
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ const { theme, setTheme } = useWrappedTheme()
|
|||||||
const themes = [
|
const themes = [
|
||||||
{ value: 'off', label: 'MODERN' },
|
{ value: 'off', label: 'MODERN' },
|
||||||
{ value: 'gameboy', label: 'GAME BOY' },
|
{ value: 'gameboy', label: 'GAME BOY' },
|
||||||
{ value: 'dos', label: 'DOS' },
|
{ value: 'dos', label: 'DOS' }
|
||||||
{ value: 'vhs', label: 'VHS' }
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const selectTheme = (value) => {
|
const selectTheme = (value) => {
|
||||||
|
|||||||
@@ -20,12 +20,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
const { theme, setTheme, VALID_THEMES } = useWrappedTheme()
|
const { theme, setTheme } = useWrappedTheme()
|
||||||
|
|
||||||
const themes = [
|
const themes = [
|
||||||
{ value: 'off', label: 'Modern' },
|
{ value: 'off', label: 'Modern' },
|
||||||
{ value: 'gameboy', label: 'Game Boy' },
|
{ value: 'gameboy', label: 'Game Boy' },
|
||||||
{ value: 'dos', label: 'DOS' },
|
{ value: 'dos', label: 'DOS' }
|
||||||
{ value: 'vhs', label: 'VHS' }
|
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,126 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="vhs-panel select-none">
|
|
||||||
<!-- VHS 风格物理按钮组 -->
|
|
||||||
<div class="vhs-button-group">
|
|
||||||
<button
|
|
||||||
v-for="t in themes"
|
|
||||||
:key="t.value"
|
|
||||||
class="vhs-button"
|
|
||||||
:class="{ 'is-active': theme === t.value, 'is-pressed': pressedKey === t.value }"
|
|
||||||
@mousedown="pressButton(t.value)"
|
|
||||||
@mouseup="releaseButton"
|
|
||||||
@mouseleave="releaseButton"
|
|
||||||
@click="setTheme(t.value)"
|
|
||||||
>
|
|
||||||
<span class="vhs-button-face">{{ t.label }}</span>
|
|
||||||
<span class="vhs-led" :class="{ 'is-on': theme === t.value }"></span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
const { theme, setTheme } = useWrappedTheme()
|
|
||||||
|
|
||||||
const themes = [
|
|
||||||
{ value: 'off', label: 'MOD' },
|
|
||||||
{ value: 'gameboy', label: 'GB' },
|
|
||||||
{ value: 'dos', label: 'DOS' },
|
|
||||||
{ value: 'vhs', label: 'VHS' }
|
|
||||||
]
|
|
||||||
|
|
||||||
const pressedKey = ref(null)
|
|
||||||
|
|
||||||
const pressButton = (value) => {
|
|
||||||
pressedKey.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
const releaseButton = () => {
|
|
||||||
pressedKey.value = null
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.vhs-panel {
|
|
||||||
font-family: 'Arial', 'Helvetica', sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vhs-button-group {
|
|
||||||
display: flex;
|
|
||||||
gap: 6px;
|
|
||||||
padding: 8px 10px;
|
|
||||||
background: linear-gradient(180deg, #2a2a3e 0%, #1a1a2e 100%);
|
|
||||||
border-radius: 4px;
|
|
||||||
border: 1px solid #3a3a5e;
|
|
||||||
box-shadow:
|
|
||||||
inset 0 1px 0 rgba(255,255,255,0.1),
|
|
||||||
0 2px 4px rgba(0,0,0,0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vhs-button {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
gap: 4px;
|
|
||||||
padding: 0;
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vhs-button-face {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 36px;
|
|
||||||
height: 24px;
|
|
||||||
font-size: 9px;
|
|
||||||
font-weight: bold;
|
|
||||||
letter-spacing: 0.5px;
|
|
||||||
color: #cccccc;
|
|
||||||
background: linear-gradient(180deg, #4a4a5e 0%, #2a2a3e 50%, #3a3a4e 100%);
|
|
||||||
border: 1px solid #5a5a7e;
|
|
||||||
border-radius: 3px;
|
|
||||||
box-shadow:
|
|
||||||
0 2px 0 #1a1a2e,
|
|
||||||
inset 0 1px 0 rgba(255,255,255,0.2);
|
|
||||||
transition: all 0.05s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vhs-button:hover .vhs-button-face {
|
|
||||||
background: linear-gradient(180deg, #5a5a6e 0%, #3a3a4e 50%, #4a4a5e 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vhs-button.is-pressed .vhs-button-face,
|
|
||||||
.vhs-button:active .vhs-button-face {
|
|
||||||
transform: translateY(2px);
|
|
||||||
box-shadow:
|
|
||||||
0 0 0 #1a1a2e,
|
|
||||||
inset 0 1px 2px rgba(0,0,0,0.3);
|
|
||||||
background: linear-gradient(180deg, #3a3a4e 0%, #2a2a3e 50%, #3a3a4e 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vhs-button.is-active .vhs-button-face {
|
|
||||||
background: linear-gradient(135deg, #e94560 0%, #c73e54 50%, #0f3460 100%);
|
|
||||||
color: #ffffff;
|
|
||||||
border-color: #e94560;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vhs-led {
|
|
||||||
width: 6px;
|
|
||||||
height: 6px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: #1a1a1a;
|
|
||||||
border: 1px solid #3a3a3a;
|
|
||||||
transition: all 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vhs-led.is-on {
|
|
||||||
background: #ff3333;
|
|
||||||
border-color: #ff6666;
|
|
||||||
box-shadow:
|
|
||||||
0 0 4px #ff3333,
|
|
||||||
0 0 8px #ff3333,
|
|
||||||
0 0 12px rgba(255,51,51,0.5);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,34 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="year-selector" :class="selectorClass">
|
<div class="year-selector" :class="selectorClass">
|
||||||
<!-- Modern 风格:下拉菜单 -->
|
|
||||||
<div v-if="theme === 'off'" class="year-modern">
|
|
||||||
<div class="relative inline-flex items-center">
|
|
||||||
<select
|
|
||||||
class="appearance-none bg-transparent pr-5 pl-0 py-0.5 rounded-md wrapped-label text-xs text-[#00000066] text-right focus:outline-none focus-visible:ring-2 focus-visible:ring-[#07C160]/30 hover:bg-[#000000]/5 transition disabled:opacity-70 disabled:cursor-default"
|
|
||||||
:disabled="years.length <= 1"
|
|
||||||
:value="String(modelValue)"
|
|
||||||
@change="onSelectChange"
|
|
||||||
>
|
|
||||||
<option v-for="y in years" :key="y" :value="String(y)">{{ y }}年</option>
|
|
||||||
</select>
|
|
||||||
<svg
|
|
||||||
v-if="years.length > 1"
|
|
||||||
class="pointer-events-none absolute right-1 w-3 h-3 text-[#00000066]"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.23 7.21a.75.75 0 0 1 1.06.02L10 10.94l3.71-3.71a.75.75 0 1 1 1.06 1.06l-4.24 4.24a.75.75 0 0 1-1.06 0L5.21 8.29a.75.75 0 0 1 .02-1.08z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Game Boy 风格 -->
|
<!-- Game Boy 风格 -->
|
||||||
<div v-else-if="theme === 'gameboy'" class="year-gameboy">
|
<div v-if="theme === 'gameboy'" class="year-gameboy">
|
||||||
<div class="gameboy-year-box">
|
<div class="gameboy-year-box">
|
||||||
<button
|
<button
|
||||||
class="gameboy-arrow"
|
class="gameboy-arrow"
|
||||||
@@ -65,27 +38,31 @@
|
|||||||
>[+]</button>
|
>[+]</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- VHS 风格 -->
|
<!-- Modern 风格:下拉菜单(默认) -->
|
||||||
<div v-else-if="theme === 'vhs'" class="year-vhs">
|
<div v-else class="year-modern">
|
||||||
<button
|
<div class="relative inline-flex items-center">
|
||||||
class="vhs-transport-btn"
|
<select
|
||||||
:disabled="!canGoPrev"
|
class="appearance-none bg-transparent pr-5 pl-0 py-0.5 rounded-md wrapped-label text-xs text-[#00000066] text-right focus:outline-none focus-visible:ring-2 focus-visible:ring-[#07C160]/30 hover:bg-[#000000]/5 transition disabled:opacity-70 disabled:cursor-default"
|
||||||
@click="prevYear"
|
:disabled="years.length <= 1"
|
||||||
aria-label="Previous year"
|
:value="String(modelValue)"
|
||||||
>
|
@change="onSelectChange"
|
||||||
<span class="vhs-icon">◀◀</span>
|
>
|
||||||
</button>
|
<option v-for="y in years" :key="y" :value="String(y)">{{ y }}年</option>
|
||||||
<div class="vhs-led-display">
|
</select>
|
||||||
<span class="vhs-led-digit">{{ modelValue }}</span>
|
<svg
|
||||||
|
v-if="years.length > 1"
|
||||||
|
class="pointer-events-none absolute right-1 w-3 h-3 text-[#00000066]"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M5.23 7.21a.75.75 0 0 1 1.06.02L10 10.94l3.71-3.71a.75.75 0 1 1 1.06 1.06l-4.24 4.24a.75.75 0 0 1-1.06 0L5.21 8.29a.75.75 0 0 1 .02-1.08z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<button
|
|
||||||
class="vhs-transport-btn"
|
|
||||||
:disabled="!canGoNext"
|
|
||||||
@click="nextYear"
|
|
||||||
aria-label="Next year"
|
|
||||||
>
|
|
||||||
<span class="vhs-icon">▶▶</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -263,72 +240,4 @@ onBeforeUnmount(() => {
|
|||||||
min-width: 50px;
|
min-width: 50px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========== VHS 风格 ========== */
|
|
||||||
.year-vhs {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
padding: 6px 10px;
|
|
||||||
background: linear-gradient(180deg, #2a2a3e 0%, #1a1a2e 100%);
|
|
||||||
border-radius: 4px;
|
|
||||||
border: 1px solid #3a3a5e;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vhs-transport-btn {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 28px;
|
|
||||||
height: 22px;
|
|
||||||
background: linear-gradient(180deg, #4a4a5e 0%, #2a2a3e 50%, #3a3a4e 100%);
|
|
||||||
border: 1px solid #5a5a7e;
|
|
||||||
border-radius: 3px;
|
|
||||||
color: #cccccc;
|
|
||||||
font-size: 8px;
|
|
||||||
cursor: pointer;
|
|
||||||
box-shadow:
|
|
||||||
0 2px 0 #1a1a2e,
|
|
||||||
inset 0 1px 0 rgba(255,255,255,0.2);
|
|
||||||
transition: all 0.05s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vhs-transport-btn:hover:not(:disabled) {
|
|
||||||
background: linear-gradient(180deg, #5a5a6e 0%, #3a3a4e 50%, #4a4a5e 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vhs-transport-btn:active:not(:disabled) {
|
|
||||||
transform: translateY(2px);
|
|
||||||
box-shadow:
|
|
||||||
0 0 0 #1a1a2e,
|
|
||||||
inset 0 1px 2px rgba(0,0,0,0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vhs-transport-btn:disabled {
|
|
||||||
opacity: 0.3;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vhs-icon {
|
|
||||||
letter-spacing: -2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vhs-led-display {
|
|
||||||
background: #0a0a0a;
|
|
||||||
border: 1px solid #3a3a3a;
|
|
||||||
padding: 4px 10px;
|
|
||||||
border-radius: 2px;
|
|
||||||
box-shadow: inset 0 1px 3px rgba(0,0,0,0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vhs-led-digit {
|
|
||||||
font-family: 'Courier New', monospace;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #ff3333;
|
|
||||||
text-shadow:
|
|
||||||
0 0 4px #ff3333,
|
|
||||||
0 0 8px #ff3333;
|
|
||||||
letter-spacing: 2px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -391,19 +391,4 @@ watch(
|
|||||||
font-family: 'Courier New', monospace;
|
font-family: 'Courier New', monospace;
|
||||||
text-shadow: 0 0 3px rgba(51, 255, 51, 0.6);
|
text-shadow: 0 0 3px rgba(51, 255, 51, 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========== VHS 主题 ========== */
|
|
||||||
.wrapped-theme-vhs .wrapped-chat-replay {
|
|
||||||
--wr-chat-frame-bg: #16213e;
|
|
||||||
--wr-chat-top-bg: #0f3460;
|
|
||||||
--wr-chat-chat-bg: #1a1a2e;
|
|
||||||
--wr-chat-border: #0f3460;
|
|
||||||
|
|
||||||
--wr-chat-bubble-bg: linear-gradient(135deg, #e94560 0%, #0f3460 100%);
|
|
||||||
--wr-chat-bubble-tail: #0f3460;
|
|
||||||
--wr-chat-bubble-text: #ffffff;
|
|
||||||
|
|
||||||
--wr-chat-typing-bg: rgba(255, 255, 255, 0.08);
|
|
||||||
--wr-chat-typing-dot: rgba(255, 255, 255, 0.85);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -377,56 +377,4 @@ const labels = computed(() => {
|
|||||||
color: #33ff33 !important;
|
color: #33ff33 !important;
|
||||||
text-shadow: 0 0 5px #33ff33;
|
text-shadow: 0 0 5px #33ff33;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========== VHS 主题 ========== */
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .overview-card {
|
|
||||||
background: #16213e !important;
|
|
||||||
border: 1px solid #0f3460 !important;
|
|
||||||
backdrop-filter: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .overview-grid-line {
|
|
||||||
stroke: #0f3460;
|
|
||||||
stroke-opacity: 0.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .overview-axis-line {
|
|
||||||
stroke: #0f3460;
|
|
||||||
stroke-opacity: 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .overview-data-polygon {
|
|
||||||
fill: rgba(233, 69, 96, 0.2);
|
|
||||||
stroke: #e94560;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .overview-data-node {
|
|
||||||
fill: #e94560;
|
|
||||||
stroke: #16213e;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .overview-label {
|
|
||||||
fill: #a0a0a0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .overview-progress-bg {
|
|
||||||
background: #0f3460 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .overview-progress-fill {
|
|
||||||
background: linear-gradient(90deg, #e94560, #0f3460) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .wrapped-label,
|
|
||||||
.wrapped-theme-vhs .wrapped-body {
|
|
||||||
color: #a0a0a0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .wrapped-number {
|
|
||||||
color: #e94560 !important;
|
|
||||||
text-shadow:
|
|
||||||
-1px 0 rgba(0, 255, 247, 0.5),
|
|
||||||
1px 0 rgba(255, 0, 255, 0.5);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1321,218 +1321,6 @@ const getLabelStyle = (code) => {
|
|||||||
text-shadow: 0 0 5px #ff3333;
|
text-shadow: 0 0 5px #ff3333;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========== VHS 录像带主题 - 复古视频风格键盘 ========== */
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .keyboard-outer {
|
|
||||||
border-radius: 4px;
|
|
||||||
background: linear-gradient(180deg, #2a2a4e 0%, #1a1a2e 100%);
|
|
||||||
border: 2px solid #0f3460;
|
|
||||||
padding: 4px;
|
|
||||||
box-shadow:
|
|
||||||
0 4px 20px rgba(233, 69, 96, 0.2),
|
|
||||||
inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .keyboard-inner {
|
|
||||||
border-radius: 2px;
|
|
||||||
background: linear-gradient(180deg, #16213e 0%, #0f0f23 100%);
|
|
||||||
border: 1px solid #0f3460;
|
|
||||||
padding: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .keyboard-header {
|
|
||||||
border-bottom: 1px solid #0f3460;
|
|
||||||
padding-bottom: 6px;
|
|
||||||
margin-bottom: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .dot {
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
}
|
|
||||||
.wrapped-theme-vhs .dot-red {
|
|
||||||
background: #e94560;
|
|
||||||
box-shadow: 0 0 8px #e94560;
|
|
||||||
animation: vhs-dot-flicker 0.1s infinite;
|
|
||||||
}
|
|
||||||
.wrapped-theme-vhs .dot-yellow { background: #f39c12; box-shadow: 0 0 5px #f39c12; }
|
|
||||||
.wrapped-theme-vhs .dot-green { background: #27ae60; box-shadow: 0 0 5px #27ae60; }
|
|
||||||
|
|
||||||
@keyframes vhs-dot-flicker {
|
|
||||||
0%, 90%, 100% { opacity: 1; }
|
|
||||||
92% { opacity: 0.7; }
|
|
||||||
95% { opacity: 1; }
|
|
||||||
97% { opacity: 0.8; }
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .keyboard-stats,
|
|
||||||
.wrapped-theme-vhs .keyboard-hint {
|
|
||||||
font-family: 'Courier New', monospace;
|
|
||||||
color: #eaeaea;
|
|
||||||
text-shadow:
|
|
||||||
-1px 0 #00fff7,
|
|
||||||
1px 0 #ff00ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .keyboard-body {
|
|
||||||
border-radius: 2px;
|
|
||||||
background: #0a0a1a;
|
|
||||||
box-shadow: inset 0 2px 10px rgba(0, 0, 0, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .kb-key::before {
|
|
||||||
border-radius: 2px;
|
|
||||||
background: #1a1a2e;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .kb-key-top {
|
|
||||||
border-radius: 2px;
|
|
||||||
border: 1px solid #0f3460 !important;
|
|
||||||
background: linear-gradient(180deg, #2a2a4e 0%, #1a1a2e 100%) !important;
|
|
||||||
box-shadow:
|
|
||||||
inset 0 1px 0 rgba(255, 255, 255, 0.1),
|
|
||||||
0 2px 4px rgba(0, 0, 0, 0.3) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .kb-label {
|
|
||||||
font-family: 'Courier New', monospace;
|
|
||||||
color: #eaeaea !important;
|
|
||||||
text-shadow:
|
|
||||||
-1px 0 rgba(0, 255, 247, 0.5),
|
|
||||||
1px 0 rgba(255, 0, 255, 0.5);
|
|
||||||
filter: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .kb-sub {
|
|
||||||
font-family: 'Courier New', monospace;
|
|
||||||
color: #a0a0a0 !important;
|
|
||||||
filter: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .kb-space-bar {
|
|
||||||
border-radius: 2px;
|
|
||||||
background: linear-gradient(90deg, #e94560 0%, #0f3460 100%);
|
|
||||||
height: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .keyboard-brand {
|
|
||||||
font-family: 'Courier New', monospace;
|
|
||||||
color: #e94560;
|
|
||||||
text-shadow:
|
|
||||||
-1px 0 #00fff7,
|
|
||||||
1px 0 #ff00ff;
|
|
||||||
letter-spacing: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* VHS 磨损效果 - 色彩溢出增强 */
|
|
||||||
.wrapped-theme-vhs .kb-level-1 .kb-label,
|
|
||||||
.wrapped-theme-vhs .kb-level-2 .kb-label {
|
|
||||||
text-shadow:
|
|
||||||
-1px 0 rgba(0, 255, 247, 0.6),
|
|
||||||
1px 0 rgba(255, 0, 255, 0.6);
|
|
||||||
}
|
|
||||||
.wrapped-theme-vhs .kb-level-3 .kb-label,
|
|
||||||
.wrapped-theme-vhs .kb-level-4 .kb-label {
|
|
||||||
text-shadow:
|
|
||||||
-2px 0 rgba(0, 255, 247, 0.7),
|
|
||||||
2px 0 rgba(255, 0, 255, 0.7);
|
|
||||||
}
|
|
||||||
.wrapped-theme-vhs .kb-level-5 .kb-label,
|
|
||||||
.wrapped-theme-vhs .kb-level-6 .kb-label {
|
|
||||||
text-shadow:
|
|
||||||
-2px 0 rgba(0, 255, 247, 0.8),
|
|
||||||
2px 0 rgba(255, 0, 255, 0.8);
|
|
||||||
animation: vhs-text-glitch 3s infinite;
|
|
||||||
}
|
|
||||||
.wrapped-theme-vhs .kb-level-7 .kb-key-top,
|
|
||||||
.wrapped-theme-vhs .kb-level-8 .kb-key-top {
|
|
||||||
animation: vhs-key-glitch 2s infinite;
|
|
||||||
}
|
|
||||||
.wrapped-theme-vhs .kb-level-9 .kb-key-top {
|
|
||||||
animation: vhs-key-glitch 1s infinite;
|
|
||||||
border-color: #e94560 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes vhs-text-glitch {
|
|
||||||
0%, 95%, 100% { transform: translateX(0); }
|
|
||||||
96% { transform: translateX(-1px); }
|
|
||||||
97% { transform: translateX(1px); }
|
|
||||||
98% { transform: translateX(-1px); }
|
|
||||||
99% { transform: translateX(0); }
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes vhs-key-glitch {
|
|
||||||
0%, 92%, 100% {
|
|
||||||
transform: translate(0);
|
|
||||||
filter: none;
|
|
||||||
}
|
|
||||||
93% {
|
|
||||||
transform: translate(-1px, 0);
|
|
||||||
filter: hue-rotate(90deg);
|
|
||||||
}
|
|
||||||
95% {
|
|
||||||
transform: translate(1px, 0);
|
|
||||||
filter: hue-rotate(-90deg);
|
|
||||||
}
|
|
||||||
97% {
|
|
||||||
transform: translate(0, -1px);
|
|
||||||
filter: saturate(1.5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .kb-level-10 .kb-key-top {
|
|
||||||
opacity: 0 !important;
|
|
||||||
}
|
|
||||||
.wrapped-theme-vhs .kb-level-10::before {
|
|
||||||
background: linear-gradient(
|
|
||||||
45deg,
|
|
||||||
#1a1a2e 25%,
|
|
||||||
#0f3460 25%,
|
|
||||||
#0f3460 50%,
|
|
||||||
#1a1a2e 50%,
|
|
||||||
#1a1a2e 75%,
|
|
||||||
#0f3460 75%
|
|
||||||
) !important;
|
|
||||||
background-size: 4px 4px;
|
|
||||||
animation: vhs-static 0.5s infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes vhs-static {
|
|
||||||
0% { background-position: 0 0; }
|
|
||||||
100% { background-position: 4px 4px; }
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .kb-level-10::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
width: 6px;
|
|
||||||
height: 6px;
|
|
||||||
background: #e94560;
|
|
||||||
border-radius: 50%;
|
|
||||||
box-shadow: 0 0 10px #e94560;
|
|
||||||
animation: vhs-dot-flicker 0.2s infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* VHS 聊天气泡主题适配 */
|
|
||||||
.wrapped-theme-vhs .bubble-left,
|
|
||||||
.wrapped-theme-vhs .bubble-right {
|
|
||||||
background: #16213e;
|
|
||||||
border: 1px solid #0f3460;
|
|
||||||
}
|
|
||||||
.wrapped-theme-vhs .bubble-left::before {
|
|
||||||
border-right-color: #16213e;
|
|
||||||
}
|
|
||||||
.wrapped-theme-vhs .bubble-right {
|
|
||||||
background: linear-gradient(135deg, #e94560 0%, #0f3460 100%);
|
|
||||||
}
|
|
||||||
.wrapped-theme-vhs .bubble-right::after {
|
|
||||||
border-left-color: #0f3460;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* DOS 聊天气泡主题适配 */
|
/* DOS 聊天气泡主题适配 */
|
||||||
.wrapped-theme-dos .bubble-left,
|
.wrapped-theme-dos .bubble-left,
|
||||||
.wrapped-theme-dos .bubble-right {
|
.wrapped-theme-dos .bubble-right {
|
||||||
@@ -1560,12 +1348,6 @@ const getLabelStyle = (code) => {
|
|||||||
stroke: #33ff33;
|
stroke: #33ff33;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* VHS 头像适配 */
|
|
||||||
.wrapped-theme-vhs .avatar-box {
|
|
||||||
background: #16213e;
|
|
||||||
border-color: #0f3460;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========== Game Boy 主题 - 聊天气泡适配 ========== */
|
/* ========== Game Boy 主题 - 聊天气泡适配 ========== */
|
||||||
|
|
||||||
/* 聊天区域背景 */
|
/* 聊天区域背景 */
|
||||||
@@ -1655,28 +1437,4 @@ const getLabelStyle = (code) => {
|
|||||||
text-shadow: 0 0 3px #33ff33;
|
text-shadow: 0 0 3px #33ff33;
|
||||||
font-family: 'Courier New', monospace;
|
font-family: 'Courier New', monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========== VHS 主题 - 聊天气泡文字适配 ========== */
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .bubble-left .wrapped-label,
|
|
||||||
.wrapped-theme-vhs .bubble-right .wrapped-label {
|
|
||||||
color: #a0a0a0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .bubble-left .wrapped-number,
|
|
||||||
.wrapped-theme-vhs .bubble-right .wrapped-number {
|
|
||||||
color: #eaeaea !important;
|
|
||||||
text-shadow:
|
|
||||||
-1px 0 rgba(0, 255, 247, 0.5),
|
|
||||||
1px 0 rgba(255, 0, 255, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .bubble-left .wrapped-body,
|
|
||||||
.wrapped-theme-vhs .bubble-right .wrapped-body {
|
|
||||||
color: #a0a0a0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .avatar-box svg {
|
|
||||||
stroke: #e94560;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -157,18 +157,4 @@ const originFor = (weekdayIndex, hour) => {
|
|||||||
.wrapped-theme-dos .heatmap-legend-cell {
|
.wrapped-theme-dos .heatmap-legend-cell {
|
||||||
border-radius: 0 !important;
|
border-radius: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========== VHS 主题 ========== */
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .wrapped-label,
|
|
||||||
.wrapped-theme-vhs .wrapped-body {
|
|
||||||
color: #a0a0a0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapped-theme-vhs .wrapped-number {
|
|
||||||
color: #e94560 !important;
|
|
||||||
text-shadow:
|
|
||||||
-1px 0 rgba(0, 255, 247, 0.5),
|
|
||||||
1px 0 rgba(255, 0, 255, 0.5);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* 年度总结页面主题管理 composable
|
* 年度总结页面主题管理 composable
|
||||||
* 支持四种主题:modern(现代)、gameboy(Game Boy)、dos(DOS终端)、vhs(VHS录像带)
|
* 支持三种主题:modern(现代)、gameboy(Game Boy)、dos(DOS终端)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const STORAGE_KEY = 'wrapped-theme'
|
const STORAGE_KEY = 'wrapped-theme'
|
||||||
const VALID_THEMES = ['off', 'gameboy', 'dos', 'vhs']
|
const VALID_THEMES = ['off', 'gameboy', 'dos']
|
||||||
|
|
||||||
// 全局响应式状态(跨组件共享)
|
// 全局响应式状态(跨组件共享)
|
||||||
const theme = ref('off')
|
const theme = ref('off')
|
||||||
@@ -62,13 +62,12 @@ export function useWrappedTheme() {
|
|||||||
const names = {
|
const names = {
|
||||||
off: 'Modern',
|
off: 'Modern',
|
||||||
gameboy: 'Game Boy',
|
gameboy: 'Game Boy',
|
||||||
dos: 'DOS Terminal',
|
dos: 'DOS Terminal'
|
||||||
vhs: 'VHS Tape'
|
|
||||||
}
|
}
|
||||||
return names[theme.value] || 'Modern'
|
return names[theme.value] || 'Modern'
|
||||||
})
|
})
|
||||||
|
|
||||||
// 全局 F1-F4 快捷键切换主题(仅初始化一次)
|
// 全局 F1-F3 快捷键切换主题(仅初始化一次)
|
||||||
const initKeyboardShortcuts = () => {
|
const initKeyboardShortcuts = () => {
|
||||||
if (keyboardInitialized || !import.meta.client) return
|
if (keyboardInitialized || !import.meta.client) return
|
||||||
keyboardInitialized = true
|
keyboardInitialized = true
|
||||||
@@ -89,9 +88,6 @@ export function useWrappedTheme() {
|
|||||||
} else if (e.key === 'F3') {
|
} else if (e.key === 'F3') {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
setTheme('dos')
|
setTheme('dos')
|
||||||
} else if (e.key === 'F4') {
|
|
||||||
e.preventDefault()
|
|
||||||
setTheme('vhs')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -183,8 +183,8 @@ const year = ref(Number(route.query?.year) || new Date().getFullYear())
|
|||||||
// 分享视图不展示账号信息:默认让后端自动选择;需要指定时可用 query ?account=wxid_xxx
|
// 分享视图不展示账号信息:默认让后端自动选择;需要指定时可用 query ?account=wxid_xxx
|
||||||
const account = ref(typeof route.query?.account === 'string' ? route.query.account : '')
|
const account = ref(typeof route.query?.account === 'string' ? route.query.account : '')
|
||||||
|
|
||||||
// 主题管理:modern / gameboy / dos / vhs
|
// 主题管理:modern / gameboy / dos
|
||||||
const { theme, setTheme, cycleTheme, isRetro, themeClass } = useWrappedTheme()
|
const { theme, cycleTheme, isRetro, themeClass } = useWrappedTheme()
|
||||||
|
|
||||||
const accounts = ref([])
|
const accounts = ref([])
|
||||||
const accountsLoading = ref(true)
|
const accountsLoading = ref(true)
|
||||||
@@ -219,8 +219,7 @@ let navUnlockTimer = null
|
|||||||
const THEME_BG = {
|
const THEME_BG = {
|
||||||
off: '#F3FFF8', // Modern: 浅绿
|
off: '#F3FFF8', // Modern: 浅绿
|
||||||
gameboy: '#9bbc0f', // Game Boy: 亮绿
|
gameboy: '#9bbc0f', // Game Boy: 亮绿
|
||||||
dos: '#0a0a0a', // DOS: 黑色
|
dos: '#0a0a0a' // DOS: 黑色
|
||||||
vhs: '#0a0a14' // VHS: 深蓝黑
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const slides = computed(() => {
|
const slides = computed(() => {
|
||||||
|
|||||||
@@ -58,15 +58,6 @@ export const themedHeatColor = (value, max, theme) => {
|
|||||||
const light = 20 + 60 * t
|
const light = 20 + 60 * t
|
||||||
return `hsl(120 100% ${light.toFixed(1)}%)`
|
return `hsl(120 100% ${light.toFixed(1)}%)`
|
||||||
}
|
}
|
||||||
case 'vhs': {
|
|
||||||
// VHS: from dark blue to pink/magenta
|
|
||||||
if (t === 0) return 'rgba(15, 52, 96, 0.3)'
|
|
||||||
// Interpolate from #0f3460 (dark blue) to #e94560 (pink)
|
|
||||||
const r = Math.round(15 + (233 - 15) * t)
|
|
||||||
const g = Math.round(52 + (69 - 52) * t)
|
|
||||||
const b = Math.round(96 + (96 - 96) * t)
|
|
||||||
return `rgb(${r}, ${g}, ${b})`
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
// Modern (off) - use original heatColor
|
// Modern (off) - use original heatColor
|
||||||
return heatColor(value, max)
|
return heatColor(value, max)
|
||||||
@@ -79,4 +70,3 @@ export const formatHourRange = (hour) => {
|
|||||||
const hh = String(h).padStart(2, '0')
|
const hh = String(h).padStart(2, '0')
|
||||||
return `${hh}:00-${hh}:59`
|
return `${hh}:00-${hh}:59`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user