From cc48a02676f7ddb34b04a2e6cef1031e2b71bee3 Mon Sep 17 00:00:00 2001 From: rbetree Date: Sat, 24 Jan 2026 23:03:03 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=AF=B9=E5=8E=9F=E6=9C=AC?= =?UTF-8?q?=E7=9A=84=E8=BF=87=E9=95=BFstyle.css=E8=BF=9B=E8=A1=8C=E6=8B=86?= =?UTF-8?q?=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/README.md | 99 +- assets/style.css | 4337 +-------------------------------- assets/styles/_animations.css | 49 + assets/styles/_base.css | 238 ++ assets/styles/_cards.css | 1365 +++++++++++ assets/styles/_content.css | 216 ++ assets/styles/_dashboard.css | 371 +++ assets/styles/_layout.css | 101 + assets/styles/_main.css | 1448 +++++++++++ assets/styles/_modal.css | 152 ++ assets/styles/_search.css | 306 +++ assets/styles/_sidebar.css | 613 +++++ assets/styles/_variables.css | 147 ++ src/generator/main.js | 66 +- templates/README.md | 1 + 15 files changed, 5166 insertions(+), 4343 deletions(-) create mode 100644 assets/styles/_animations.css create mode 100644 assets/styles/_base.css create mode 100644 assets/styles/_cards.css create mode 100644 assets/styles/_content.css create mode 100644 assets/styles/_dashboard.css create mode 100644 assets/styles/_layout.css create mode 100644 assets/styles/_main.css create mode 100644 assets/styles/_modal.css create mode 100644 assets/styles/_search.css create mode 100644 assets/styles/_sidebar.css create mode 100644 assets/styles/_variables.css diff --git a/assets/README.md b/assets/README.md index 5113513..448b1df 100644 --- a/assets/README.md +++ b/assets/README.md @@ -4,7 +4,7 @@ - [目录概述](#目录概述) - [资源列表](#资源列表) -- [资源使用说明](#资源使用说明) +- [CSS 模块化架构](#css-模块化架构) - [添加新资源](#添加新资源) ## 目录概述 @@ -15,59 +15,84 @@ 目录包含以下主要资源: -- **style.css**: 网站的主样式表文件 - - 定义了网站的整体样式、布局和主题 - - 包含响应式设计和动画效果的实现 +- **style.css**: 样式入口文件 + - 通过 `@import` 聚合所有模块化 CSS + - 构建时由 esbuild 合并压缩为单文件 + +- **styles/**: CSS 模块目录(详见下方) - **menav.svg**: 网站图标和项目logo - 显示在浏览器标签页、书签和收藏夹中 - - 作为网站的标识符 - SVG格式,包含黑色字母"M"和蓝色向上箭头设计 -- **preview_light.png**: 明亮主题预览图 - - 用于README文档中展示网站明亮主题效果 - - 作为项目展示素材 +- **preview_light.png / preview_dark.png**: 主题预览图 + - 用于 README 文档展示 -- **preview_dark.png**: 暗黑主题预览图 - - 用于README文档中展示网站暗黑主题效果 - - 作为项目展示素材 +## CSS 模块化架构 -## 资源使用说明 +样式采用模块化组织,构建时自动合并: -### 样式表 +``` +assets/ +├── style.css # 入口文件(@import 聚合) +└── styles/ + ├── _variables.css # CSS 变量、主题色 + ├── _base.css # 全局重置、滚动条 + ├── _animations.css # @keyframes 动画 + ├── _layout.css # 页面容器布局 + ├── _sidebar.css # 侧边栏组件 + ├── _search.css # 搜索框组件 + ├── _cards.css # 卡片组件(站点卡片、tooltip) + ├── _modal.css # 模态框、表单 + ├── _content.css # Markdown 内容页 + ├── _dashboard.css # 仪表盘(时钟/Todo) + └── _main.css # 兜底样式(分类、热力图、响应式) +``` -`style.css` 文件包含网站的所有样式定义,遵循以下组织结构: +### 模块说明 -- 基础样式 - 通用元素样式定义 -- 布局样式 - 页面结构和布局定义 -- 组件样式 - 特定UI组件的样式定义 -- 响应式样式 - 适配不同设备屏幕的媒体查询 -- 主题样式 - 明亮和暗黑主题的颜色方案 +| 模块 | 职责 | +|------|------| +| `_variables.css` | CSS 变量、深色/浅色主题、间距/圆角系统 | +| `_base.css` | 全局重置、滚动条、遮罩层、主题切换按钮 | +| `_animations.css` | 所有 `@keyframes` 定义 | +| `_layout.css` | 页面容器、欢迎区域、模板布局 | +| `_sidebar.css` | 侧边栏、导航项、折叠状态、子菜单 | +| `_search.css` | 搜索框、引擎下拉、快捷键提示 | +| `_cards.css` | 站点卡片、网格布局、tooltip、编辑按钮 | +| `_modal.css` | 模态框、表单控件、按钮样式 | +| `_content.css` | Markdown 渲染(标题、代码块、表格等) | +| `_dashboard.css` | 仪表盘网格、时钟卡片、Todo 列表 | +| `_main.css` | 分类层级、GitHub 热力图、全局响应式 | -样式表支持主题切换功能,通过CSS变量实现不同主题下的颜色变换。 +### 构建流程 -### 图标与图片 +构建时 esbuild 会: +1. 解析 `style.css` 中的 `@import` 语句 +2. 合并所有模块为单文件 +3. 压缩输出到 `dist/style.css` -- 网站图标 (`menav.svg`) 自动应用于生成的网站 -- 预览图片用于项目文档和宣传 +> **开发提示**:修改 CSS 后运行 `npm run build` 或 `npm run dev` 查看效果。 ## 添加新资源 -向资源目录添加新文件时,请遵循以下指南: +### 文件命名规范 -1. **文件命名**: - - 使用小写字母和连字符 (`-`) - - 避免使用空格和特殊字符 - - 名称应清晰表达文件用途 +- 使用小写字母和连字符 (`-`) +- 避免使用空格和特殊字符 +- 名称应清晰表达文件用途 -2. **图片优化**: - - 压缩图片以减小文件大小 - - 使用适合web的格式 (PNG, JPG, WebP) - - 考虑添加合适的分辨率版本 +### CSS 扩展指南 -3. **样式扩展**: - - 新的样式应该添加到 `style.css` 的合适部分 - - 遵循现有的命名规范和组织结构 - - 确保添加响应式设计支持 +1. **找到合适的模块**:根据功能选择对应的 `_*.css` 文件 +2. **遵循命名规范**:使用 BEM 风格或现有选择器模式 +3. **添加响应式支持**:在同一模块内添加 `@media` 查询 +4. **变量优先**:优先使用 `_variables.css` 中定义的变量 -添加新资源后,构建系统会自动将这些文件复制到生成的网站中。 \ No newline at end of file +### 图片优化 + +- 压缩图片以减小文件大小 +- 使用 PNG、JPG、WebP 等 web 友好格式 +- 考虑添加合适的分辨率版本 + +添加新资源后,构建系统会自动将这些文件复制到生成的网站中。 \ No newline at end of file diff --git a/assets/style.css b/assets/style.css index f188811..28fcc1e 100644 --- a/assets/style.css +++ b/assets/style.css @@ -1,4304 +1,33 @@ -/* 主题颜色变量 - Apple Design System */ -:root { - /* 深色主题 (iOS Dark Mode Inspired) */ - --bg-color: #000000; - /* Pure Black background */ - --sidebar-bg: #1c1c1e; - /* System Gray 6 */ - --secondary-bg: #2c2c2e; - /* System Gray 5 */ - - /* 卡片背景 - 仪表盘卡片 */ - --card-bg-gradient-1: #1c1c1e; - --card-bg-gradient-2: #1c1c1e; - - /* 站点卡片 - 提升亮度以区分层级 (Optimize: Use System Gray 5 for cards on black bg) */ - --site-card-bg-gradient-1: #2c2c2e; - --site-card-bg-gradient-2: #2c2c2e; - --site-card-hover-bg: #3a3a3c; - /* System Gray 4 for hover */ - - /* 文字颜色 */ - --text-color: #ffffff; - --text-muted: #8e8e93; - /* System Gray */ - --text-bright: #ffffff; - - /* 边框与阴影 */ - --border-color: rgba(255, 255, 255, 0.12); - --shadow-color: rgba(0, 0, 0, 0.3); - - /* 功能色 */ - --highlight-bg: rgba(118, 148, 185, 0.3); - /* Restore original Highlight */ - --scrollbar-color: rgba(255, 255, 255, 0.2); - --scrollbar-hover-color: rgba(255, 255, 255, 0.3); - - /* 恢复原有强调色 (Restore Original Accent) */ - --accent-color: #7694b9; - --accent-hover: #6684a9; - --accent-rgb: 118, 148, 185; - - --nav-item-color: #98989d; - --success-color: #30d158; - --error-color: #ff453a; - --white-color: #ffffff; - - /* 恢复原有渐变 (Restore Original Gradient) */ - --gradient-color: linear-gradient(135deg, #7694b9 0%, #a855f7 50%, #ff6b6b 100%); - --gradient-color-simple: linear-gradient(135deg, #7694b9 0%, #a855f7 100%); - - --sidebar-width: 240px; - --sidebar-collapsed-width: 60px; - --app-height: 100vh; - - /* Spacing System */ - --spacing-xs: 0.25rem; - --spacing-sm: 0.5rem; - --spacing-md: 1rem; - --spacing-lg: 1.5rem; - --spacing-xl: 2rem; - --spacing-2xl: 3rem; - - --page-max-width: 1300px; - - /* UI Tuning - Apple Style (Kept) */ - --radius-sm: 6px; - --radius-md: 10px; - --radius-lg: 14px; - --radius-xl: 20px; - --radius-full: 9999px; - - /* Transitions - Kept iOS Spring */ - --transition-fast: 0.2s ease; - --transition-normal: 0.35s cubic-bezier(0.25, 1, 0.5, 1); - --transition-slow: 0.5s cubic-bezier(0.25, 1, 0.5, 1); - --transition-bounce: cubic-bezier(0.175, 0.885, 0.32, 1.275); - - --card-bg-rgb: 28, 28, 30; -} - -/* 浅色主题 - 恢复原有配色 (Restored Morandi/Warm) */ -html.theme-preload, -body.light-theme { - --bg-color: #e0e0d8; - --sidebar-bg: #f0f0eb; - --secondary-bg: #e6e6e1; - /* Slightly darker than sidebar for hover state */ - --card-bg-gradient-1: #f0f0eb; - --card-bg-gradient-2: #e9e9e4; - --site-card-bg-gradient-1: #ffffff; - --site-card-bg-gradient-2: #f4f5f0; - --site-card-hover-bg: linear-gradient(145deg, #fafaf8, #eef0eb); - - --text-color: #333333; - --text-muted: #666666; - --text-bright: #000000; - - --border-color: rgba(0, 0, 0, 0.08); - --shadow-color: rgba(0, 0, 0, 0.1); - - --highlight-bg: rgba(118, 148, 185, 0.15); - --scrollbar-color: rgba(0, 0, 0, 0.1); - --scrollbar-hover-color: rgba(0, 0, 0, 0.2); - - --accent-color: #7694b9; - --accent-hover: #6684a9; - --accent-rgb: 118, 148, 185; - - --nav-item-color: #666666; - --success-color: #4caf50; - --error-color: #f44336; - --white-color: #ffffff; - - /* Restore original gradients */ - --gradient-color: linear-gradient(135deg, #7694b9 0%, #a855f7 50%, #ff6b6b 100%); - --gradient-color-simple: linear-gradient(135deg, #7694b9 0%, #a855f7 100%); - - --card-bg-rgb: 240, 240, 235; -} - -/* 预加载主题 - 在JS完全加载前显示正确的主题 */ -html.theme-preload body { - background-color: #e0e0d8; - color: #333333; -} - -/* 预加载侧边栏状态 - 在JS完全加载前显示正确的侧边栏宽度 */ -html.sidebar-collapsed-preload .sidebar { - width: var(--sidebar-collapsed-width); -} - -html.sidebar-collapsed-preload main.content { - margin-left: var(--sidebar-collapsed-width); -} - -/* 控制页面预加载状态 */ -html.preload .layout { - opacity: 0; -} - -html.preload * { - transition: none !important; -} - -/* 可访问性:视觉隐藏但保留屏幕阅读器可读 */ -.visually-hidden { - position: absolute !important; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border: 0; -} - -/* 主题切换按钮 - 调整为 iOS 风格 */ -.theme-toggle { - position: fixed; - bottom: var(--spacing-xl); - right: var(--spacing-xl); - width: 2.5rem; - height: 2.5rem; - border-radius: var(--radius-lg); - background: rgba(var(--card-bg-rgb), 0.65); - border: 1px solid var(--border-color); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); - color: var(--text-color); - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - transition: all var(--transition-normal); - transition-timing-function: var(--transition-bounce); - z-index: 100; - box-shadow: 0 4px 16px var(--shadow-color); -} - -.theme-toggle:hover { - transform: translateY(-2px); - background: rgba(var(--card-bg-rgb), 0.75); - box-shadow: 0 6px 20px var(--shadow-color); - color: var(--accent-color); -} - -.theme-toggle:active { - transform: translateY(0); - box-shadow: 0 2px 8px var(--shadow-color); -} - -.theme-toggle i { - font-size: 18px; -} - -/* 全局样式 */ -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -/* 全局 Focus Visible 样式 */ -:focus-visible { - outline: 2px solid var(--accent-color); - outline-offset: 2px; -} - -/* 导航项 Focus 样式 */ -.nav-item:focus-visible, -.submenu-item:focus-visible, -.site-card:focus-visible, -.theme-toggle:focus-visible, -.category-toggle:focus-visible, -.menu-toggle:focus-visible, -.search-toggle:focus-visible { - outline: 2px solid var(--accent-color); - outline-offset: 2px; - z-index: 10; -} - -/* 通用滚动条样式 */ -.custom-scrollbar { - scrollbar-width: thin; - /* Firefox */ - scrollbar-color: var(--scrollbar-color) transparent; - /* Firefox */ -} - -/* Webkit滚动条样式(Chrome, Safari, Edge等) */ -.custom-scrollbar::-webkit-scrollbar { - width: 7px; - /* 统一滚动条宽度 */ -} - -.custom-scrollbar::-webkit-scrollbar-track { - background: transparent; -} - -.custom-scrollbar::-webkit-scrollbar-thumb { - background-color: var(--scrollbar-color); - /* 使用变量 */ - border-radius: 4px; -} - -.custom-scrollbar::-webkit-scrollbar-thumb:hover { - background-color: var(--scrollbar-hover-color); - /* 使用变量 */ -} - -/* 防止滚动条导致的布局偏移 */ -html { - overflow-y: hidden; - /* 改为hidden,移除强制显示的滚动条 */ - scrollbar-width: thin; - /* Firefox */ - /* 明确 rem 基准字号:便于用 rem 统一管理字号(1rem = 16px) */ - font-size: 16px; -} - -/* 搜索高亮样式 */ -.highlight { - background-color: var(--highlight-bg); - border-radius: var(--radius-sm); - padding: 0 2px; - font-weight: bold; - color: var(--text-color); -} - -body { - font-family: var( - --font-body, - system-ui, - -apple-system, - 'Segoe UI', - Roboto, - 'Noto Sans', - 'Helvetica Neue', - Arial, - sans-serif - ); - font-weight: var(--font-weight-body, normal); - line-height: 1.6; - background-color: var(--bg-color); - color: var(--text-color); - min-height: var(--app-height, 100vh); - overflow: hidden; - /* 防止body滚动 */ - padding-right: 0 !important; - /* 防止滚动条导致的布局偏移 */ - transition: - background-color 0.3s ease, - color 0.3s ease; -} - -/* 布局 */ -.layout { - display: flex; - min-height: var(--app-height, 100vh); - position: relative; - z-index: 1; - overflow: hidden; - /* 防止layout滚动 */ - opacity: 0; - transition: opacity 0.3s ease; -} - -/* 确保加载后立即显示 */ -body.loaded .layout { - opacity: 1; -} - -/* 移动端基础样式 */ -.mobile-buttons { - display: none; - position: fixed; - top: var(--spacing-md); - top: calc(env(safe-area-inset-top) + var(--spacing-md)); - left: 0; - right: 0; - width: 100%; - padding: 0 var(--spacing-md); - padding-left: calc(env(safe-area-inset-left) + var(--spacing-md)); - padding-right: calc(env(safe-area-inset-right) + var(--spacing-md)); - justify-content: space-between; - z-index: 910; - pointer-events: none; -} - -.menu-toggle, -.search-toggle { - background: var(--sidebar-bg); - border: none; - color: var(--text-color); - width: 2.5rem; - height: 2.5rem; - border-radius: var(--radius-md); - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - transition: all 0.25s var(--transition-bounce); - box-shadow: 0 2px 8px var(--shadow-color); - pointer-events: auto; -} - -.menu-toggle:hover, -.search-toggle:hover { - background: var(--secondary-bg); - transform: translateY(-2px); - box-shadow: 0 4px 12px var(--shadow-color); -} - -.menu-toggle:active, -.search-toggle:active { - transform: translateY(0); -} - -/* 遮罩层 */ -.overlay { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: rgba(0, 0, 0, 0.5); - opacity: 0; - visibility: hidden; - transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); - z-index: 950; - /* 调整遮罩层z-index,处于按钮与弹出面板之间 */ -} - -.overlay.active { - opacity: 1; - visibility: visible; -} - -/* 侧边栏样式 */ -.sidebar { - width: var(--sidebar-width); - background-color: var(--sidebar-bg); - position: fixed; - top: 0; - left: 0; - bottom: 0; - box-shadow: 2px 0 10px var(--shadow-color); - z-index: 100; - -webkit-backface-visibility: hidden; - backface-visibility: hidden; - transform: translateZ(0); - height: var(--app-height, 100vh); - display: grid; - grid-template-rows: auto 1fr auto auto; - grid-template-areas: - 'header' - 'content' - 'social' - 'footer'; - scrollbar-width: thin; - scrollbar-color: var(--scrollbar-color) transparent; - overflow-y: hidden; - transition: background-color var(--transition-normal); -} - -/* 侧边栏折叠状态 */ -.sidebar.collapsed { - width: var(--sidebar-collapsed-width); - overflow-x: hidden; -} - -/* 优化侧边栏折叠时的Logo部分 */ -.sidebar.collapsed .logo { - padding: 1.2rem 0.5rem 0.6rem; - justify-content: center; - display: flex; - align-items: center; - height: 3.75rem; - /* 确保与展开状态高度一致 */ - margin-bottom: 0.8rem; - /* 收起态同样拉开与按钮的间距 */ -} - -/* 调整折叠侧边栏的部分元素间距 */ -.sidebar.collapsed .nav-section { - gap: 2px; -} - -/* 折叠状态下隐藏底部版权区域(不占位) */ -.sidebar.collapsed .sidebar-footer { - padding: 0; - height: 0; - min-height: 0; - margin: 0; - overflow: hidden; - border: none; -} - -/* 侧边栏头部区域 */ -.sidebar .logo { - grid-area: header; - padding: 1.2rem 1.2rem 0.6rem; - /* 调整上下padding更紧凑 */ - display: flex; - align-items: center; - overflow: hidden; - /* 防止内容溢出 */ - position: relative; - /* 添加相对定位,作为按钮的参考 */ - height: 3.75rem; - /* 固定高度 60px */ - margin-bottom: 0.8rem; - /* 与下方按钮区域拉开间距 */ - transition: padding 0.3s ease; - /* 添加padding过渡,避免突变 */ -} - -.logo-brand { - display: flex; - align-items: center; - gap: 0.6rem; - min-width: 0; - flex: 1; - padding-right: 2.2rem; - /* 预留右侧折叠按钮空间 */ -} - -.logo-brand h1 { - padding-left: 0; -} - -.logo-image { - width: 26px; - height: 26px; - flex-shrink: 0; -} - -.sidebar.collapsed .logo-image { - display: none; -} - -.logo h1 { - font-size: 1.4rem; - color: var(--text-bright); - margin-bottom: 0; - padding-left: 0.5rem; - letter-spacing: 0.5px; - transition: - opacity 0.3s ease, - transform 0.3s ease; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - flex: 1; -} - -/* 侧边栏折叠按钮 */ -.sidebar-toggle { - background: transparent; - border: none; - color: var(--accent-color); - height: 28px; - width: 28px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - transition: background 0.3s ease; - /* 只过渡背景色,移除all避免位置过渡 */ - padding: 0; - flex-shrink: 0; - /* 防止按钮被压缩 */ - position: absolute; - /* 在两种状态下都使用绝对定位 */ - right: 1.2rem; - /* 展开状态下固定在右侧 */ - top: 60%; - transform: translateY(-50%); - /* 垂直居中 */ -} - -.sidebar-toggle .toggle-icon { - font-size: 0.9rem; - transition: transform 0.3s ease; - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 100%; -} - -.sidebar-toggle:hover { - background: var(--secondary-bg); -} - -.sidebar-toggle:active { - background: var(--secondary-bg); -} - -/* 收起状态下按钮居中 */ -.sidebar.collapsed .sidebar-toggle { - left: 50%; - /* 水平居中 */ - right: auto; - /* 移除右侧定位 */ - transform: translate(-50%, -50%); - /* 同时水平和垂直居中 */ -} - -.sidebar.collapsed .sidebar-toggle:hover { - background: var(--secondary-bg); -} - -.sidebar.collapsed .sidebar-toggle:active { - background: var(--secondary-bg); -} - -/* 侧边栏折叠状态下的按钮图标旋转180度 */ -.sidebar.collapsed .toggle-icon { - transform: rotate(180deg); -} - -/* 侧边栏内容区域:导航项常驻显示,分类列表在独立面板内滚动 */ -.sidebar-content { - grid-area: content; - min-height: 0; - /* 允许在 CSS Grid 内正确收缩与滚动,避免把 footer 挤出可视区域 */ - overflow: hidden; - /* 导航项常驻显示,分类列表在独立面板内滚动 */ - padding: 0 1.2rem; - display: flex; - flex-direction: column; - gap: 0.6rem; - /* 从1rem减小到0.6rem */ -} - -.sidebar-content::-webkit-scrollbar { - display: none; - /* Webkit browsers(默认不滚动,保留兼容) */ -} - -/* 展开态:子菜单不在导航项内部展开,改在独立面板展示(避免把“页面列表”挤出首屏) */ -.sidebar:not(.collapsed) .nav-item-wrapper > .submenu { - display: none; -} - -/* 侧边栏:页面分类面板(容器本身可滚动,隐藏滚动条) */ -.sidebar-submenu-panel { - flex: 1 1 auto; - min-height: 0; - overflow-y: auto; - padding: 0 0 0.6rem; - /* 移除顶部 padding,避免标题上方出现缝隙 */ - scrollbar-width: none; - /* Firefox 隐藏滚动条 */ -} - -.sidebar-submenu-panel:empty { - display: none; -} - -.sidebar-submenu-panel::-webkit-scrollbar { - display: none; - /* Webkit 浏览器隐藏滚动条 */ -} - -/* 面板内的 submenu 始终可见(不依赖 wrapper.expanded) */ -.sidebar-submenu-panel .submenu { - max-height: none; - overflow: visible; - opacity: 1; - visibility: visible; - margin-left: 0; - transition: none; -} - -/* 折叠状态下的内容区域调整 */ -.sidebar.collapsed .sidebar-content { - padding: 0 0.5rem; - overflow-y: auto; - overflow-x: hidden; - scrollbar-width: none; - /* 隐藏滚动条 */ -} - -.sidebar.collapsed .sidebar-content::-webkit-scrollbar { - display: none; - /* 隐藏WebKit浏览器的滚动条 */ -} - -.sidebar.collapsed .sidebar-submenu-panel { - display: none; -} - -/* 子菜单标题:默认隐藏(在导航栏内折叠时) */ -.submenu-header { - display: none; - font-size: 0.85rem; - font-weight: 500; - text-transform: uppercase; - color: var(--text-muted); - letter-spacing: 0.5px; - padding: 0.8rem 1rem 0.6rem; - margin-bottom: 0.2rem; - border-bottom: 1px solid var(--border-color); - transition: - color var(--transition-normal), - background-color var(--transition-normal), - border-bottom-color var(--transition-normal); - opacity: 0.8; -} - -/* 当子菜单在面板中显示时:显示标题并固定在顶部 */ -.sidebar-submenu-panel .submenu-header { - display: block; - position: sticky; - top: 0; - margin-top: 0; - margin-bottom: 0.2rem; - /* 覆盖基础样式的 margin-bottom */ - background-color: var(--sidebar-bg); - opacity: 1; - /* 覆盖基础样式的半透明,确保背景完全不透明 */ - z-index: 1; - /* 确保标题在滚动时覆盖下方内容 */ -} - -/* 子菜单项样式优化 */ -.submenu-item { - display: flex; - align-items: center; - gap: 0.8rem; - padding: 0.6rem 1rem; - color: var(--nav-item-color); - text-decoration: none; - border-radius: var(--radius-md); - transition: all var(--transition-normal); - margin-bottom: 2px; - font-size: 0.95rem; - position: relative; - overflow: hidden; -} - -.submenu-item i { - width: 1.4rem; - text-align: center; - font-size: 1rem; - opacity: 0.8; - transition: transform var(--transition-normal); -} - -.submenu-item span { - flex: 1; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -/* 悬浮状态 */ -.submenu-item:hover { - background-color: var(--secondary-bg); - color: var(--text-bright); - padding-left: 1.2rem; - /* 悬浮时轻微右移增加动感 */ -} - -.submenu-item:hover i { - transform: scale(1.1); - color: var(--accent-color); - opacity: 1; -} - -/* 激活状态 */ -.submenu-item.active { - background-color: rgba(var(--accent-rgb), 0.15); - color: var(--accent-color); - font-weight: 500; -} - -.submenu-item.active i { - color: var(--accent-color); - opacity: 1; -} - -/* 在激活状态左侧添加指示条 */ -.submenu-item.active::before { - content: ''; - position: absolute; - left: 0; - top: 50%; - transform: translateY(-50%); - height: 60%; - width: 3px; - background-color: var(--accent-color); - border-radius: 0 2px 2px 0; -} - -/* 折叠状态下的Logo文本 */ -.sidebar.collapsed .logo h1 { - opacity: 0; - transform: translateX(-20px); - width: 0; - visibility: hidden; - /* 确保完全隐藏,防止干扰布局 */ - pointer-events: none; - /* 禁用交互,避免影响布局 */ -} - -/* 导航区域样式 */ -.nav-section { - display: flex; - flex-direction: column; - gap: 0; - /* wrapper 之间不需要 gap,由 nav-item 的 margin 控制 */ - flex: 0 0 auto; - /* 不伸缩,根据内容大小 */ - overflow: visible; - /* 导航项不滚动,保持常驻显示 */ -} - -.section-title { - font-size: 1rem; - color: var(--accent-color); - padding: 0.4rem 0.5rem; - /* 减小上下padding */ - margin-bottom: 0.2rem; - /* 增大与下方按钮组的间距 */ - display: flex; - align-items: center; - gap: 0.5rem; - transition: color 0.3s ease; -} - -.section-title i { - font-size: 1.2rem; -} - -/* 调整侧边栏折叠状态下的章节标题 */ -.sidebar.collapsed .section-title { - justify-content: center; - /* 统一与展开态的垂直间距 */ - padding: 0.4rem 0; - text-align: center; - margin-bottom: 0.2rem; - /* 与展开态保持一致且更大 */ -} - -.sidebar.collapsed .section-title i { - margin: 0 auto; - font-size: 1.2rem; -} - -/* 折叠状态下的导航项布局优化 */ -.sidebar.collapsed .nav-section { - gap: 0.4rem; - align-items: center; -} - -.sidebar.collapsed .nav-item { - padding: 0; - justify-content: center; - width: 2.75rem; - /* 增大按钮方块尺寸 44px */ - height: 2.75rem; - /* 增大按钮方块尺寸 44px */ - text-align: center; - margin-left: auto; - margin-right: auto; - border-radius: var(--radius-md); - /* 略增圆角 */ - display: flex; - align-items: center; - box-sizing: border-box; -} - -.sidebar.collapsed .nav-item i { - font-size: 1.25rem; - width: auto; - margin: 0; - padding: 0; -} - -.sidebar.collapsed .nav-item .icon-container { - margin: 0; - width: 100%; - height: 100%; - display: flex; - justify-content: center; - align-items: center; -} - -/* 折叠状态下的导航项文本 */ -.sidebar.collapsed .nav-item .nav-text, -.sidebar.collapsed .nav-item .external-icon { - opacity: 0; - transform: translateX(-10px); - width: 0; - display: none; - /* 完全移除,防止干扰布局 */ - visibility: hidden; -} - -.nav-item { - display: flex; - align-items: center; - height: 44px; - padding: 0 0.9rem; - margin-bottom: 0.4rem; - /* 导航按钮之间的间距 */ - color: var(--nav-item-color); - text-decoration: none; - border-radius: var(--radius-md); - transition: - background-color var(--transition-normal), - color var(--transition-normal), - box-shadow var(--transition-normal); - position: relative; -} - -.nav-item-wrapper:last-child .nav-item { - margin-bottom: 0; - /* 最后一个导航按钮不需要底部间距 */ -} - -.nav-item .icon-container { - width: 24px; - height: 100%; - display: flex; - justify-content: center; - align-items: center; - margin-right: var(--spacing-md); - transition: margin var(--transition-normal); -} - -.nav-item .nav-text { - flex: 1; - transition: - opacity var(--transition-normal), - transform var(--transition-normal); - white-space: nowrap; - overflow: hidden; -} - -.nav-item .external-icon { - font-size: 0.9rem; - opacity: 0.6; - margin-left: 0.5rem; - transition: all var(--transition-normal); -} - -.nav-item:hover { - background-color: var(--secondary-bg); - color: var(--text-bright); -} - -.nav-item:hover .external-icon { - opacity: 1; - transform: translateX(2px); -} - -.nav-item.active { - background-color: var(--secondary-bg); - color: var(--text-bright); -} - -.nav-item i { - width: 20px; - text-align: center; -} - -.nav-item i { - width: 20px; - text-align: center; -} - -.nav-item i { - width: 20px; - text-align: center; -} - -/* 折叠状态下:底部区域不可见且不可交互 */ -.sidebar.collapsed .sidebar-footer { - visibility: hidden; - pointer-events: none; -} - -/* 主内容区域 - 修复滚动条问题 */ -main.content { - flex: 1; - margin-left: var(--sidebar-width); - padding: 1.5rem 1rem; - background-color: var(--bg-color); - position: relative; - height: var(--app-height, 100vh); - /* 固定高度(移动端避免 100vh 问题) */ - overflow-y: auto; - /* 使用auto替代scroll,只在需要时显示滚动条 */ - overflow-x: hidden; - width: calc(100vw - var(--sidebar-width)); - display: flex; - flex-direction: column; - align-items: center; - /* 防止“有无滚动条”导致内容横向平移(支持的浏览器会稳定预留滚动条槽位) */ - scrollbar-gutter: stable; - /* 自定义滚动条颜色(Firefox) */ - scrollbar-width: thin; - scrollbar-color: var(--scrollbar-color) transparent; -} - -/* 自定义滚动条(Chromium / Safari) */ -main.content::-webkit-scrollbar { - width: 8px; -} - -main.content::-webkit-scrollbar-track { - background: transparent; -} - -main.content::-webkit-scrollbar-thumb { - background-color: var(--scrollbar-color); - border-radius: var(--radius-full); - /* 用透明边框制造“内边距”,更贴合卡片阴影风格 */ - border: 2px solid transparent; - background-clip: content-box; -} - -main.content::-webkit-scrollbar-thumb:hover { - background-color: var(--scrollbar-hover-color); -} - -/* 回退:不支持 scrollbar-gutter 的浏览器,强制始终显示滚动条以避免横向抖动 */ -@supports not (scrollbar-gutter: stable) { - main.content { - overflow-y: scroll; - } -} - -/* 优化内容区域在侧边栏折叠状态下的边距 */ -body main.content.expanded { - margin-left: var(--sidebar-collapsed-width); - width: calc(100vw - var(--sidebar-collapsed-width)); -} - -/* 仅在交互时启用布局相关过渡,避免首帧闪烁 */ -.with-anim .sidebar { - transition: - width 0.3s ease, - background-color 0.3s ease; -} - -.with-anim main.content { - transition: - background-color 0.3s ease, - margin-left 0.3s ease, - width 0.3s ease; -} - -/* 搜索框容器 - 固定在顶部 */ -.search-container { - width: 100%; - display: flex; - justify-content: center; - padding: 0 2rem; - margin-bottom: 1rem; - position: sticky; - top: 0; - /* 搜索框必须始终位于页面内容之上,避免搜索结果卡片滚动时遮挡 */ - z-index: 200; -} - -/* 分类切换按钮 */ -.category-toggle { - position: fixed; - bottom: 5rem; - right: var(--spacing-xl); - width: 2.5rem; - height: 2.5rem; - border-radius: var(--radius-lg); - background: rgba(var(--card-bg-rgb), 0.65); - border: 1px solid var(--border-color); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); - color: var(--text-color); - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - transition: all var(--transition-normal); - transition-timing-function: var(--transition-bounce); - z-index: 100; - box-shadow: 0 4px 16px var(--shadow-color); -} - -.category-toggle:hover { - transform: translateY(-2px); - background: rgba(var(--card-bg-rgb), 0.75); - box-shadow: 0 6px 20px var(--shadow-color); - color: var(--accent-color); -} - -.category-toggle:active { - transform: translateY(0); - box-shadow: 0 2px 8px var(--shadow-color); -} - -.category-toggle i { - font-size: 18px; -} - -/* 搜索框 */ -.search-box { - position: relative; - width: 100%; - max-width: 600px; - display: flex; - align-items: stretch; - --search-status-right: 0.9rem; - --search-hint-right: 1.6rem; - background: rgba(var(--card-bg-rgb), 0.65); - border: 1px solid var(--border-color); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); - border-radius: var(--radius-lg); - box-shadow: 0 4px 16px var(--shadow-color); - transition: - background var(--transition-normal), - border-color var(--transition-normal), - box-shadow var(--transition-normal); -} - -.search-box:focus-within { - border-color: rgba(var(--accent-rgb), 0.55); - box-shadow: - 0 0 0 1px rgba(var(--accent-rgb), 0.28), - 0 0 18px rgba(var(--accent-rgb), 0.18), - 0 6px 24px var(--shadow-color); -} - -.search-box::after { - content: ''; - position: absolute; - right: var(--search-status-right); - top: 50%; - transform: translateY(-50%); - width: 6px; - height: 6px; - border-radius: 50%; - opacity: 0; - transition: all var(--transition-normal); - pointer-events: none; -} - -.search-box.has-results::after { - background-color: var(--success-color); - opacity: 1; -} - -.search-box.no-results::after { - background-color: var(--error-color); - opacity: 1; -} - -.search-box input { - flex: 1; - min-width: 0; - width: 100%; - padding: var(--spacing-md) calc(var(--spacing-lg) + 4.8rem) var(--spacing-md) var(--spacing-md); - border: none; - border-radius: 0 var(--radius-lg) var(--radius-lg) 0; - background-color: transparent; - color: var(--text-color); - font-family: inherit; - font-weight: inherit; - font-size: 1rem; - transition: - background-color var(--transition-normal), - color var(--transition-normal); - box-shadow: none; -} - -.search-box input:focus { - outline: none; - background-color: rgba(var(--card-bg-rgb), 0.25); - box-shadow: none; -} - -.search-box input::placeholder { - color: var(--text-muted); - font-family: inherit; - font-weight: inherit; -} - -.search-shortcut-hint { - position: absolute; - top: 50%; - right: var(--search-hint-right); - transform: translateY(-50%); - padding: 0.1rem 0.4rem; - border: 1px solid var(--border-color); - border-radius: var(--radius-md); - background: rgba(var(--card-bg-rgb), 0.25); - font-size: 0.78rem; - line-height: 1.2; - color: var(--text-muted); - opacity: 0.65; - pointer-events: none; - user-select: none; -} - -.search-box:focus-within .search-shortcut-hint { - opacity: 0.85; -} - -/* 搜索引擎前缀按钮(方案B:输入框前缀一体化) */ -.search-engine-button { - display: flex; - align-items: center; - gap: 0.5rem; - padding: 0 0.75rem; - width: 120px; - flex: 0 0 120px; - border: none; - border-right: 1px solid var(--border-color); - border-radius: var(--radius-lg) 0 0 var(--radius-lg); - background: transparent; - color: var(--text-muted); - cursor: pointer; - font: inherit; - transition: - background var(--transition-normal), - color var(--transition-normal), - transform var(--transition-normal); -} - -.search-engine-button:hover { - background: rgba(var(--card-bg-rgb), 0.25); -} - -.search-engine-button:focus-visible { - outline: 2px solid var(--accent-color); - outline-offset: 2px; -} - -.search-box:focus-within .search-engine-button { - color: var(--accent-color); -} - -.search-engine-icon { - display: grid; - place-items: center; - height: 1.2em; - width: 1.2em; - min-width: 1.2em; - font-size: 1.25rem; - line-height: 1; - text-align: center; - flex: 0 0 1.2em; -} - -.search-engine-icon.search-engine-icon-svg { - font-size: 1.25rem; -} - -.search-engine-icon.search-engine-icon-svg svg { - width: 100%; - height: 100%; - display: block; -} - -.search-engine-label { - flex: 1; - min-width: 0; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - font-size: 0.95rem; -} - -.search-box.dropdown-open .search-engine-button { - background: rgba(var(--card-bg-rgb), 0.25); -} - -/* 搜索引擎下拉菜单 */ -.search-engine-dropdown { - position: absolute; - top: calc(100% + 6px); - left: 0; - background: rgba(var(--card-bg-rgb), 0.9); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); - border-radius: var(--radius-md); - box-shadow: 0 4px 15px var(--shadow-color); - display: none; - z-index: 100; - padding: 0.35rem; - border: 1px solid var(--border-color); - min-width: 190px; - flex-direction: column; - gap: 0.25rem; -} - -.search-engine-dropdown.active { - display: flex; - animation: fadeIn 0.2s ease-out forwards; -} - -.search-engine-option { - display: flex; - align-items: center; - justify-content: flex-start; - gap: 0.6rem; - width: 100%; - height: 40px; - padding: 0 0.75rem; - border: none; - border-radius: var(--radius-md); - cursor: pointer; - transition: all 0.2s ease; - background: transparent; - color: var(--text-color); - font: inherit; -} - -.search-engine-option:hover { - background: rgba(var(--card-bg-rgb), 0.22); -} - -.search-engine-option:focus-visible { - outline: 2px solid var(--accent-color); - outline-offset: 2px; -} - -.search-engine-option.active { - background-color: var(--secondary-bg); - color: var(--text-bright); -} - -.search-engine-option i { - display: grid; - place-items: center; - position: static; - transform: none; - font-size: 1.25rem; - width: 1.35em; - height: 1.35em; - line-height: 1; - text-align: center; - flex: 0 0 1.35em; -} - -.search-engine-option i.search-engine-option-svg svg { - width: 100%; - height: 100%; - display: block; -} - -.search-engine-option-label { - font-size: 0.95rem; -} - -/* 页面容器 */ -.page { - position: relative; - width: 100%; - display: none; - flex-direction: column; - align-items: center; - padding-top: 2rem; - padding-left: 0.5rem; - padding-right: 0.5rem; -} - -.page.active { - display: flex; -} - -/* 页面模板容器(friends/articles/projects 等): - * .page 是 flex 且 align-items:center,如果子元素未显式设置宽度,会触发 shrink-to-fit, - * 导致分类/网格布局变窄(只剩单列)。 */ -.page-template { - width: 100%; - max-width: var(--page-max-width); - margin: 0 auto; -} - -/* 欢迎区域 - Design A (Minimalist) */ -.welcome-section { - width: 100%; - max-width: var(--page-max-width); - margin: 0 auto 1.2rem auto; - padding: 0 var(--spacing-lg); - text-align: left; - position: relative; - z-index: 5; - display: flex; - justify-content: space-between; - align-items: flex-end; - flex-wrap: wrap; - gap: var(--spacing-md); -} - -.welcome-section-main { - flex: 1; - min-width: 220px; -} - -.welcome-section-side { - flex: 0 0 auto; -} - -.welcome-section h2 { - font-size: 1.75rem; - color: var(--text-bright); - margin-bottom: 0.25rem; - letter-spacing: 0.5px; - transition: color 0.3s ease; -} - -.welcome-section h3 { - font-family: var(--font-body); - font-weight: 400; - font-size: 1rem; - margin-bottom: 0.5rem; - letter-spacing: 0.3px; - color: var(--text-muted); - position: relative; - display: block; -} - -.welcome-section h3::before { - display: none; -} - -.welcome-section .subtitle { - color: var(--text-muted); - font-size: 0.95rem; - line-height: 1.5; - transition: color 0.3s ease; -} - -/* bookmarks:标题后追加“更新时间”小字(灰色、只读展示) */ -.welcome-title-row { - display: flex; - align-items: baseline; - flex-wrap: wrap; - gap: 0.6rem; - margin-bottom: 0.5rem; -} - -.welcome-title-row h2 { - margin: 0; -} - -.page-updated-inline { - color: var(--text-muted); - font-size: 0.9rem; - opacity: 0.85; - white-space: nowrap; -} - -@keyframes glow { - from { - filter: drop-shadow(0 0 2px rgba(118, 148, 185, 0.2)) - drop-shadow(0 0 4px rgba(168, 85, 247, 0.2)); - } - - to { - filter: drop-shadow(0 0 4px rgba(118, 148, 185, 0.4)) - drop-shadow(0 0 8px rgba(168, 85, 247, 0.4)); - } -} - -.site-card { - display: flex; - align-items: center; - padding: 1rem; - /* More generous padding */ - gap: 0.8rem; - background-color: var(--site-card-bg-gradient-1); - /* Solid color */ - border-radius: var(--radius-lg); - /* Larger radius */ - text-decoration: none; - color: var(--text-color); - transition: - transform var(--transition-normal), - box-shadow var(--transition-normal), - background-color var(--transition-normal); - /* Spring transition */ - position: relative; - overflow: hidden; - border: 0.5px solid var(--border-color); - /* Subtle separator */ - /* Remove hard shadow by default for cleaner look, only adding on hover or using very subtle depth */ -} - -.site-card:hover { - transform: translateY(-2px) scale(1.01); - /* Subtle scale */ - background-color: var(--site-card-hover-bg); - box-shadow: 0 8px 20px var(--shadow-color); - /* Deep soft shadow */ - z-index: 2; - border-color: transparent; - /* Merge with shadow */ -} - -/* 分类样式 */ -.category { - background: linear-gradient(145deg, var(--card-bg-gradient-1), var(--card-bg-gradient-2)); - border-radius: var(--radius-xl); - padding: 1rem; - margin: 0 auto 1.2rem auto; - width: 100%; - max-width: var(--page-max-width); - position: relative; - z-index: 1; - opacity: 1; - box-shadow: 0 4px 20px var(--shadow-color); - border: 1px solid var(--border-color); - transition: - background var(--transition-normal), - box-shadow var(--transition-normal); -} - -/* 分类标题容器 */ -.category-header { - border-radius: var(--radius-md); - padding: 0.4rem; - margin: -0.4rem -0.4rem 0.8rem -0.4rem; - transition: all var(--transition-normal); -} - -/* 标题前图标固定宽度:避免不同图标宽度导致标题文本不对齐 */ -.category-header [data-editable='category-name'] > i, -.group-header [data-editable='group-name'] > i { - width: 1.25em; - min-width: 1.25em; - text-align: center; - flex: 0 0 1.25em; -} - -/* 分组标题容器:与分类保持一致的悬浮动效基础 */ -.group-header { - border-radius: var(--radius-md); - transition: all var(--transition-normal); -} - -/* 仅可折叠的标题显示交互态 */ -.category-header[data-toggle='category'], -.group-header[data-toggle='group'] { - cursor: pointer; - user-select: none; -} - -.category-header[data-toggle='category']:hover { - transform: translateY(-2px); - background: linear-gradient(145deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0.01)); -} - -.group-header[data-toggle='group']:hover { - transform: translateY(-2px); - background: linear-gradient(145deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0.01)); -} - -.category-header[data-toggle='category']:active { - transform: translateY(0); -} - -.group-header[data-toggle='group']:active { - transform: translateY(0); -} - -.category h2 { - font-size: 1.2rem; - margin-bottom: 0; - color: var(--text-bright); - display: flex; - align-items: center; - gap: 0.8rem; - letter-spacing: 0.3px; - transition: color 0.3s ease; -} - -.category h2 > i { - color: var(--accent-color); - font-size: 1.3rem; - transition: all 0.3s ease; -} - -.category-header[data-toggle='category']:hover h2 > i { - transform: scale(1.1); - color: var(--accent-hover); -} - -/* 多层级嵌套样式 - 扁平化设计 */ - -/* 通用重置:移除所有嵌套层级的卡片背景和边框 */ -.category-level-2, -.category-level-3, -.category-level-4, -.group-level-3, -.group-level-4 { - background: none; - border: none; - box-shadow: none; - padding: 0; - width: 100%; - margin: 0; -} - -/* 嵌套层级指示线 (Hierarchy Indicator A) */ -.category-level-2::before, -.category-level-3::before, -.group-level-3::before, -.category-level-4::before, -.group-level-4::before { - content: ''; - position: absolute; - left: 0; - top: 0; - bottom: 0; - width: 2px; - background-color: var(--border-color); - opacity: 0.6; -} - -/* 层级2: 子分类 */ -.category-level-2 { - margin-top: 0; - margin-bottom: 0; - padding-left: 1rem; - border-left: none; - position: relative; -} - -/* 层级2: 标题样式 */ -.category-level-2 .category-header { - margin: 0 -0.5rem 1rem -0.5rem; - padding: 0.5rem; - background: none; - border-radius: var(--radius-md); -} - -.category-level-2 .category-header h3 { - font-size: 1.1rem; - font-weight: 600; - color: var(--text-bright); - display: flex; - align-items: center; - gap: 0.8rem; -} - -.category-level-2 .category-header h3 > i { - color: var(--accent-color); - font-size: 1.2rem; - opacity: 0.9; -} - -/* 层级3: 分组 */ -.group-level-3, -.category-level-3 { - margin-top: 0; - margin-bottom: 0; - padding-left: 1rem; - position: relative; -} - -/* 层级3: 标题样式 */ -.group-level-3 .group-header, -.category-level-3 .category-header { - margin: 0 0 0.8rem 0; - padding: 0.3rem 0; - background: none; -} - -.group-level-3 .group-header h4, -.category-level-3 .category-header h4 { - font-size: 1rem; - font-weight: 500; - color: var(--text-color); - display: flex; - align-items: center; - gap: 0.6rem; -} - -.group-level-3 .group-header h4 i, -.category-level-3 .category-header h4 i { - color: var(--text-muted); - font-size: 1rem; -} - -/* 层级4: 子分组 */ -.group-level-4, -.category-level-4 { - margin-top: 0; - margin-bottom: 0; - padding-left: 1rem; - position: relative; -} - -/* 嵌套层级间距:仅在同级相邻时增加间距,避免首项被额外下推 */ -.subcategories-container > .category-level-2 + .category-level-2 { - margin-top: 1rem; -} - -.groups-container > .group-level-3 + .group-level-3, -.groups-container > .category-level-3 + .category-level-3 { - margin-top: 0.8rem; -} - -.subgroups-container > .group-level-4 + .group-level-4, -.subcategories-container > .category-level-4 + .category-level-4 { - margin-top: 0.6rem; -} - -/* 层级4: 标题样式 */ -.group-level-4 .group-header, -.category-level-4 .category-header { - margin: 0 0 0.6rem 0; - padding: 0.2rem 0; - background: none; -} - -.group-level-4 .group-header h5, -.category-level-4 .category-header h5 { - font-size: 0.9rem; - font-weight: 500; - color: var(--text-muted); - display: flex; - align-items: center; - gap: 0.5rem; -} - -.group-level-4 .group-header h5 i, -.category-level-4 .category-header h5 i { - font-size: 0.9rem; - opacity: 0.7; -} - -/* 移除悬停时的缩放效果,保持简洁 */ -.category-level-2 .category-header:hover h3 > i, -.group-level-3 .group-header:hover h4 i, -.category-level-3 .category-header:hover h4 i, -.group-level-4 .group-header:hover h5 i, -.category-level-4 .category-header:hover h5 i { - transform: none; -} - -/* 切换图标样式 */ -.category-header .toggle-icon, -.group-header .toggle-icon { - display: inline-flex; - align-items: center; - justify-content: center; - width: 20px; - height: 20px; - margin-left: auto; - color: var(--text-muted); - font-size: 0.9rem; -} - -.category-header .toggle-icon i, -.group-header .toggle-icon i { - transition: - transform 0.3s ease, - color 0.3s ease; - transform: rotate(0deg); -} - -/* 展开态:图标旋转 180°(类似参考样式1) */ -.category:not(.collapsed) > .category-header .toggle-icon i, -.group:not(.collapsed) > .group-header .toggle-icon i { - transform: rotate(180deg); - color: var(--text-bright); -} - -.category-header[data-toggle='category']:hover .toggle-icon i, -.group-header[data-toggle='group']:hover .toggle-icon i { - color: var(--accent-color); -} - -/* 分类/分组折叠图标:桌面端默认隐藏,悬停/收起时显示,避免按钮过多 */ -@media (hover: hover) and (pointer: fine) { - .category-header .toggle-icon, - .group-header .toggle-icon { - opacity: 0; - transition: opacity 0.2s ease; - } - - .category-header[data-toggle='category']:hover .toggle-icon, - .category.collapsed > .category-header .toggle-icon, - .group-header[data-toggle='group']:hover .toggle-icon, - .group.collapsed > .group-header .toggle-icon { - opacity: 1; - } -} - -/* 展开/折叠动画 */ -.category-content, -.group-content { - overflow: visible; - transition: - max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1), - opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1); - max-height: 5000px; - opacity: 1; -} - -.category.collapsed .category-content, -.group.collapsed .group-content { - overflow: hidden; - max-height: 0; - opacity: 0; - margin-top: 0; -} - -/* 收起状态下调整header的下边距 */ -.category.collapsed > .category-header { - margin-bottom: -0.5rem; -} - -.category-level-2.collapsed > .category-header { - margin-bottom: 0; - border-bottom: none; -} - -.group-level-3.collapsed > .group-header, -.category-level-3.collapsed > .category-header { - margin-bottom: 0; -} - -.group-level-4.collapsed > .group-header, -.category-level-4.collapsed > .category-header { - margin-bottom: 0; -} - -/* 收起态默认向下,无需额外旋转(保持 0deg) */ - -/* 空内容提示 */ -.empty-content { - color: var(--text-muted); - font-style: italic; - text-align: center; - padding: 1rem; - font-size: 0.9rem; -} - -/* 子容器样式 */ -.subcategories-container, -.groups-container { - width: 100%; -} - -/* 当分类同时包含子分类和站点时的样式优化 */ -.category-content .subcategories-container + .sites-grid { - margin-top: 1.2rem; - padding-top: 1rem; - border-top: 1px solid var(--border-color); -} - -/* 当分类同时包含分组和站点时的样式优化 */ -.category-content .groups-container + .sites-grid { - margin-top: 1.2rem; - padding-top: 1rem; - border-top: 1px solid var(--border-color); -} - -/* 子分类容器底部间距调整 */ -.category-content .subcategories-container:not(:last-child), -.category-content .groups-container:not(:last-child) { - margin-bottom: 0.6rem; -} - -/* 确保嵌套的网站网格正确显示 */ -.category-level-2 .sites-grid, -.group-level-3 .sites-grid, -.category-level-3 .sites-grid, -.group-level-4 .sites-grid, -.category-level-4 .sites-grid { - margin-top: 0; - gap: 0.75rem; - /* 保持与顶层一致的网格布局 */ - grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); -} - -/* 响应式设计 - 嵌套结构 */ -@media (max-width: 768px) { - .category-level-2 { - padding-left: 0.75rem; - } - - .group-level-3, - .category-level-3 { - padding-left: 0.75rem; - } - - .group-level-4, - .category-level-4 { - padding-left: 0.75rem; - } - - .subcategories-container > .category-level-2 + .category-level-2 { - margin-top: 0.8rem; - } - - .groups-container > .group-level-3 + .group-level-3, - .groups-container > .category-level-3 + .category-level-3 { - margin-top: 0.7rem; - } - - .subgroups-container > .group-level-4 + .group-level-4, - .subcategories-container > .category-level-4 + .category-level-4 { - margin-top: 0.55rem; - } - - .category-level-2 .sites-grid, - .group-level-3 .sites-grid, - .category-level-3 .sites-grid, - .group-level-4 .sites-grid, - .category-level-4 .sites-grid { - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: var(--spacing-sm); - } -} - -@media (max-width: 480px) { - .category { - margin-left: 0.5rem; - margin-right: 0.5rem; - padding: 1rem; - } - - .category-level-2, - .group-level-3, - .category-level-3 { - margin-left: 0; - padding-left: 0.75rem; - width: 100%; - } - - .group-level-4, - .category-level-4 { - margin-left: 0; - padding-left: 0.75rem; - width: 100%; - } - - .category-level-2 .sites-grid, - .group-level-3 .sites-grid, - .category-level-3 .sites-grid, - .group-level-4 .sites-grid, - .category-level-4 .sites-grid { - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 0.5rem; - } -} - -/* 网站卡片网格 */ -.sites-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); - gap: 0.75rem; - position: relative; - z-index: 1; - width: 100%; -} - -/* projects:GitHub 热力图(github-calendar.js,底部展示) */ -.page-template-projects .gh-heatmap-category { - /* 外层已复用一级分类卡片(.category),这里仅保留热力图内部布局/色阶 */ - --gh-text: var(--text-color); - --gh-text-muted: var(--text-muted); - --gh-level-0: rgba(255, 255, 255, 0.08); - --gh-level-1: rgba(55, 178, 77, 0.35); - --gh-level-2: rgba(55, 178, 77, 0.55); - --gh-level-3: rgba(55, 178, 77, 0.75); - --gh-level-4: rgba(55, 178, 77, 0.95); - --gh-radius: 3px; - - margin: 0 auto 1.2rem auto; -} - -.page-template-projects .gh-heatmap-wrapper { - margin-top: 0; -} - -/* 浅色主题:更接近 GitHub 原色阶 */ -html.theme-preload .page-template-projects .gh-heatmap-category, -body.light-theme .page-template-projects .gh-heatmap-category { - /* 浅色主题下,空格子需要比背景更明显一点 */ - --gh-level-0: #d8dee4; - --gh-level-1: #9be9a8; - --gh-level-2: #40c463; - --gh-level-3: #30a14e; - --gh-level-4: #216e39; -} - -/* 标题中的用户名(@xxx)更弱化一点,像副标题 */ -.page-template-projects .gh-heatmap-username { - color: var(--text-muted); - font-weight: 400; - margin-left: 0.35rem; -} - -/* 使用一级分类标题的排版节奏,略收紧热力图区域 */ -.page-template-projects .gh-heatmap-category .category-header { - margin-bottom: 0.8rem; -} - -/* 标题行:左侧标题 + 右侧 legend(不占内容区高度) */ -.page-template-projects .gh-heatmap-category .gh-heatmap-header { - display: flex; - align-items: center; - justify-content: space-between; - gap: 0.8rem; -} - -.page-template-projects .gh-heatmap-category .gh-heatmap-header h2 { - margin: 0; -} - -/* 让 legend 与标题体系保持一致:放在标题区右侧 */ -.page-template-projects .gh-heatmap-category .gh-legend { - justify-content: flex-end; - margin: 0; -} - -.page-template-projects .gh-header { - display: none; -} - -.page-template-projects .gh-legend { - display: flex; - align-items: center; - gap: 4px; - font-size: 0.75rem; - color: var(--gh-text-muted); - white-space: nowrap; -} - -/* heatmap:移动端标题/legend 文本简写 */ -.gh-text-mobile { - display: none; -} - -@media (max-width: 480px) { - .gh-text-desktop { - display: none; - } - - .gh-text-mobile { - display: inline; - } - - .page-template-projects .gh-heatmap-category .gh-heatmap-header { - flex-wrap: wrap; - } - - .page-template-projects .gh-heatmap-category .gh-legend { - gap: 2px; - font-size: 0.7rem; - } - - .page-template-projects .gh-legend-item { - width: 8px; - height: 8px; - } -} - -.page-template-projects .gh-legend-item { - width: 10px; - height: 10px; - border-radius: 2px; -} - -.page-template-projects .gh-legend .level-0 { - background-color: var(--gh-level-0); -} - -.page-template-projects .gh-legend .level-1 { - background-color: var(--gh-level-1); -} - -.page-template-projects .gh-legend .level-2 { - background-color: var(--gh-level-2); -} - -.page-template-projects .gh-legend .level-3 { - background-color: var(--gh-level-3); -} - -.page-template-projects .gh-legend .level-4 { - background-color: var(--gh-level-4); -} - -/* github-calendar 注入的内容容器 */ -.page-template-projects .gh-calendar { - border: none !important; - min-height: 0; - width: 100%; - /* 构建期注入:避免 flex 居中导致内容超宽“撑破卡片” */ - display: block; -} - -/* 顶部统计标题:XXX contributions in the last year */ -.page-template-projects .gh-calendar #js-contribution-activity-description { - /* 注意:全局 .category h2 会把 h2 设为 flex,导致“看起来左对齐”。这里强制回退为 block。 */ - display: block; - width: 100%; - text-align: center; - margin: 0 0 12px 0; -} - -/* 外层包裹:强制占满卡片宽度,滚动发生在内部 */ -.page-template-projects .gh-calendar .graph-before-activity-overview { - width: 100%; -} - -/* 允许移动端横向滚动查看(GitHub 风格) */ -.page-template-projects .gh-calendar .js-calendar-graph { - width: 100%; - /* 构建期注入 GitHub 原生 table:滚动交给内层容器,避免裁剪 */ - display: block; -} - -/* GitHub 原生 markup:通常在 .js-calendar-graph 内有一个 div 设置 overflow-x */ -.page-template-projects .gh-calendar .js-calendar-graph > div { - width: 100%; - max-width: 100%; - overflow-x: auto; - overflow-y: hidden; - -webkit-overflow-scrolling: touch; - /* 由 table 的 margin:auto 来实现“可居中 + 可滚动时左对齐起始列” */ - display: block; - padding-bottom: 10px; -} - -.page-template-projects .gh-calendar .js-calendar-graph-svg { - width: 100%; - height: auto; -} - -/* 覆盖每个方块的颜色(依赖 github-calendar 的 data-level) */ -.page-template-projects .gh-calendar .day { - rx: var(--gh-radius); - ry: var(--gh-radius); - outline: none; -} - -.page-template-projects .gh-calendar .day[data-level='0'] { - fill: var(--gh-level-0); -} - -.page-template-projects .gh-calendar .day[data-level='1'] { - fill: var(--gh-level-1); -} - -.page-template-projects .gh-calendar .day[data-level='2'] { - fill: var(--gh-level-2); -} - -.page-template-projects .gh-calendar .day[data-level='3'] { - fill: var(--gh-level-3); -} - -.page-template-projects .gh-calendar .day[data-level='4'] { - fill: var(--gh-level-4); -} - -.page-template-projects .gh-calendar text { - fill: var(--gh-text-muted); - font-size: 10px; -} - -/* 去掉库自带 footer(更简洁) */ -.page-template-projects .gh-calendar .contrib-footer { - display: none !important; -} - -.page-template-projects .gh-calendar.gh-calendar-error { - color: var(--gh-text-muted); - font-size: 0.85rem; -} - -/* github-calendar(HTML table 版):适配 ContributionCalendar-* 类名 */ -.page-template-projects .gh-calendar table { - /* 让热力图在卡片内尽量铺满宽度;需要时仍可横向滚动 */ - /* 关键:避免 table 按列拉伸导致 day 变成长方形 */ - display: table; - /* 不强制占满:保持自然宽度,并在容器内居中 */ - width: max-content; - min-width: max-content; - max-width: none; - table-layout: auto; - border-collapse: separate; - border-spacing: 5px !important; - /* table 未超宽时居中;超宽时 margin auto 会退化为 0(滚动起始列左对齐) */ - margin: 0 auto; -} - -/* GitHub 原生 table:thead 行内写死 height:15px,需强制更高以避免月份 label 压到格子 */ -.page-template-projects .gh-calendar table thead tr { - height: 20px !important; -} - -/* GitHub 原生 table 的月份 label 使用 absolute 定位,需要为 thead 行预留高度,避免与格子重叠 */ -.page-template-projects .gh-calendar .ContributionCalendar-label { - height: 16px; - position: relative; - padding-bottom: 4px; - font-size: 10px; - line-height: 10px; - font-weight: 400; - vertical-align: bottom; -} - -@media (max-width: 600px) { - /* 移动端:格子更紧凑,减少横向滚动压力 */ - .page-template-projects .gh-calendar table { - border-spacing: 3px !important; - } - - .page-template-projects .gh-calendar .ContributionCalendar-day { - width: 12px; - height: 12px; - min-width: 12px; - min-height: 12px; - } - - .page-template-projects .gh-calendar #js-contribution-activity-description { - font-size: 0.95rem; - } -} - -/* GitHub 原生 footer:保留“Learn how we count contributions”,隐藏右侧自带 legend(避免与自定义 legend 重复) */ -.page-template-projects .gh-calendar .float-right.color-fg-muted.d-flex.flex-items-center { - display: none !important; -} - -/* 按需求:去除 “Learn how we count contributions” */ -.page-template-projects .gh-calendar .float-left { - display: none !important; -} - -/* Link--muted 目前不展示(float-left 已隐藏);保留基础链接色由下方 a 规则兜底 */ - -.page-template-projects .gh-calendar .ContributionCalendar-day { - /* 固定正方形,防止被 table 列宽拉伸 */ - width: 15px; - height: 15px; - min-width: 15px; - min-height: 15px; - aspect-ratio: 1 / 1; - border-radius: var(--gh-radius); - background-color: var(--gh-level-0); -} - -.page-template-projects .gh-calendar .ContributionCalendar-day[data-level='0'] { - background-color: var(--gh-level-0) !important; -} - -.page-template-projects .gh-calendar .ContributionCalendar-day[data-level='1'] { - background-color: var(--gh-level-1) !important; -} - -.page-template-projects .gh-calendar .ContributionCalendar-day[data-level='2'] { - background-color: var(--gh-level-2) !important; -} - -.page-template-projects .gh-calendar .ContributionCalendar-day[data-level='3'] { - background-color: var(--gh-level-3) !important; -} - -.page-template-projects .gh-calendar .ContributionCalendar-day[data-level='4'] { - background-color: var(--gh-level-4) !important; -} - -/* a11y 跳转链接:视觉隐藏(保留可访问性) */ -.page-template-projects .gh-calendar a[href^='#year-list'], -.page-template-projects .gh-calendar a[href*='year-list'], -.page-template-projects .gh-calendar a[href*='contributions-year'], -/* GitHub 注入的 "Skip to contributions year list"(常见为 show-on-focus) */ -.page-template-projects .gh-calendar a.show-on-focus { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border: 0; -} - -/* 隐藏库自带 footer/legend,避免与自定义 legend 重复 */ -.page-template-projects .gh-calendar .ContributionCalendar-footer, -.page-template-projects .gh-calendar .contrib-footer, -.page-template-projects .gh-calendar .legend, -/* GitHub 原生 legend 容器(float-right + flex) */ -.page-template-projects .gh-calendar .float-right.color-fg-muted.d-flex.flex-items-center { - display: none !important; -} - -/* 修复星期/月份 label 的意外高亮(如 Wed 蓝底) */ -.page-template-projects .gh-calendar .ContributionCalendar-label { - background: transparent !important; - background-color: transparent !important; - color: var(--gh-text-muted) !important; -} - -/* 组件内链接样式:去掉默认紫色 */ -.page-template-projects .gh-calendar a { - color: var(--gh-text-muted); - text-decoration: none; -} - -.page-template-projects .gh-calendar a:hover { - color: var(--gh-text); - text-decoration: underline; -} - -/* Mobile text toggling for Heatmap Header:已在上方 heatmap 区域定义,避免重复 */ - -/* projects:旧版 GitHub 热力图(ghchart 图片)已弃用,改用 github-calendar.js */ - -.page-template-projects .sites-grid { - /* projects:桌面端固定 3 列(避免 auto-fill 在中等宽度下退化为 2 列) */ - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 24px; -} - -@media (max-width: 1024px) { - .page-template-projects .sites-grid { - grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); - } -} - -@media (max-width: 600px) { - .page-template-projects .sites-grid { - grid-template-columns: 1fr; - gap: 0.75rem; - } -} - -/* projects:代码仓库风卡片 */ -.site-card.site-card-repo { - position: relative; - display: flex; - flex-direction: column; - align-items: stretch; - padding: 1.1rem 1.1rem 1rem; - gap: 0; -} - -.site-card.site-card-repo:hover { - transform: translateY(-4px); -} - -.site-card.site-card-repo .repo-header { - display: flex; - align-items: center; - gap: 0.75rem; - margin-bottom: 12px; - min-width: 0; -} - -.site-card.site-card-repo .repo-icon { - font-size: 1.15rem; - color: var(--nav-item-color); - opacity: 0.85; - transition: - color 0.3s ease, - opacity 0.3s ease; - flex: 0 0 auto; -} - -.site-card.site-card-repo:hover .repo-icon { - color: var(--accent-color); - opacity: 1; -} - -.site-card.site-card-repo .repo-title { - font-size: 1rem; - font-weight: 600; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.site-card.site-card-repo .repo-desc { - font-size: 0.9rem; - color: var(--nav-item-color); - opacity: 0.85; - line-height: 1.5; - flex-grow: 1; - margin: 0 0 16px 0; - display: -webkit-box; - -webkit-line-clamp: 3; - -webkit-box-orient: vertical; - overflow: hidden; - position: relative; - /* Ensure tooltip positioning context */ -} - -.site-card.site-card-repo .repo-stats { - display: flex; - align-items: center; - gap: 16px; - padding-top: 12px; - border-top: 1px solid rgba(255, 255, 255, 0.06); - font-size: 0.8rem; - color: var(--nav-item-color); - opacity: 0.85; -} - -.site-card.site-card-repo .stat-item { - display: flex; - align-items: center; - gap: 6px; - min-width: 0; -} - -.site-card.site-card-repo .lang-dot { - width: 10px; - height: 10px; - border-radius: 50%; - display: inline-block; -} - -@media (max-width: 600px) { - .welcome-section-with-side { - align-items: flex-start; - } - - .welcome-section-with-side .welcome-section-side { - width: 100%; - } - - /* 旧版 heatmap-container/heatmap-img 已弃用 */ -} - -/* 网站卡片样式 */ -.site-card { - background: linear-gradient( - 145deg, - var(--site-card-bg-gradient-1), - var(--site-card-bg-gradient-2) - ); - border-radius: var(--radius-lg); - padding: 0.75rem 0.9rem; - text-decoration: none; - color: inherit; - transition: - background var(--transition-normal), - transform var(--transition-normal), - box-shadow var(--transition-normal), - border-color var(--transition-normal); - display: flex; - align-items: center; - gap: 0.6rem; - text-align: left; - backface-visibility: hidden; - transform: translateZ(0); - will-change: transform; - max-width: 100%; - position: relative; - box-shadow: 0 4px 16px var(--shadow-color); - border: 1px solid var(--border-color); - z-index: 2; - overflow: hidden; -} - -/* 网站卡片变体:projects 大卡片 */ -.site-card.site-card-large { - padding: 1.1rem 1.2rem; - gap: 0.9rem; -} - -.site-card.site-card-large .site-card-icon { - width: 3.1rem; - height: 3.1rem; -} - -.site-card.site-card-large h3 { - font-size: 1rem; - font-weight: 600; -} - -.site-card.site-card-large p { - font-size: 0.9rem; -} - -/* Phase 2:articles 页面隐藏“扩展写回结构”,避免与文章条目渲染混淆 */ -.menav-extension-shadow { - display: none; -} - -/* articles:文章元信息(日期 + 来源) */ -.site-card[data-type='article'] .site-card-meta { - margin: 0 0 8px 0; - font-size: 0.75rem; - color: var(--nav-item-color); - opacity: 0.9; - display: flex; - align-items: center; - gap: 0.4rem; -} - -.site-card[data-type='article'] .site-card-meta-sep { - opacity: 0.8; -} - -/* articles:文章卡片布局(首行:图标+标题;下方:时间/来源 + 简介 全宽对齐) */ -.site-card[data-type='article'] { - display: block; - padding: 1rem 1.1rem; -} - -.site-card[data-type='article'] .article-card-header { - display: flex; - align-items: flex-start; - gap: 0.75rem; -} - -.site-card[data-type='article'] .article-card-title { - min-width: 0; -} - -.site-card[data-type='article'] .article-card-body { - margin-top: 0.55rem; -} - -.site-card[data-type='article'] h3 { - margin: 0; -} - -.site-card[data-type='article'] p { - margin: 0; -} - -/* articles:桌面端网格固定 3 列(避免 auto-fill 在大屏上过多列导致阅读密度过高) */ -.page-template-articles .sites-grid { - grid-template-columns: repeat(3, minmax(0, 1fr)); -} - -@media (max-width: 1024px) { - .page-template-articles .sites-grid { - grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); - } -} - -@media (max-width: 480px) { - .page-template-articles .sites-grid { - grid-template-columns: 1fr; - gap: 0.5rem; - } -} - -/* articles:标题/描述允许两行显示(更适合多列宽卡片,也适用于搜索结果页) */ -.site-card[data-type='article'] h3 { - white-space: normal; - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; -} - -.site-card[data-type='article'] p { - white-space: normal; - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; -} - -.site-card:hover { - transform: translateY(-3px); - background: var(--site-card-hover-bg); - border-color: var(--border-color); -} - -.site-card-icon { - flex-shrink: 0; - width: 2.5rem; - height: 2.5rem; - border-radius: var(--radius-md); - background: rgba(var(--card-bg-rgb), 0.35); - border: 1px solid var(--border-color); - display: flex; - align-items: center; - justify-content: center; - transition: - transform 0.3s ease, - background-color 0.3s ease; -} - -.site-card .site-icon { - font-size: 1.4rem; - color: var(--accent-color); - transition: color 0.3s ease; -} - -.site-card:hover .site-card-icon { - transform: scale(1.06); -} - -.site-card:hover .site-icon { - color: var(--accent-hover); -} - -/* 网站卡片 favicon 图片样式,与图标尺寸保持一致 */ -.site-card .favicon-icon { - display: inline-block; - width: 1.8rem; - height: 1.8rem; - border-radius: var(--radius-sm); - object-fit: cover; - transition: - transform 0.3s ease, - box-shadow 0.3s ease; -} - -.site-card .icon-placeholder, -.site-card .icon-fallback { - display: inline-block; - width: 1.8rem; - height: 1.8rem; - border-radius: var(--radius-sm); - flex-shrink: 0; - vertical-align: middle; - text-align: center; - line-height: 1.8rem; - font-size: 1.5rem; - transition: - transform 0.3s ease, - box-shadow 0.3s ease; - color: var(--accent-color); -} - -/* 确保图标容器在加载过程中保持固定尺寸 */ -.site-card .icon-container { - display: inline-block; - width: 1.8rem; - height: 1.8rem; - position: relative; - vertical-align: middle; -} - -.site-card .icon-container .favicon-icon, -.site-card .icon-container .icon-placeholder, -.site-card .icon-container .icon-fallback { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - margin-bottom: 0; -} - -/* 优化图标切换动画 */ -.site-card .icon-container .favicon-icon { - opacity: 0; - transition: opacity 0.3s ease; -} - -.site-card .icon-container .favicon-icon.loaded { - opacity: 1; -} - -.site-card .icon-container .favicon-icon.error { - display: none; -} - -.site-card .icon-container .icon-placeholder { - opacity: 1; - transition: opacity 0.3s ease; -} - -.site-card .icon-container .icon-placeholder.hidden { - opacity: 0; - pointer-events: none; -} - -.site-card .icon-container .icon-fallback { - opacity: 0; - transition: opacity 0.3s ease; -} - -.site-card .icon-container .icon-fallback.visible { - opacity: 1; -} - -.site-card:hover .icon-placeholder, -.site-card:hover .icon-fallback { - color: var(--accent-hover); -} - -.site-card-content { - flex: 1; - min-width: 0; - overflow: hidden; -} - -.site-card h3 { - font-size: 1rem; - margin-bottom: 0.25rem; - color: var(--text-bright); - font-weight: 500; - letter-spacing: 0.3px; - transition: color 0.3s ease; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - max-width: 100%; -} - -.site-card p { - font-size: 0.9rem; - color: var(--nav-item-color); - margin: 0; - line-height: 1.4; - transition: color 0.3s ease; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - width: 100%; - position: relative; - /* Ensure tooltip positioning context */ -} - -/* Tooltip styles */ -/* Tooltip styles */ -.site-card p[data-tooltip], -.site-card .repo-desc[data-tooltip] { - cursor: default; - /* Indicate interactivity */ -} - -.custom-tooltip { - position: fixed; - background: rgba(47, 48, 53, 0.95); - /* Fallback dark */ - background: rgba(var(--card-bg-rgb), 0.95); - color: var(--text-bright); - padding: 0.5rem 0.8rem; - border-radius: var(--radius-md); - box-shadow: 0 4px 12px var(--shadow-color); - border: 1px solid var(--border-color); - font-size: 0.85rem; - white-space: normal; - line-height: 1.4; - z-index: 9999; - pointer-events: none; - opacity: 0; - transition: opacity 0.2s ease-out; - backdrop-filter: blur(4px); - -webkit-backdrop-filter: blur(4px); - max-width: 300px; - word-break: break-word; -} - -.custom-tooltip.visible { - opacity: 1; -} - -/* 添加编辑按钮 */ -.edit-buttons { - position: absolute; - top: 0.5rem; - right: 0.5rem; - display: flex; - gap: 0.5rem; - opacity: 0; - transition: opacity 0.3s ease; -} - -.site-card:hover .edit-buttons { - opacity: 1; -} - -.edit-btn, -.delete-btn { - background: none; - border: none; - color: var(--text-muted); - cursor: pointer; - padding: 0.3rem; - border-radius: 4px; - transition: all 0.3s ease; -} - -.edit-btn:hover, -.delete-btn:hover { - color: var(--text-bright); - background-color: var(--secondary-bg); -} - -/* 添加网站按钮 */ -.add-site-btn { - background: linear-gradient( - 145deg, - var(--site-card-bg-gradient-1), - var(--site-card-bg-gradient-2) - ); - border: 2px dashed var(--border-color); - border-radius: var(--radius-lg); - padding: 1.5rem; - color: var(--text-muted); - cursor: pointer; - transition: all var(--transition-normal); - transition-timing-function: var(--transition-bounce); - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - min-height: 180px; - box-shadow: 0 4px 16px var(--shadow-color); -} - -.add-site-btn:hover { - background: linear-gradient(145deg, var(--secondary-bg), var(--site-card-bg-gradient-1)); - border-color: var(--accent-color); - color: var(--text-bright); - transform: translateY(-2px); - box-shadow: 0 6px 20px var(--shadow-color); -} - -.add-site-btn i { - font-size: 2.2rem; - margin-bottom: 0.8rem; - transition: transform 0.3s ease; -} - -.add-site-btn:hover i { - transform: scale(1.1); -} - -/* 模态框样式 */ -.modal { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: rgba(0, 0, 0, 0.6); - display: none; - justify-content: center; - align-items: center; - z-index: 1000; -} - -.modal.active { - display: flex; - animation: modalFadeIn 0.3s ease-out forwards; -} - -.modal-content { - background-color: var(--sidebar-bg); - border-radius: var(--radius-xl); - padding: var(--spacing-xl); - width: 90%; - max-width: 520px; - position: relative; - box-shadow: 0 8px 32px var(--shadow-color); - transform: scale(0.95); - opacity: 0; - animation: modalContentShow 0.3s ease-out forwards; - transition: background-color 0.3s ease; -} - -.modal-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 2rem; -} - -.modal-header h3 { - color: var(--text-bright); - font-size: 1.3rem; - letter-spacing: 0.3px; - font-weight: 500; - transition: color 0.3s ease; -} - -.close-modal { - background: none; - border: none; - color: var(--text-muted); - cursor: pointer; - font-size: 1.5rem; - padding: var(--spacing-sm); - transition: all var(--transition-normal); - border-radius: var(--radius-md); -} - -.close-modal:hover { - color: var(--text-bright); - background-color: var(--secondary-bg); -} - -/* 表单样式 */ -.site-form { - display: flex; - flex-direction: column; - gap: 1.2rem; -} - -.form-group { - display: flex; - flex-direction: column; - gap: 0.6rem; -} - -.form-group label { - color: var(--text-muted); - font-size: 0.95rem; - letter-spacing: 0.2px; - transition: color 0.3s ease; -} - -.form-group input, -.form-group select { - background-color: var(--secondary-bg); - border: 1px solid transparent; - border-radius: var(--radius-md); - padding: var(--spacing-md) var(--spacing-lg); - color: var(--text-color); - font-size: 1rem; - transition: all var(--transition-normal); - box-shadow: 0 2px 6px var(--shadow-color); -} - -.form-group input:focus, -.form-group select:focus { - outline: none; - background-color: var(--secondary-bg); - border-color: var(--accent-color); - box-shadow: 0 2px 8px rgba(118, 148, 185, 0.15); -} - -.form-group input::placeholder { - color: var(--text-muted); -} - -.form-actions { - display: flex; - justify-content: flex-end; - gap: 1rem; - margin-top: 2rem; -} - -.btn { - padding: var(--spacing-md) var(--spacing-xl); - border: none; - border-radius: var(--radius-md); - cursor: pointer; - font-size: 1rem; - font-weight: 500; - letter-spacing: 0.3px; - transition: all var(--transition-normal); - transition-timing-function: var(--transition-bounce); - box-shadow: 0 2px 6px var(--shadow-color); -} - -.btn-primary { - background-color: var(--accent-color); - color: var(--white-color); -} - -.btn-primary:hover { - background-color: var(--accent-hover); - transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(118, 148, 185, 0.2); -} - -.btn-secondary { - background-color: var(--secondary-bg); - color: var(--text-muted); -} - -.btn-secondary:hover { - background-color: var(--secondary-bg); - color: var(--text-bright); - transform: translateY(-2px); - box-shadow: 0 4px 12px var(--shadow-color); -} - -/* 响应式设计 */ -@media (max-width: 1200px) { - .welcome-section { - padding: 0 var(--spacing-lg); - margin-bottom: 2rem; - } - - .category { - max-width: 1100px; - margin: 0 auto 2.5rem auto; - } -} - -@media (max-width: 768px) { - .mobile-buttons { - display: flex; - } - - :root { - /* 与移动端搜索框高度更贴合(搜索框更高一些,菜单按钮同步放大) */ - --mobile-top-button-size: 2.9rem; - } - - .menu-toggle { - width: var(--mobile-top-button-size); - height: var(--mobile-top-button-size); - background: rgba(var(--card-bg-rgb), 0.65); - border: 1px solid var(--border-color); - border-radius: var(--radius-lg); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); - box-shadow: 0 4px 16px var(--shadow-color); - } - - /* 移动端:右下角磁贴与侧边栏按钮磁贴统一风格 */ - .theme-toggle, - .category-toggle { - width: var(--mobile-top-button-size); - height: var(--mobile-top-button-size); - background: rgba(var(--card-bg-rgb), 0.65); - border: 1px solid var(--border-color); - border-radius: var(--radius-lg); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); - box-shadow: 0 4px 16px var(--shadow-color); - transition: all var(--transition-normal); - transition-timing-function: var(--transition-bounce); - } - - .theme-toggle:hover, - .category-toggle:hover { - transform: translateY(-2px); - background: rgba(var(--card-bg-rgb), 0.75); - box-shadow: 0 6px 20px var(--shadow-color); - color: var(--accent-color); - } - - .theme-toggle:active, - .category-toggle:active { - transform: translateY(0); - box-shadow: 0 2px 8px var(--shadow-color); - } - - main.content { - margin-left: 0; - width: 100vw; - max-width: 100vw; - padding-top: calc(var(--spacing-md) + var(--mobile-top-button-size) + var(--spacing-sm)); - padding-top: calc( - env(safe-area-inset-top) + var(--spacing-md) + var(--mobile-top-button-size) + - var(--spacing-sm) - ); - /* 缩短分类卡片与页面边缘的左右留白,扩大分类卡片可用宽度 */ - padding-left: calc(var(--spacing-sm) + var(--spacing-xs)); - padding-right: calc(var(--spacing-sm) + var(--spacing-xs)); - } - - .sidebar { - transform: translateX(-100%); - box-shadow: none; - transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); - max-width: 100vw; - overflow-x: hidden; - } - - .sidebar .logo { - padding-top: 1.5rem; - display: flex; - align-items: center; - height: 60px; - } - - /* 移动端下隐藏侧边栏折叠按钮 */ - .sidebar-toggle { - display: none; - } - - .sidebar.active { - transform: translateX(0); - box-shadow: 2px 0 10px var(--shadow-color); - z-index: 1000; - /* 增加侧边栏激活时的z-index,确保显示在按钮之上 */ - } - - /* 重置移动端下的侧边栏展开状态 */ - .sidebar.collapsed { - width: var(--sidebar-width); - } - - .sidebar.collapsed .logo h1, - .sidebar.collapsed .nav-item .nav-text, - .sidebar.collapsed .nav-item .external-icon { - opacity: 1; - transform: none; - width: auto; - } - - .sidebar.collapsed .sidebar-footer { - height: auto; - padding: 1rem 1.2rem; - visibility: visible; - pointer-events: auto; - border-top: 1px solid var(--border-color); - } - - .sidebar.collapsed .sidebar-social { - padding: 0.2rem 1.2rem 0.8rem; - flex-direction: row; - } - - .sidebar.collapsed .nav-item { - padding: 0.6rem 0.8rem; - justify-content: flex-start; - } - - .sidebar.collapsed .nav-item .icon-container { - margin-right: 1rem; - } - - /* 移动端:搜索框常驻显示(与侧边栏按钮同一行,无需“悬浮磁贴”) */ - .search-container { - position: fixed; - top: var(--spacing-md); - top: calc(env(safe-area-inset-top) + var(--spacing-md)); - /* 给左侧菜单按钮留出空间 */ - left: calc(var(--spacing-md) + var(--mobile-top-button-size) + var(--spacing-sm)); - right: var(--spacing-md); - left: calc( - env(safe-area-inset-left) + var(--spacing-md) + var(--mobile-top-button-size) + - var(--spacing-sm) - ); - right: calc(env(safe-area-inset-right) + var(--spacing-md)); - width: auto; - padding: 0; - margin-bottom: 0; - box-shadow: none; - z-index: 900; - } - - .search-box { - max-width: 100%; - } - - .search-box input { - padding: 0.8rem 3rem 0.8rem 1rem; - font-size: 0.95rem; - } - - .search-box::after { - right: 0.8rem; - } - - .search-shortcut-hint { - right: 1.2rem; - font-size: 0.72rem; - padding: 0.1rem 0.35rem; - } - - .search-engine-button { - width: 104px; - flex: 0 0 104px; - padding: 0 0.6rem; - } - - .sidebar .logo h1, - .sidebar .nav-item span { - opacity: 1; - display: block; - } - - /* 欢迎区域样式 */ - .welcome-section { - padding: 0 1rem; - margin-top: 1rem; - /* 增加顶部间距 */ - } - - .page { - padding-left: 0.15rem; - padding-right: 0.15rem; - } - - .welcome-section h2 { - font-size: 1.5rem; - } - - .welcome-section h3 { - font-size: 1rem; - background: none; - -webkit-background-clip: border-box; - background-clip: border-box; - animation: none; - color: var(--text-muted); - } - - /* 移动端分类切换按钮 */ - .category-toggle { - bottom: 4rem; - bottom: calc(env(safe-area-inset-bottom) + 4rem); - right: 1rem; - right: calc(env(safe-area-inset-right) + 1rem); - } - - /* 移动端:隐藏搜索按钮(未删除,仅隐藏;搜索框常驻) */ - .search-toggle { - display: none; - } - - /* 分类样式优化 */ - .category { - margin: 0 auto var(--spacing-lg) auto; - padding: var(--spacing-md); - width: 100%; - } - - .sites-grid { - gap: var(--spacing-sm); - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - - .site-card { - /* 移动端保持与客户端一致:横排卡片(图标在左,文本左对齐) */ - flex-direction: row; - align-items: center; - text-align: left; - padding: 0.75rem 0.65rem; - gap: 0.6rem; - } - - .site-card-icon { - width: 2.2rem; - height: 2.2rem; - } - - .site-card .site-icon { - font-size: 1.5rem; - } - - .site-card .favicon-icon, - .site-card .icon-placeholder, - .site-card .icon-fallback, - .site-card .icon-container { - width: 1.5rem; - height: 1.5rem; - } - - .site-card .icon-placeholder, - .site-card .icon-fallback { - line-height: 1.5rem; - font-size: 1.3rem; - } - - .site-card-content { - text-align: left; - } - - .site-card h3 { - font-size: 1rem; - margin-bottom: 0.25rem; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - max-width: 100%; - } - - .site-card p { - font-size: 0.9rem; - line-height: 1.4; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - /* 在移动端的主题切换按钮 */ - .theme-toggle { - bottom: 1rem; - bottom: calc(env(safe-area-inset-bottom) + 1rem); - right: 1rem; - right: calc(env(safe-area-inset-right) + 1rem); - } - - .sidebar .submenu { - margin-left: 1rem; - } - - .sidebar.active .submenu-item { - padding: 0.5rem 0.6rem; - } - - /* 确保移动设备上子菜单不会出现漏出问题 */ - .sidebar.collapsed .submenu { - display: none; - } -} - -@media (max-width: 480px) { - .welcome-section { - padding: 0 1rem; - margin-bottom: 1rem; - } - - .category { - margin: 0 auto 1.3rem auto; - padding: 0.95rem; - width: 100%; - } - - .search-container { - left: calc(var(--spacing-md) + var(--mobile-top-button-size) + var(--spacing-sm)); - right: var(--spacing-md); - left: calc( - env(safe-area-inset-left) + var(--spacing-md) + var(--mobile-top-button-size) + - var(--spacing-sm) - ); - right: calc(env(safe-area-inset-right) + var(--spacing-md)); - } - - .page { - padding-top: 1rem; - padding-left: 0.1rem; - padding-right: 0.1rem; - } - - .sites-grid { - gap: 0.5rem; - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - - .site-card { - padding: 0.75rem 0.5rem; - gap: 0.5rem; - } - - .site-card-icon { - width: 2rem; - height: 2rem; - } - - .site-card .site-icon { - font-size: 1.3rem; - } - - .site-card .favicon-icon, - .site-card .icon-placeholder, - .site-card .icon-fallback, - .site-card .icon-container { - width: 1.35rem; - height: 1.35rem; - } - - .site-card .icon-placeholder, - .site-card .icon-fallback { - line-height: 1.35rem; - font-size: 1.2rem; - } - - .site-card h3 { - font-size: 1rem; - margin-bottom: 0.3rem; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - max-width: 100%; - } - - .site-card p { - font-size: 0.9rem; - line-height: 1.2; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } -} - -@media (max-width: 400px) { - .category { - padding: 0.85rem; - margin: 0 0.05rem 1.2rem 0.05rem; - width: calc(100% - 0.1rem); - } - - .sites-grid { - gap: 0.4rem; - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - - .site-card { - padding: 0.6rem 0.4rem; - gap: 0.45rem; - } - - .site-card-icon { - width: 1.9rem; - height: 1.9rem; - } - - .site-card .site-icon { - font-size: 1.2rem; - } - - .site-card .favicon-icon, - .site-card .icon-placeholder, - .site-card .icon-fallback, - .site-card .icon-container { - width: 1.25rem; - height: 1.25rem; - } - - .site-card .icon-placeholder, - .site-card .icon-fallback { - line-height: 1.25rem; - font-size: 1.1rem; - } - - .site-card h3 { - font-size: 1rem; - margin-bottom: 0.25rem; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - max-width: 100%; - } - - .site-card p { - font-size: 0.9rem; - line-height: 1.15; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } -} - -/* 动画效果 */ -@keyframes fadeIn { - from { - opacity: 0; - transform: translateY(10px); - } - - to { - opacity: 1; - transform: translateY(0); - } -} - -/* 搜索结果页面 */ -#search-results { - position: relative; - width: 100%; - display: none; - flex-direction: column; - align-items: center; - /* 保持在搜索框之下,避免滚动时覆盖 sticky 的搜索容器 */ - z-index: 1; - transform: none !important; - /* 确保没有变换 */ - min-height: 400px; - /* 确保最小高度,防止内容过少时的布局跳动 */ -} - -#search-results.active { - display: flex; - animation: fadeIn 0.3s ease-out forwards; -} - -/* 搜索结果区域 */ -.search-section { - width: 100%; - max-width: var(--page-max-width); - margin: 0 auto 2.5rem auto; - position: relative; - z-index: 1; - transform: none !important; - opacity: 1 !important; -} - -/* 确保搜索结果中的网格有正确的间距 */ -.search-section .sites-grid { - margin-top: 1rem; -} - -/* 搜索结果页:按来源页面复用对应网格规则(方案 2:复用原卡片 DOM) */ -#search-results [data-section='projects'] .sites-grid { - grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); - gap: 24px; -} - -#search-results [data-section='articles'] .sites-grid { - grid-template-columns: repeat(4, minmax(0, 1fr)); -} - -@media (max-width: 1024px) { - #search-results [data-section='articles'] .sites-grid { - grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); - } -} - -@media (max-width: 480px) { - #search-results [data-section='articles'] .sites-grid { - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 0.5rem; - } -} - -/* 确保搜索结果中的卡片样式一致 */ -.search-section .site-card { - max-width: 100%; -} - -/* 加载中动画 */ -.page { - opacity: 0; - transition: opacity 0.3s ease; -} - -.page.active { - opacity: 1; -} - -/* 模态框动画 */ -@keyframes modalFadeIn { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} - -@keyframes modalContentShow { - from { - opacity: 0; - transform: scale(0.9); - } - - to { - opacity: 1; - transform: scale(1); - } -} - -.sites-grid { - transition: gap 0.3s ease; -} - -/* 侧边栏底部:社交图标(位于 sidebar-footer 上方) */ -.sidebar-social { - grid-area: social; - padding: 0.2rem 1.2rem 0.8rem; - display: flex; - justify-content: center; - flex-wrap: wrap; - gap: 0.9rem; -} - -.social-icon { - display: inline-flex; - align-items: center; - justify-content: center; - padding: 0.35rem; - border-radius: var(--radius-full); - color: var(--nav-item-color); - text-decoration: none; - transition: - color var(--transition-fast), - transform var(--transition-fast); -} - -.social-icon:hover { - color: var(--accent-color); - transform: translateY(-1px); -} - -.social-icon:active { - transform: translateY(0); -} - -.social-icon:focus-visible { - outline: 2px solid rgba(118, 148, 185, 0.35); - outline-offset: 2px; -} - -.social-icon i { - width: auto; - font-size: 1.2rem; -} - -/* 侧边栏底部:版权信息 */ -.sidebar-footer { - grid-area: footer; - padding: 1rem 1.2rem; - padding-bottom: calc(1rem + env(safe-area-inset-bottom)); - text-align: center; - color: var(--text-muted); - font-size: 0.85rem; - border-top: 1px solid var(--border-color); - background-color: var(--sidebar-bg); - /* 使用变量 */ - transition: - background-color 0.3s ease, - color 0.3s ease, - opacity 0.3s ease; -} - -.sidebar-footer .copyright { - margin: 0; -} - -.sidebar.collapsed .sidebar-social { - padding: 0.2rem 0.5rem 0.8rem; - flex-direction: column; - align-items: center; - gap: 0.6rem; -} - -.copyright a { - color: var(--accent-color); - text-decoration: none; - transition: all 0.3s ease; -} - -.copyright a:hover { - color: var(--accent-hover); - text-decoration: underline; -} - -/* 导航项包装器 - 包含导航项和子菜单 */ -.nav-item-wrapper { - position: relative; - display: flex; - flex-direction: column; - width: 100%; -} - -/* 子菜单容器 */ -.submenu { - max-height: 0; - overflow: hidden; - transition: max-height 0.3s ease; - margin-left: 1.5rem; - opacity: 0; - visibility: hidden; -} - -/* 子菜单展开状态 */ -.nav-item-wrapper.expanded .submenu { - max-height: none; - overflow: visible; - opacity: 1; - visibility: visible; -} - -/* 子菜单项样式 */ -.submenu-item { - display: flex; - align-items: center; - padding: 0.5rem 0.8rem; - color: var(--nav-item-color); - text-decoration: none; - border-radius: 8px; - transition: all 0.3s ease; - font-size: 0.9rem; - margin: 0.1rem 0; -} - -.submenu-item i { - margin-right: 0.8rem; - font-size: 0.85rem; - width: 16px; - text-align: center; -} - -.submenu-item span { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.submenu-item:hover { - background-color: var(--secondary-bg); - color: var(--text-bright); -} - -.submenu-item.active { - background-color: var(--secondary-bg); - color: var(--text-bright); -} - -/* 侧边栏折叠状态下子菜单样式 - 通过精确控制子菜单的位置和显示方式,确保在侧边栏折叠状态下子菜单不会漏出 - 使用display: none确保完全隐藏,避免任何可能的视觉问题 */ -.sidebar.collapsed .submenu { - position: absolute; - left: var(--sidebar-collapsed-width); - /* 使用变量确保与侧边栏宽度一致 */ - top: 0; - background-color: var(--sidebar-bg); - border-radius: 0 8px 8px 0; - box-shadow: 4px 0 10px var(--shadow-color); - margin-left: 0; - width: 180px; - opacity: 0; - visibility: hidden; - max-height: 0; - overflow: hidden; - z-index: 200; - pointer-events: none; - transition: all 0.3s ease; - display: none; - /* 添加 display: none 确保完全隐藏 */ -} - -/* 确保子菜单项在悬停时不会漏出 - 控制子菜单项的文本溢出行为,确保内容不会超出容器范围 */ -.sidebar.collapsed .submenu-item { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - width: 100%; - box-sizing: border-box; -} - -/* 确保子菜单容器在悬停时不会漏出 - 使用static定位是为了让子菜单相对于侧边栏定位,而不是相对于nav-item-wrapper, - 这样可以避免子菜单在折叠状态下漏出的问题 */ -.sidebar.collapsed .nav-item-wrapper { - position: static; - /* 改为static,防止子菜单定位问题 */ -} - -/* 修改子菜单在悬停时的显示位置 - 当用户悬停在导航项上时,显示子菜单,并确保其位置正确 - 使用绝对定位确保子菜单相对于侧边栏定位,避免在不同滚动位置出现问题 */ -.sidebar.collapsed .nav-item-wrapper:hover .submenu { - max-height: 300px; - overflow-y: scroll; - opacity: 1; - visibility: visible; - scrollbar-width: none; - pointer-events: auto; - display: block; - left: var(--sidebar-collapsed-width); - /* 确保与侧边栏宽度一致 */ - top: 0; - /* 确保从顶部开始 */ - position: absolute; - /* 使用绝对定位,更符合文档流 */ -} - -/* 为WebKit浏览器隐藏滚动条 */ -.sidebar.collapsed .nav-item-wrapper:hover .submenu::-webkit-scrollbar { - display: none; -} - -/* 移动端样式调整 */ -@media (max-width: 768px) { - .sidebar .submenu { - margin-left: 1rem; - } - - .sidebar.active .submenu-item { - padding: 0.5rem 0.6rem; - } - - /* 确保移动设备上子菜单不会出现漏出问题 */ - .sidebar.collapsed .submenu { - display: none; - } -} - -/* ------------------------------------------------------------------ - Markdown Content Styling (GitHub-like) - Scoped to .content-page - ------------------------------------------------------------------ */ - -/* Increase inner spacing for content pages to separate text from card border */ -.content-category .content-page { - padding-left: var(--spacing-sm); - padding-right: var(--spacing-sm); -} - -@media (max-width: 480px) { - .content-category .content-page { - padding-left: var(--spacing-xs); - padding-right: var(--spacing-xs); - } -} - -.content-page { - font-family: var( - --font-body, - -apple-system, - BlinkMacSystemFont, - 'Segoe UI', - 'Noto Sans', - Helvetica, - Arial, - sans-serif, - 'Apple Color Emoji', - 'Segoe UI Emoji' - ); - font-size: 16px; - line-height: 1.6; - color: var(--text-color); - word-wrap: break-word; - padding-bottom: 2rem; -} - -.content-page h1, -.content-page h2, -.content-page h3, -.content-page h4, -.content-page h5, -.content-page h6 { - margin-top: 24px; - margin-bottom: 16px; - font-weight: 600; - line-height: 1.25; - color: var(--text-bright); -} - -.content-page h1 { - font-size: 2em; - padding-bottom: 0.3em; - border-bottom: 1px solid var(--border-color); -} - -.content-page h2 { - font-size: 1.5em; - padding-bottom: 0.3em; - border-bottom: 1px solid var(--border-color); -} - -.content-page h3 { - font-size: 1.25em; -} - -.content-page h4 { - font-size: 1em; -} - -.content-page h5 { - font-size: 0.875em; -} - -.content-page h6 { - font-size: 0.85em; - color: var(--text-muted); -} - -.content-page p { - margin-top: 0; - margin-bottom: 16px; -} - -.content-page blockquote { - margin: 0 0 16px; - padding: 0 1em; - color: var(--text-muted); - border-left: 0.25em solid var(--border-color); - background-color: transparent; -} - -.content-page ul, -.content-page ol { - margin-top: 0; - margin-bottom: 16px; - padding-left: 2em; -} - -.content-page li + li { - margin-top: 0.25em; -} - -/* Inline code */ -.content-page code { - font-family: - ui-monospace, - SFMono-Regular, - SF Mono, - Menlo, - Consolas, - Liberation Mono, - monospace; - font-size: 85%; - padding: 0.2em 0.4em; - margin: 0; - border-radius: var(--radius-sm); - background-color: rgba(127, 127, 127, 0.15); - color: var(--text-bright); -} - -/* Block code (pre) */ -.content-page pre { - padding: 16px; - overflow: auto; - font-size: 85%; - line-height: 1.45; - /* 代码块背景需要与内容卡片区分开:避免与 card-bg 过于接近 */ - background-color: rgba(127, 127, 127, 0.08); - border-radius: var(--radius-md); - margin-top: 0; - margin-bottom: 16px; - border: 1px solid var(--border-color); -} - -.content-page pre code { - background-color: transparent; - padding: 0; - font-size: 100%; - color: inherit; - word-break: normal; - border-radius: 0; -} - -.content-page hr { - height: 0.25em; - padding: 0; - margin: 24px 0; - background-color: var(--border-color); - border: 0; -} - -/* Tables */ -.content-page table { - border-spacing: 0; - border-collapse: collapse; - margin-top: 0; - margin-bottom: 16px; - display: block; - width: max-content; - max-width: 100%; - overflow: auto; -} - -.content-page table th, -.content-page table td { - padding: 6px 13px; - border: 1px solid var(--border-color); -} - -.content-page table th { - font-weight: 600; - background-color: rgba(var(--card-bg-rgb), 0.3); -} - -.content-page table tr { - background-color: transparent; - border-top: 1px solid var(--border-color); -} - -.content-page table tr:nth-child(2n) { - background-color: rgba(127, 127, 127, 0.04); -} - -.content-page img { - max-width: 100%; - box-sizing: content-box; - background-color: transparent; - border-radius: var(--radius-sm); -} - -.content-page a { - color: var(--accent-color); - text-decoration: none; -} - -.content-page a:hover { - text-decoration: underline; -} - -/* Task lists */ -.content-page ul.contains-task-list { - list-style-type: none; - padding-left: 0; -} - -.content-page .task-list-item input { - margin-right: 0.5em; - vertical-align: middle; -} - -/* GitHub Calendar Fixes (HTML Table Version) - * 注:此处样式已合并到上方「projects:GitHub 热力图(github-calendar.js)」区域,避免重复维护。 - */ - -/* ========================================= - Home Dashboard Styles - ========================================= */ - -.dashboard-grid { - display: grid; - grid-template-columns: 1fr; - /* Mobile first: stack vertically */ - gap: var(--spacing-xl); - margin-bottom: var(--spacing-xl); -} - -@media (min-width: 992px) { - .dashboard-grid { - grid-template-columns: 5fr 7fr; - /* Desktop: 5/12 - 7/12 ratio like 1.html */ - align-items: stretch; - /* Stretch to align bottoms */ - gap: var(--spacing-lg); - /* Reduced gap */ - margin-bottom: var(--spacing-lg); - /* Reduced margin */ - } -} - -/* --- Left Column: Welcome & Clock --- */ -.dashboard-intro { - display: flex; - flex-direction: column; - height: 100%; - /* Match grid row height */ - gap: var(--spacing-md); - /* Reduced gap */ - justify-content: space-between; - /* Spread welcome and clock */ -} - -.dashboard-welcome { - display: flex; - flex-direction: column; - gap: var(--spacing-md); -} - -.welcome-title { - font-size: 3.5rem; - font-family: var(--font-heading, var(--font-body, sans-serif)); - font-weight: 800; - /* Extra Bold */ - font-style: normal; - /* Remove italic */ - text-transform: uppercase; - /* Pop Style */ - letter-spacing: -0.03em; - /* Tight spacing */ - color: var(--text-color); - /* Use primary text color, accent reserved for highlights */ - line-height: 0.95; - margin: 0; - padding-left: var(--spacing-xl); - /* Shift right */ -} - -.welcome-subtitle { - font-size: 0.9rem; - letter-spacing: 0.1em; - text-transform: uppercase; - color: var(--accent-color); - /* Accent color for subtitle */ - font-weight: 600; - margin-top: 1rem; - padding-left: var(--spacing-xl); - opacity: 0.9; -} - -@media (min-width: 768px) { - .welcome-title { - font-size: 3.5rem; - padding-left: 2rem; - /* Reduced from 5rem */ - } - - .welcome-subtitle { - font-size: 1.125rem; - padding-left: 2rem; - } -} - -/* Clock Card - Apple Style: Flat + Soft Shadow */ -.dashboard-clock-card { - position: relative; - background-color: var(--card-bg-gradient-1); - /* Solid color, no gradient needed for flat look */ - border: 0.5px solid var(--border-color); - /* Very subtle border */ - border-radius: var(--radius-xl); - display: flex; - flex-direction: column; - justify-content: space-between; - flex: 1; - box-shadow: 0 8px 24px var(--shadow-color); - /* Soft, diffused shadow */ - transition: - transform var(--transition-normal), - box-shadow var(--transition-normal); - overflow: hidden; - padding: var(--spacing-xl); - /* More padding for spatial luxury */ -} - -body.light-theme .dashboard-clock-card { - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08); - /* Lighter shadow for light mode */ -} - -.clock-header { - display: flex; - justify-content: space-between; - align-items: flex-start; - z-index: 1; -} - -.clock-meta { - display: flex; - flex-direction: column; -} - -.clock-main { - align-self: flex-end; - /* Time at bottom right */ - z-index: 1; -} - -.clock-time { - font-size: 3.5rem; - /* Reduced from 4.5rem to prevent overflow */ - font-weight: 700; - color: var(--text-bright); - line-height: 1; - font-family: var(--font-body); - letter-spacing: -0.02em; -} - -.clock-greeting { - font-size: 0.85rem; - color: var(--accent-color); - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.1em; - margin-bottom: 0.2rem; -} - -.clock-week { - font-size: 0.75rem; - color: var(--text-muted); - border: 1px solid var(--border-color); - padding: 2px 8px; - border-radius: 12px; -} - -.clock-date { - font-size: 1.25rem; - /* Reduced from 1.5rem */ - color: var(--text-muted); - font-family: var(--font-body); -} - -/* --- Right Column: Stats / Todo --- */ -.dashboard-stats { - height: 100%; - min-height: 300px; -} - -.dashboard-panel { - background-color: var(--card-bg-gradient-1); - border: 1px solid var(--border-color); - border-radius: var(--radius-xl); - display: flex; - height: 310px; - /* Increased from 280px to align with clock card better */ - overflow: hidden; - box-shadow: 4px 4px 0px 0px rgba(255, 255, 255, 0.15); - transition: box-shadow 0.2s ease; -} - -body.light-theme .dashboard-panel { - box-shadow: 4px 4px 0px 0px rgba(0, 0, 0, 0.2); -} - -.panel-sidebar { - width: 4rem; - background-color: var(--sidebar-bg); - border-right: 4px solid var(--border-color); - display: flex; - flex-direction: column; - justify-content: space-between; - /* Icon at top, button at bottom */ - align-items: center; - padding: var(--spacing-md) 0; -} - -.panel-static-icon { - color: var(--text-muted); - font-size: 1.5rem; - padding: 0.5rem; -} - -.panel-icon-btn { - background: none; - border: none; - color: var(--text-muted); - font-size: 1.5rem; - cursor: pointer; - padding: 0.5rem; - border-radius: var(--radius-md); - transition: color 0.2s; -} - -.panel-icon-btn:hover { - color: var(--accent-color); -} - -.panel-content-wrapper { - flex: 1; - display: flex; - flex-direction: column; - overflow: hidden; - height: 100%; -} - -.panel-content { - flex: 1; - padding: var(--spacing-lg); - overflow-y: auto; - display: flex; - flex-direction: column; - gap: var(--spacing-md); -} - -/* Todo Items */ -.todo-item { - display: flex; - align-items: center; - gap: var(--spacing-md); - padding: 4px 0; - /* Tighter spacing */ - cursor: pointer; - transition: opacity 0.2s; - opacity: 1; - position: relative; -} - -.todo-item:hover .todo-delete-btn { - opacity: 1; - pointer-events: auto; -} - -.todo-checkbox { - width: 1.25rem; - height: 1.25rem; - border: 2px solid var(--text-muted); - border-radius: var(--radius-sm); - display: flex; - align-items: center; - justify-content: center; - flex-shrink: 0; - transition: all 0.2s; -} - -.todo-checkbox.checked { - background-color: var(--accent-color); - border-color: var(--accent-color); - color: white; -} - -.todo-checkbox.checked span { - font-size: 0.8rem; -} - -.todo-text { - font-size: 1.1rem; - color: var(--text-bright); - flex: 1; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.todo-item.done .todo-text { - text-decoration: line-through; - opacity: 0.5; -} - -/* Delete Button */ -.todo-delete-btn { - opacity: 0; - pointer-events: none; - background: none; - border: none; - color: var(--error-color); - padding: 0 0.5rem; - cursor: pointer; - transition: opacity 0.2s; - font-size: 0.85rem; -} - -/* Todo Input Area */ -.todo-input-container { - padding-top: var(--spacing-sm); - border-top: 1px solid var(--border-color); - display: flex; - align-items: center; - gap: 0.5rem; - width: 100%; - /* Ensure full width */ - margin-top: auto; - /* Push to bottom if flex child */ -} - -.todo-input { - flex: 1; - background: transparent; - border: none; - border-bottom: 2px solid var(--border-color); - color: var(--text-bright); - padding: 0.4rem 0; - font-size: 1rem; - font-family: var(--font-body); -} - -.todo-input:focus { - outline: none; - border-bottom-color: var(--accent-color); -} - -.todo-add-btn-small { - background: none; - border: none; - color: var(--accent-color); - cursor: pointer; - font-size: 1.2rem; -} - -/* Light Mode Overrides for Specific Dashboard Colors if needed */ - -@media (max-width: 768px) { - /* 移动端隐藏首页的时间卡片和Todo面板 */ - .dashboard-clock-card, - .dashboard-stats { - display: none !important; - } - - /* 调整移动端首页欢迎语布局 */ - .dashboard-intro { - height: auto; - gap: 0; - margin-bottom: var(--spacing-md); - } - - /* 适当减小欢迎语字号 */ - .welcome-title { - font-size: 2.5rem; - padding-left: 1rem; - } - - .welcome-subtitle { - padding-left: 1rem; - margin-top: 0.5rem; - } -} +/* ============================================ + Menav Style System - Modular Entry Point + ============================================ + + 模块化 CSS 架构: + - 本文件作为入口,通过 @import 聚合所有模块 + - esbuild bundle 模式会在构建时自动合并 + - 模块导入顺序很重要!变量必须第一个导入 + + ============================================ */ + +/* 1. 基础层:变量和全局样式必须最先加载 */ +@import './styles/_variables.css'; +@import './styles/_base.css'; +@import './styles/_animations.css'; + +/* 2. 布局层 */ +@import './styles/_layout.css'; +@import './styles/_sidebar.css'; + +/* 3. 组件层 */ +@import './styles/_search.css'; +@import './styles/_cards.css'; +@import './styles/_modal.css'; + +/* 4. 页面层 */ +@import './styles/_content.css'; +@import './styles/_dashboard.css'; + +/* 5. 兜底样式(包含分类层级、GitHub热力图、响应式等) + 注意:此文件包含所有未独立拆分的样式,部分选择器可能与上方模块重复 + esbuild 会按导入顺序合并,后导入的样式优先级更高 */ +@import './styles/_main.css'; diff --git a/assets/styles/_animations.css b/assets/styles/_animations.css new file mode 100644 index 0000000..6745a5a --- /dev/null +++ b/assets/styles/_animations.css @@ -0,0 +1,49 @@ +/* ============================================ + Animations & Keyframes + ============================================ */ + +@keyframes glow { + from { + filter: drop-shadow(0 0 2px rgba(118, 148, 185, 0.2)) + drop-shadow(0 0 4px rgba(168, 85, 247, 0.2)); + } + + to { + filter: drop-shadow(0 0 4px rgba(118, 148, 185, 0.4)) + drop-shadow(0 0 8px rgba(168, 85, 247, 0.4)); + } +} + +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(10px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes modalFadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +@keyframes modalContentShow { + from { + opacity: 0; + transform: scale(0.95); + } + + to { + opacity: 1; + transform: scale(1); + } +} diff --git a/assets/styles/_base.css b/assets/styles/_base.css new file mode 100644 index 0000000..dd8512d --- /dev/null +++ b/assets/styles/_base.css @@ -0,0 +1,238 @@ +/* ============================================ + Base Styles & Global Reset + ============================================ */ + +/* 可访问性:视觉隐藏但保留屏幕阅读器可读 */ +.visually-hidden { + position: absolute !important; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +/* 主题切换按钮 - 调整为 iOS 风格 */ +.theme-toggle { + position: fixed; + bottom: var(--spacing-xl); + right: var(--spacing-xl); + width: 2.5rem; + height: 2.5rem; + border-radius: var(--radius-lg); + background: rgba(var(--card-bg-rgb), 0.65); + border: 1px solid var(--border-color); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + color: var(--text-color); + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all var(--transition-normal); + transition-timing-function: var(--transition-bounce); + z-index: 100; + box-shadow: 0 4px 16px var(--shadow-color); +} + +.theme-toggle:hover { + transform: translateY(-2px); + background: rgba(var(--card-bg-rgb), 0.75); + box-shadow: 0 6px 20px var(--shadow-color); + color: var(--accent-color); +} + +.theme-toggle:active { + transform: translateY(0); + box-shadow: 0 2px 8px var(--shadow-color); +} + +.theme-toggle i { + font-size: 18px; +} + +/* 全局样式 */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +/* 全局 Focus Visible 样式 */ +:focus-visible { + outline: 2px solid var(--accent-color); + outline-offset: 2px; +} + +/* 导航项 Focus 样式 */ +.nav-item:focus-visible, +.submenu-item:focus-visible, +.site-card:focus-visible, +.theme-toggle:focus-visible, +.category-toggle:focus-visible, +.menu-toggle:focus-visible, +.search-toggle:focus-visible { + outline: 2px solid var(--accent-color); + outline-offset: 2px; + z-index: 10; +} + +/* 通用滚动条样式 */ +.custom-scrollbar { + scrollbar-width: thin; + /* Firefox */ + scrollbar-color: var(--scrollbar-color) transparent; + /* Firefox */ +} + +/* Webkit滚动条样式(Chrome, Safari, Edge等) */ +.custom-scrollbar::-webkit-scrollbar { + width: 7px; + /* 统一滚动条宽度 */ +} + +.custom-scrollbar::-webkit-scrollbar-track { + background: transparent; +} + +.custom-scrollbar::-webkit-scrollbar-thumb { + background-color: var(--scrollbar-color); + /* 使用变量 */ + border-radius: 4px; +} + +.custom-scrollbar::-webkit-scrollbar-thumb:hover { + background-color: var(--scrollbar-hover-color); + /* 使用变量 */ +} + +/* 防止滚动条导致的布局偏移 */ +html { + overflow-y: hidden; + /* 改为hidden,移除强制显示的滚动条 */ + scrollbar-width: thin; + /* Firefox */ + /* 明确 rem 基准字号:便于用 rem 统一管理字号(1rem = 16px) */ + font-size: 16px; +} + +/* 搜索高亮样式 */ +.highlight { + background-color: var(--highlight-bg); + border-radius: var(--radius-sm); + padding: 0 2px; + font-weight: bold; + color: var(--text-color); +} + +body { + font-family: var( + --font-body, + system-ui, + -apple-system, + 'Segoe UI', + Roboto, + 'Noto Sans', + 'Helvetica Neue', + Arial, + sans-serif + ); + font-weight: var(--font-weight-body, normal); + line-height: 1.6; + background-color: var(--bg-color); + color: var(--text-color); + min-height: var(--app-height, 100vh); + overflow: hidden; + /* 防止body滚动 */ + padding-right: 0 !important; + /* 防止滚动条导致的布局偏移 */ + transition: + background-color 0.3s ease, + color 0.3s ease; +} + +/* 布局 */ +.layout { + display: flex; + min-height: var(--app-height, 100vh); + position: relative; + z-index: 1; + overflow: hidden; + /* 防止layout滚动 */ + opacity: 0; + transition: opacity 0.3s ease; +} + +/* 确保加载后立即显示 */ +body.loaded .layout { + opacity: 1; +} + +/* 移动端基础样式 */ +.mobile-buttons { + display: none; + position: fixed; + top: var(--spacing-md); + top: calc(env(safe-area-inset-top) + var(--spacing-md)); + left: 0; + right: 0; + width: 100%; + padding: 0 var(--spacing-md); + padding-left: calc(env(safe-area-inset-left) + var(--spacing-md)); + padding-right: calc(env(safe-area-inset-right) + var(--spacing-md)); + justify-content: space-between; + z-index: 910; + pointer-events: none; +} + +.menu-toggle, +.search-toggle { + background: var(--sidebar-bg); + border: none; + color: var(--text-color); + width: 2.5rem; + height: 2.5rem; + border-radius: var(--radius-md); + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.25s var(--transition-bounce); + box-shadow: 0 2px 8px var(--shadow-color); + pointer-events: auto; +} + +.menu-toggle:hover, +.search-toggle:hover { + background: var(--secondary-bg); + transform: translateY(-2px); + box-shadow: 0 4px 12px var(--shadow-color); +} + +.menu-toggle:active, +.search-toggle:active { + transform: translateY(0); +} + +/* 遮罩层 */ +.overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + opacity: 0; + visibility: hidden; + transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); + z-index: 950; + /* 调整遮罩层z-index,处于按钮与弹出面板之间 */ +} + +.overlay.active { + opacity: 1; + visibility: visible; +} diff --git a/assets/styles/_cards.css b/assets/styles/_cards.css new file mode 100644 index 0000000..d566978 --- /dev/null +++ b/assets/styles/_cards.css @@ -0,0 +1,1365 @@ +/* Cards Component */ + +.site-card { + display: flex; + align-items: center; + padding: 1rem; + /* More generous padding */ + gap: 0.8rem; + background-color: var(--site-card-bg-gradient-1); + /* Solid color */ + border-radius: var(--radius-lg); + /* Larger radius */ + text-decoration: none; + color: var(--text-color); + transition: + transform var(--transition-normal), + box-shadow var(--transition-normal), + background-color var(--transition-normal); + /* Spring transition */ + position: relative; + overflow: hidden; + border: 0.5px solid var(--border-color); + /* Subtle separator */ + /* Remove hard shadow by default for cleaner look, only adding on hover or using very subtle depth */ +} + +.site-card:hover { + transform: translateY(-2px) scale(1.01); + /* Subtle scale */ + background-color: var(--site-card-hover-bg); + box-shadow: 0 8px 20px var(--shadow-color); + /* Deep soft shadow */ + z-index: 2; + border-color: transparent; + /* Merge with shadow */ +} + +/* 分类样式 */ +.category { + background: linear-gradient(145deg, var(--card-bg-gradient-1), var(--card-bg-gradient-2)); + border-radius: var(--radius-xl); + padding: 1rem; + margin: 0 auto 1.2rem auto; + width: 100%; + max-width: var(--page-max-width); + position: relative; + z-index: 1; + opacity: 1; + box-shadow: 0 4px 20px var(--shadow-color); + border: 1px solid var(--border-color); + transition: + background var(--transition-normal), + box-shadow var(--transition-normal); +} + +/* 分类标题容器 */ +.category-header { + border-radius: var(--radius-md); + padding: 0.4rem; + margin: -0.4rem -0.4rem 0.8rem -0.4rem; + transition: all var(--transition-normal); +} + +/* 标题前图标固定宽度:避免不同图标宽度导致标题文本不对齐 */ +.category-header [data-editable='category-name'] > i, +.group-header [data-editable='group-name'] > i { + width: 1.25em; + min-width: 1.25em; + text-align: center; + flex: 0 0 1.25em; +} + +/* 分组标题容器:与分类保持一致的悬浮动效基础 */ +.group-header { + border-radius: var(--radius-md); + transition: all var(--transition-normal); +} + +/* 仅可折叠的标题显示交互态 */ +.category-header[data-toggle='category'], +.group-header[data-toggle='group'] { + cursor: pointer; + user-select: none; +} + +.category-header[data-toggle='category']:hover { + transform: translateY(-2px); + background: linear-gradient(145deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0.01)); +} + +.group-header[data-toggle='group']:hover { + transform: translateY(-2px); + background: linear-gradient(145deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0.01)); +} + +.category-header[data-toggle='category']:active { + transform: translateY(0); +} + +.group-header[data-toggle='group']:active { + transform: translateY(0); +} + +.category h2 { + font-size: 1.2rem; + margin-bottom: 0; + color: var(--text-bright); + display: flex; + align-items: center; + gap: 0.8rem; + letter-spacing: 0.3px; + transition: color 0.3s ease; +} + +.category h2 > i { + color: var(--accent-color); + font-size: 1.3rem; + transition: all 0.3s ease; +} + +.category-header[data-toggle='category']:hover h2 > i { + transform: scale(1.1); + color: var(--accent-hover); +} + +/* 多层级嵌套样式 - 扁平化设计 */ + +/* 通用重置:移除所有嵌套层级的卡片背景和边框 */ +.category-level-2, +.category-level-3, +.category-level-4, +.group-level-3, +.group-level-4 { + background: none; + border: none; + box-shadow: none; + padding: 0; + width: 100%; + margin: 0; +} + +/* 嵌套层级指示线 (Hierarchy Indicator A) */ +.category-level-2::before, +.category-level-3::before, +.group-level-3::before, +.category-level-4::before, +.group-level-4::before { + content: ''; + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 2px; + background-color: var(--border-color); + opacity: 0.6; +} + +/* 层级2: 子分类 */ +.category-level-2 { + margin-top: 0; + margin-bottom: 0; + padding-left: 1rem; + border-left: none; + position: relative; +} + +/* 层级2: 标题样式 */ +.category-level-2 .category-header { + margin: 0 -0.5rem 1rem -0.5rem; + padding: 0.5rem; + background: none; + border-radius: var(--radius-md); +} + +.category-level-2 .category-header h3 { + font-size: 1.1rem; + font-weight: 600; + color: var(--text-bright); + display: flex; + align-items: center; + gap: 0.8rem; +} + +.category-level-2 .category-header h3 > i { + color: var(--accent-color); + font-size: 1.2rem; + opacity: 0.9; +} + +/* 层级3: 分组 */ +.group-level-3, +.category-level-3 { + margin-top: 0; + margin-bottom: 0; + padding-left: 1rem; + position: relative; +} + +/* 层级3: 标题样式 */ +.group-level-3 .group-header, +.category-level-3 .category-header { + margin: 0 0 0.8rem 0; + padding: 0.3rem 0; + background: none; +} + +.group-level-3 .group-header h4, +.category-level-3 .category-header h4 { + font-size: 1rem; + font-weight: 500; + color: var(--text-color); + display: flex; + align-items: center; + gap: 0.6rem; +} + +.group-level-3 .group-header h4 i, +.category-level-3 .category-header h4 i { + color: var(--text-muted); + font-size: 1rem; +} + +/* 层级4: 子分组 */ +.group-level-4, +.category-level-4 { + margin-top: 0; + margin-bottom: 0; + padding-left: 1rem; + position: relative; +} + +/* 嵌套层级间距:仅在同级相邻时增加间距,避免首项被额外下推 */ +.subcategories-container > .category-level-2 + .category-level-2 { + margin-top: 1rem; +} + +.groups-container > .group-level-3 + .group-level-3, +.groups-container > .category-level-3 + .category-level-3 { + margin-top: 0.8rem; +} + +.subgroups-container > .group-level-4 + .group-level-4, +.subcategories-container > .category-level-4 + .category-level-4 { + margin-top: 0.6rem; +} + +/* 层级4: 标题样式 */ +.group-level-4 .group-header, +.category-level-4 .category-header { + margin: 0 0 0.6rem 0; + padding: 0.2rem 0; + background: none; +} + +.group-level-4 .group-header h5, +.category-level-4 .category-header h5 { + font-size: 0.9rem; + font-weight: 500; + color: var(--text-muted); + display: flex; + align-items: center; + gap: 0.5rem; +} + +.group-level-4 .group-header h5 i, +.category-level-4 .category-header h5 i { + font-size: 0.9rem; + opacity: 0.7; +} + +/* 移除悬停时的缩放效果,保持简洁 */ +.category-level-2 .category-header:hover h3 > i, +.group-level-3 .group-header:hover h4 i, +.category-level-3 .category-header:hover h4 i, +.group-level-4 .group-header:hover h5 i, +.category-level-4 .category-header:hover h5 i { + transform: none; +} + +/* 切换图标样式 */ +.category-header .toggle-icon, +.group-header .toggle-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + margin-left: auto; + color: var(--text-muted); + font-size: 0.9rem; +} + +.category-header .toggle-icon i, +.group-header .toggle-icon i { + transition: + transform 0.3s ease, + color 0.3s ease; + transform: rotate(0deg); +} + +/* 展开态:图标旋转 180°(类似参考样式1) */ +.category:not(.collapsed) > .category-header .toggle-icon i, +.group:not(.collapsed) > .group-header .toggle-icon i { + transform: rotate(180deg); + color: var(--text-bright); +} + +.category-header[data-toggle='category']:hover .toggle-icon i, +.group-header[data-toggle='group']:hover .toggle-icon i { + color: var(--accent-color); +} + +/* 分类/分组折叠图标:桌面端默认隐藏,悬停/收起时显示,避免按钮过多 */ +@media (hover: hover) and (pointer: fine) { + .category-header .toggle-icon, + .group-header .toggle-icon { + opacity: 0; + transition: opacity 0.2s ease; + } + + .category-header[data-toggle='category']:hover .toggle-icon, + .category.collapsed > .category-header .toggle-icon, + .group-header[data-toggle='group']:hover .toggle-icon, + .group.collapsed > .group-header .toggle-icon { + opacity: 1; + } +} + +/* 展开/折叠动画 */ +.category-content, +.group-content { + overflow: visible; + transition: + max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1), + opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1); + max-height: 5000px; + opacity: 1; +} + +.category.collapsed .category-content, +.group.collapsed .group-content { + overflow: hidden; + max-height: 0; + opacity: 0; + margin-top: 0; +} + +/* 收起状态下调整header的下边距 */ +.category.collapsed > .category-header { + margin-bottom: -0.5rem; +} + +.category-level-2.collapsed > .category-header { + margin-bottom: 0; + border-bottom: none; +} + +.group-level-3.collapsed > .group-header, +.category-level-3.collapsed > .category-header { + margin-bottom: 0; +} + +.group-level-4.collapsed > .group-header, +.category-level-4.collapsed > .category-header { + margin-bottom: 0; +} + +/* 收起态默认向下,无需额外旋转(保持 0deg) */ + +/* 空内容提示 */ +.empty-content { + color: var(--text-muted); + font-style: italic; + text-align: center; + padding: 1rem; + font-size: 0.9rem; +} + +/* 子容器样式 */ +.subcategories-container, +.groups-container { + width: 100%; +} + +/* 当分类同时包含子分类和站点时的样式优化 */ +.category-content .subcategories-container + .sites-grid { + margin-top: 1.2rem; + padding-top: 1rem; + border-top: 1px solid var(--border-color); +} + +/* 当分类同时包含分组和站点时的样式优化 */ +.category-content .groups-container + .sites-grid { + margin-top: 1.2rem; + padding-top: 1rem; + border-top: 1px solid var(--border-color); +} + +/* 子分类容器底部间距调整 */ +.category-content .subcategories-container:not(:last-child), +.category-content .groups-container:not(:last-child) { + margin-bottom: 0.6rem; +} + +/* 确保嵌套的网站网格正确显示 */ +.category-level-2 .sites-grid, +.group-level-3 .sites-grid, +.category-level-3 .sites-grid, +.group-level-4 .sites-grid, +.category-level-4 .sites-grid { + margin-top: 0; + gap: 0.75rem; + /* 保持与顶层一致的网格布局 */ + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); +} + +/* 响应式设计 - 嵌套结构 */ +@media (max-width: 768px) { + .category-level-2 { + padding-left: 0.75rem; + } + + .group-level-3, + .category-level-3 { + padding-left: 0.75rem; + } + + .group-level-4, + .category-level-4 { + padding-left: 0.75rem; + } + + .subcategories-container > .category-level-2 + .category-level-2 { + margin-top: 0.8rem; + } + + .groups-container > .group-level-3 + .group-level-3, + .groups-container > .category-level-3 + .category-level-3 { + margin-top: 0.7rem; + } + + .subgroups-container > .group-level-4 + .group-level-4, + .subcategories-container > .category-level-4 + .category-level-4 { + margin-top: 0.55rem; + } + + .category-level-2 .sites-grid, + .group-level-3 .sites-grid, + .category-level-3 .sites-grid, + .group-level-4 .sites-grid, + .category-level-4 .sites-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: var(--spacing-sm); + } +} + +@media (max-width: 480px) { + .category { + margin-left: 0.5rem; + margin-right: 0.5rem; + padding: 1rem; + } + + .category-level-2, + .group-level-3, + .category-level-3 { + margin-left: 0; + padding-left: 0.75rem; + width: 100%; + } + + .group-level-4, + .category-level-4 { + margin-left: 0; + padding-left: 0.75rem; + width: 100%; + } + + .category-level-2 .sites-grid, + .group-level-3 .sites-grid, + .category-level-3 .sites-grid, + .group-level-4 .sites-grid, + .category-level-4 .sites-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.5rem; + } +} + +/* 网站卡片网格 */ +.sites-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 0.75rem; + position: relative; + z-index: 1; + width: 100%; +} + +/* projects:GitHub 热力图(github-calendar.js,底部展示) */ +.page-template-projects .gh-heatmap-category { + /* 外层已复用一级分类卡片(.category),这里仅保留热力图内部布局/色阶 */ + --gh-text: var(--text-color); + --gh-text-muted: var(--text-muted); + --gh-level-0: rgba(255, 255, 255, 0.08); + --gh-level-1: rgba(55, 178, 77, 0.35); + --gh-level-2: rgba(55, 178, 77, 0.55); + --gh-level-3: rgba(55, 178, 77, 0.75); + --gh-level-4: rgba(55, 178, 77, 0.95); + --gh-radius: 3px; + + margin: 0 auto 1.2rem auto; +} + +.page-template-projects .gh-heatmap-wrapper { + margin-top: 0; +} + +/* 浅色主题:更接近 GitHub 原色阶 */ +html.theme-preload .page-template-projects .gh-heatmap-category, +body.light-theme .page-template-projects .gh-heatmap-category { + /* 浅色主题下,空格子需要比背景更明显一点 */ + --gh-level-0: #d8dee4; + --gh-level-1: #9be9a8; + --gh-level-2: #40c463; + --gh-level-3: #30a14e; + --gh-level-4: #216e39; +} + +/* 标题中的用户名(@xxx)更弱化一点,像副标题 */ +.page-template-projects .gh-heatmap-username { + color: var(--text-muted); + font-weight: 400; + margin-left: 0.35rem; +} + +/* 使用一级分类标题的排版节奏,略收紧热力图区域 */ +.page-template-projects .gh-heatmap-category .category-header { + margin-bottom: 0.8rem; +} + +/* 标题行:左侧标题 + 右侧 legend(不占内容区高度) */ +.page-template-projects .gh-heatmap-category .gh-heatmap-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.8rem; +} + +.page-template-projects .gh-heatmap-category .gh-heatmap-header h2 { + margin: 0; +} + +/* 让 legend 与标题体系保持一致:放在标题区右侧 */ +.page-template-projects .gh-heatmap-category .gh-legend { + justify-content: flex-end; + margin: 0; +} + +.page-template-projects .gh-header { + display: none; +} + +.page-template-projects .gh-legend { + display: flex; + align-items: center; + gap: 4px; + font-size: 0.75rem; + color: var(--gh-text-muted); + white-space: nowrap; +} + +/* heatmap:移动端标题/legend 文本简写 */ +.gh-text-mobile { + display: none; +} + +@media (max-width: 480px) { + .gh-text-desktop { + display: none; + } + + .gh-text-mobile { + display: inline; + } + + .page-template-projects .gh-heatmap-category .gh-heatmap-header { + flex-wrap: wrap; + } + + .page-template-projects .gh-heatmap-category .gh-legend { + gap: 2px; + font-size: 0.7rem; + } + + .page-template-projects .gh-legend-item { + width: 8px; + height: 8px; + } +} + +.page-template-projects .gh-legend-item { + width: 10px; + height: 10px; + border-radius: 2px; +} + +.page-template-projects .gh-legend .level-0 { + background-color: var(--gh-level-0); +} + +.page-template-projects .gh-legend .level-1 { + background-color: var(--gh-level-1); +} + +.page-template-projects .gh-legend .level-2 { + background-color: var(--gh-level-2); +} + +.page-template-projects .gh-legend .level-3 { + background-color: var(--gh-level-3); +} + +.page-template-projects .gh-legend .level-4 { + background-color: var(--gh-level-4); +} + +/* github-calendar 注入的内容容器 */ +.page-template-projects .gh-calendar { + border: none !important; + min-height: 0; + width: 100%; + /* 构建期注入:避免 flex 居中导致内容超宽“撑破卡片” */ + display: block; +} + +/* 顶部统计标题:XXX contributions in the last year */ +.page-template-projects .gh-calendar #js-contribution-activity-description { + /* 注意:全局 .category h2 会把 h2 设为 flex,导致“看起来左对齐”。这里强制回退为 block。 */ + display: block; + width: 100%; + text-align: center; + margin: 0 0 12px 0; +} + +/* 外层包裹:强制占满卡片宽度,滚动发生在内部 */ +.page-template-projects .gh-calendar .graph-before-activity-overview { + width: 100%; +} + +/* 允许移动端横向滚动查看(GitHub 风格) */ +.page-template-projects .gh-calendar .js-calendar-graph { + width: 100%; + /* 构建期注入 GitHub 原生 table:滚动交给内层容器,避免裁剪 */ + display: block; +} + +/* GitHub 原生 markup:通常在 .js-calendar-graph 内有一个 div 设置 overflow-x */ +.page-template-projects .gh-calendar .js-calendar-graph > div { + width: 100%; + max-width: 100%; + overflow-x: auto; + overflow-y: hidden; + -webkit-overflow-scrolling: touch; + /* 由 table 的 margin:auto 来实现“可居中 + 可滚动时左对齐起始列” */ + display: block; + padding-bottom: 10px; +} + +.page-template-projects .gh-calendar .js-calendar-graph-svg { + width: 100%; + height: auto; +} + +/* 覆盖每个方块的颜色(依赖 github-calendar 的 data-level) */ +.page-template-projects .gh-calendar .day { + rx: var(--gh-radius); + ry: var(--gh-radius); + outline: none; +} + +.page-template-projects .gh-calendar .day[data-level='0'] { + fill: var(--gh-level-0); +} + +.page-template-projects .gh-calendar .day[data-level='1'] { + fill: var(--gh-level-1); +} + +.page-template-projects .gh-calendar .day[data-level='2'] { + fill: var(--gh-level-2); +} + +.page-template-projects .gh-calendar .day[data-level='3'] { + fill: var(--gh-level-3); +} + +.page-template-projects .gh-calendar .day[data-level='4'] { + fill: var(--gh-level-4); +} + +.page-template-projects .gh-calendar text { + fill: var(--gh-text-muted); + font-size: 10px; +} + +/* 去掉库自带 footer(更简洁) */ +.page-template-projects .gh-calendar .contrib-footer { + display: none !important; +} + +.page-template-projects .gh-calendar.gh-calendar-error { + color: var(--gh-text-muted); + font-size: 0.85rem; +} + +/* github-calendar(HTML table 版):适配 ContributionCalendar-* 类名 */ +.page-template-projects .gh-calendar table { + /* 让热力图在卡片内尽量铺满宽度;需要时仍可横向滚动 */ + /* 关键:避免 table 按列拉伸导致 day 变成长方形 */ + display: table; + /* 不强制占满:保持自然宽度,并在容器内居中 */ + width: max-content; + min-width: max-content; + max-width: none; + table-layout: auto; + border-collapse: separate; + border-spacing: 5px !important; + /* table 未超宽时居中;超宽时 margin auto 会退化为 0(滚动起始列左对齐) */ + margin: 0 auto; +} + +/* GitHub 原生 table:thead 行内写死 height:15px,需强制更高以避免月份 label 压到格子 */ +.page-template-projects .gh-calendar table thead tr { + height: 20px !important; +} + +/* GitHub 原生 table 的月份 label 使用 absolute 定位,需要为 thead 行预留高度,避免与格子重叠 */ +.page-template-projects .gh-calendar .ContributionCalendar-label { + height: 16px; + position: relative; + padding-bottom: 4px; + font-size: 10px; + line-height: 10px; + font-weight: 400; + vertical-align: bottom; +} + +@media (max-width: 600px) { + /* 移动端:格子更紧凑,减少横向滚动压力 */ + .page-template-projects .gh-calendar table { + border-spacing: 3px !important; + } + + .page-template-projects .gh-calendar .ContributionCalendar-day { + width: 12px; + height: 12px; + min-width: 12px; + min-height: 12px; + } + + .page-template-projects .gh-calendar #js-contribution-activity-description { + font-size: 0.95rem; + } +} + +/* GitHub 原生 footer:保留“Learn how we count contributions”,隐藏右侧自带 legend(避免与自定义 legend 重复) */ +.page-template-projects .gh-calendar .float-right.color-fg-muted.d-flex.flex-items-center { + display: none !important; +} + +/* 按需求:去除 “Learn how we count contributions” */ +.page-template-projects .gh-calendar .float-left { + display: none !important; +} + +/* Link--muted 目前不展示(float-left 已隐藏);保留基础链接色由下方 a 规则兜底 */ + +.page-template-projects .gh-calendar .ContributionCalendar-day { + /* 固定正方形,防止被 table 列宽拉伸 */ + width: 15px; + height: 15px; + min-width: 15px; + min-height: 15px; + aspect-ratio: 1 / 1; + border-radius: var(--gh-radius); + background-color: var(--gh-level-0); +} + +.page-template-projects .gh-calendar .ContributionCalendar-day[data-level='0'] { + background-color: var(--gh-level-0) !important; +} + +.page-template-projects .gh-calendar .ContributionCalendar-day[data-level='1'] { + background-color: var(--gh-level-1) !important; +} + +.page-template-projects .gh-calendar .ContributionCalendar-day[data-level='2'] { + background-color: var(--gh-level-2) !important; +} + +.page-template-projects .gh-calendar .ContributionCalendar-day[data-level='3'] { + background-color: var(--gh-level-3) !important; +} + +.page-template-projects .gh-calendar .ContributionCalendar-day[data-level='4'] { + background-color: var(--gh-level-4) !important; +} + +/* a11y 跳转链接:视觉隐藏(保留可访问性) */ +.page-template-projects .gh-calendar a[href^='#year-list'], +.page-template-projects .gh-calendar a[href*='year-list'], +.page-template-projects .gh-calendar a[href*='contributions-year'], +/* GitHub 注入的 "Skip to contributions year list"(常见为 show-on-focus) */ +.page-template-projects .gh-calendar a.show-on-focus { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +/* 隐藏库自带 footer/legend,避免与自定义 legend 重复 */ +.page-template-projects .gh-calendar .ContributionCalendar-footer, +.page-template-projects .gh-calendar .contrib-footer, +.page-template-projects .gh-calendar .legend, +/* GitHub 原生 legend 容器(float-right + flex) */ +.page-template-projects .gh-calendar .float-right.color-fg-muted.d-flex.flex-items-center { + display: none !important; +} + +/* 修复星期/月份 label 的意外高亮(如 Wed 蓝底) */ +.page-template-projects .gh-calendar .ContributionCalendar-label { + background: transparent !important; + background-color: transparent !important; + color: var(--gh-text-muted) !important; +} + +/* 组件内链接样式:去掉默认紫色 */ +.page-template-projects .gh-calendar a { + color: var(--gh-text-muted); + text-decoration: none; +} + +.page-template-projects .gh-calendar a:hover { + color: var(--gh-text); + text-decoration: underline; +} + +/* Mobile text toggling for Heatmap Header:已在上方 heatmap 区域定义,避免重复 */ + +/* projects:旧版 GitHub 热力图(ghchart 图片)已弃用,改用 github-calendar.js */ + +.page-template-projects .sites-grid { + /* projects:桌面端固定 3 列(避免 auto-fill 在中等宽度下退化为 2 列) */ + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 24px; +} + +@media (max-width: 1024px) { + .page-template-projects .sites-grid { + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + } +} + +@media (max-width: 600px) { + .page-template-projects .sites-grid { + grid-template-columns: 1fr; + gap: 0.75rem; + } +} + +/* projects:代码仓库风卡片 */ +.site-card.site-card-repo { + position: relative; + display: flex; + flex-direction: column; + align-items: stretch; + padding: 1.1rem 1.1rem 1rem; + gap: 0; +} + +.site-card.site-card-repo:hover { + transform: translateY(-4px); +} + +.site-card.site-card-repo .repo-header { + display: flex; + align-items: center; + gap: 0.75rem; + margin-bottom: 12px; + min-width: 0; +} + +.site-card.site-card-repo .repo-icon { + font-size: 1.15rem; + color: var(--nav-item-color); + opacity: 0.85; + transition: + color 0.3s ease, + opacity 0.3s ease; + flex: 0 0 auto; +} + +.site-card.site-card-repo:hover .repo-icon { + color: var(--accent-color); + opacity: 1; +} + +.site-card.site-card-repo .repo-title { + font-size: 1rem; + font-weight: 600; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.site-card.site-card-repo .repo-desc { + font-size: 0.9rem; + color: var(--nav-item-color); + opacity: 0.85; + line-height: 1.5; + flex-grow: 1; + margin: 0 0 16px 0; + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; + position: relative; + /* Ensure tooltip positioning context */ +} + +.site-card.site-card-repo .repo-stats { + display: flex; + align-items: center; + gap: 16px; + padding-top: 12px; + border-top: 1px solid rgba(255, 255, 255, 0.06); + font-size: 0.8rem; + color: var(--nav-item-color); + opacity: 0.85; +} + +.site-card.site-card-repo .stat-item { + display: flex; + align-items: center; + gap: 6px; + min-width: 0; +} + +.site-card.site-card-repo .lang-dot { + width: 10px; + height: 10px; + border-radius: 50%; + display: inline-block; +} + +@media (max-width: 600px) { + .welcome-section-with-side { + align-items: flex-start; + } + + .welcome-section-with-side .welcome-section-side { + width: 100%; + } + + /* 旧版 heatmap-container/heatmap-img 已弃用 */ +} + +/* 网站卡片样式 */ +.site-card { + background: linear-gradient( + 145deg, + var(--site-card-bg-gradient-1), + var(--site-card-bg-gradient-2) + ); + border-radius: var(--radius-lg); + padding: 0.75rem 0.9rem; + text-decoration: none; + color: inherit; + transition: + background var(--transition-normal), + transform var(--transition-normal), + box-shadow var(--transition-normal), + border-color var(--transition-normal); + display: flex; + align-items: center; + gap: 0.6rem; + text-align: left; + backface-visibility: hidden; + transform: translateZ(0); + will-change: transform; + max-width: 100%; + position: relative; + box-shadow: 0 4px 16px var(--shadow-color); + border: 1px solid var(--border-color); + z-index: 2; + overflow: hidden; +} + +/* 网站卡片变体:projects 大卡片 */ +.site-card.site-card-large { + padding: 1.1rem 1.2rem; + gap: 0.9rem; +} + +.site-card.site-card-large .site-card-icon { + width: 3.1rem; + height: 3.1rem; +} + +.site-card.site-card-large h3 { + font-size: 1rem; + font-weight: 600; +} + +.site-card.site-card-large p { + font-size: 0.9rem; +} + +/* Phase 2:articles 页面隐藏“扩展写回结构”,避免与文章条目渲染混淆 */ +.menav-extension-shadow { + display: none; +} + +/* articles:文章元信息(日期 + 来源) */ +.site-card[data-type='article'] .site-card-meta { + margin: 0 0 8px 0; + font-size: 0.75rem; + color: var(--nav-item-color); + opacity: 0.9; + display: flex; + align-items: center; + gap: 0.4rem; +} + +.site-card[data-type='article'] .site-card-meta-sep { + opacity: 0.8; +} + +/* articles:文章卡片布局(首行:图标+标题;下方:时间/来源 + 简介 全宽对齐) */ +.site-card[data-type='article'] { + display: block; + padding: 1rem 1.1rem; +} + +.site-card[data-type='article'] .article-card-header { + display: flex; + align-items: flex-start; + gap: 0.75rem; +} + +.site-card[data-type='article'] .article-card-title { + min-width: 0; +} + +.site-card[data-type='article'] .article-card-body { + margin-top: 0.55rem; +} + +.site-card[data-type='article'] h3 { + margin: 0; +} + +.site-card[data-type='article'] p { + margin: 0; +} + +/* articles:桌面端网格固定 3 列(避免 auto-fill 在大屏上过多列导致阅读密度过高) */ +.page-template-articles .sites-grid { + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +@media (max-width: 1024px) { + .page-template-articles .sites-grid { + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + } +} + +@media (max-width: 480px) { + .page-template-articles .sites-grid { + grid-template-columns: 1fr; + gap: 0.5rem; + } +} + +/* articles:标题/描述允许两行显示(更适合多列宽卡片,也适用于搜索结果页) */ +.site-card[data-type='article'] h3 { + white-space: normal; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +.site-card[data-type='article'] p { + white-space: normal; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +.site-card:hover { + transform: translateY(-3px); + background: var(--site-card-hover-bg); + border-color: var(--border-color); +} + +.site-card-icon { + flex-shrink: 0; + width: 2.5rem; + height: 2.5rem; + border-radius: var(--radius-md); + background: rgba(var(--card-bg-rgb), 0.35); + border: 1px solid var(--border-color); + display: flex; + align-items: center; + justify-content: center; + transition: + transform 0.3s ease, + background-color 0.3s ease; +} + +.site-card .site-icon { + font-size: 1.4rem; + color: var(--accent-color); + transition: color 0.3s ease; +} + +.site-card:hover .site-card-icon { + transform: scale(1.06); +} + +.site-card:hover .site-icon { + color: var(--accent-hover); +} + +/* 网站卡片 favicon 图片样式,与图标尺寸保持一致 */ +.site-card .favicon-icon { + display: inline-block; + width: 1.8rem; + height: 1.8rem; + border-radius: var(--radius-sm); + object-fit: cover; + transition: + transform 0.3s ease, + box-shadow 0.3s ease; +} + +.site-card .icon-placeholder, +.site-card .icon-fallback { + display: inline-block; + width: 1.8rem; + height: 1.8rem; + border-radius: var(--radius-sm); + flex-shrink: 0; + vertical-align: middle; + text-align: center; + line-height: 1.8rem; + font-size: 1.5rem; + transition: + transform 0.3s ease, + box-shadow 0.3s ease; + color: var(--accent-color); +} + +/* 确保图标容器在加载过程中保持固定尺寸 */ +.site-card .icon-container { + display: inline-block; + width: 1.8rem; + height: 1.8rem; + position: relative; + vertical-align: middle; +} + +.site-card .icon-container .favicon-icon, +.site-card .icon-container .icon-placeholder, +.site-card .icon-container .icon-fallback { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + margin-bottom: 0; +} + +/* 优化图标切换动画 */ +.site-card .icon-container .favicon-icon { + opacity: 0; + transition: opacity 0.3s ease; +} + +.site-card .icon-container .favicon-icon.loaded { + opacity: 1; +} + +.site-card .icon-container .favicon-icon.error { + display: none; +} + +.site-card .icon-container .icon-placeholder { + opacity: 1; + transition: opacity 0.3s ease; +} + +.site-card .icon-container .icon-placeholder.hidden { + opacity: 0; + pointer-events: none; +} + +.site-card .icon-container .icon-fallback { + opacity: 0; + transition: opacity 0.3s ease; +} + +.site-card .icon-container .icon-fallback.visible { + opacity: 1; +} + +.site-card:hover .icon-placeholder, +.site-card:hover .icon-fallback { + color: var(--accent-hover); +} + +.site-card-content { + flex: 1; + min-width: 0; + overflow: hidden; +} + +.site-card h3 { + font-size: 1rem; + margin-bottom: 0.25rem; + color: var(--text-bright); + font-weight: 500; + letter-spacing: 0.3px; + transition: color 0.3s ease; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; +} + +.site-card p { + font-size: 0.9rem; + color: var(--nav-item-color); + margin: 0; + line-height: 1.4; + transition: color 0.3s ease; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + width: 100%; + position: relative; + /* Ensure tooltip positioning context */ +} + +/* Tooltip styles */ +/* Tooltip styles */ +.site-card p[data-tooltip], +.site-card .repo-desc[data-tooltip] { + cursor: default; + /* Indicate interactivity */ +} + +.custom-tooltip { + position: fixed; + background: rgba(47, 48, 53, 0.95); + /* Fallback dark */ + background: rgba(var(--card-bg-rgb), 0.95); + color: var(--text-bright); + padding: 0.5rem 0.8rem; + border-radius: var(--radius-md); + box-shadow: 0 4px 12px var(--shadow-color); + border: 1px solid var(--border-color); + font-size: 0.85rem; + white-space: normal; + line-height: 1.4; + z-index: 9999; + pointer-events: none; + opacity: 0; + transition: opacity 0.2s ease-out; + backdrop-filter: blur(4px); + -webkit-backdrop-filter: blur(4px); + max-width: 300px; + word-break: break-word; +} + +.custom-tooltip.visible { + opacity: 1; +} + +/* 添加编辑按钮 */ +.edit-buttons { + position: absolute; + top: 0.5rem; + right: 0.5rem; + display: flex; + gap: 0.5rem; + opacity: 0; + transition: opacity 0.3s ease; +} + +.site-card:hover .edit-buttons { + opacity: 1; +} + +.edit-btn, +.delete-btn { + background: none; + border: none; + color: var(--text-muted); + cursor: pointer; + padding: 0.3rem; + border-radius: 4px; + transition: all 0.3s ease; +} + +.edit-btn:hover, +.delete-btn:hover { + color: var(--text-bright); + background-color: var(--secondary-bg); +} + +/* 添加网站按钮 */ +.add-site-btn { + background: linear-gradient( + 145deg, + var(--site-card-bg-gradient-1), + var(--site-card-bg-gradient-2) + ); + border: 2px dashed var(--border-color); + border-radius: var(--radius-lg); + padding: 1.5rem; + color: var(--text-muted); + cursor: pointer; + transition: all var(--transition-normal); + transition-timing-function: var(--transition-bounce); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 180px; + box-shadow: 0 4px 16px var(--shadow-color); +} + +.add-site-btn:hover { + background: linear-gradient(145deg, var(--secondary-bg), var(--site-card-bg-gradient-1)); + border-color: var(--accent-color); + color: var(--text-bright); + transform: translateY(-2px); + box-shadow: 0 6px 20px var(--shadow-color); +} + +.add-site-btn i { + font-size: 2.2rem; + margin-bottom: 0.8rem; + transition: transform 0.3s ease; +} + +.add-site-btn:hover i { + transform: scale(1.1); +} diff --git a/assets/styles/_content.css b/assets/styles/_content.css new file mode 100644 index 0000000..cb3f721 --- /dev/null +++ b/assets/styles/_content.css @@ -0,0 +1,216 @@ +/* Markdown Content Page */ + +/* ------------------------------------------------------------------ + Markdown Content Styling (GitHub-like) - Scoped to .content-page + ------------------------------------------------------------------ */ + +/* Increase inner spacing for content pages to separate text from card border */ +.content-category .content-page { + padding-left: var(--spacing-sm); + padding-right: var(--spacing-sm); +} + +@media (max-width: 480px) { + .content-category .content-page { + padding-left: var(--spacing-xs); + padding-right: var(--spacing-xs); + } +} + +.content-page { + font-family: var( + --font-body, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + 'Noto Sans', + Helvetica, + Arial, + sans-serif, + 'Apple Color Emoji', + 'Segoe UI Emoji' + ); + font-size: 16px; + line-height: 1.6; + color: var(--text-color); + word-wrap: break-word; + padding-bottom: 2rem; +} + +.content-page h1, +.content-page h2, +.content-page h3, +.content-page h4, +.content-page h5, +.content-page h6 { + margin-top: 24px; + margin-bottom: 16px; + font-weight: 600; + line-height: 1.25; + color: var(--text-bright); +} + +.content-page h1 { + font-size: 2em; + padding-bottom: 0.3em; + border-bottom: 1px solid var(--border-color); +} + +.content-page h2 { + font-size: 1.5em; + padding-bottom: 0.3em; + border-bottom: 1px solid var(--border-color); +} + +.content-page h3 { + font-size: 1.25em; +} + +.content-page h4 { + font-size: 1em; +} + +.content-page h5 { + font-size: 0.875em; +} + +.content-page h6 { + font-size: 0.85em; + color: var(--text-muted); +} + +.content-page p { + margin-top: 0; + margin-bottom: 16px; +} + +.content-page blockquote { + margin: 0 0 16px; + padding: 0 1em; + color: var(--text-muted); + border-left: 0.25em solid var(--border-color); + background-color: transparent; +} + +.content-page ul, +.content-page ol { + margin-top: 0; + margin-bottom: 16px; + padding-left: 2em; +} + +.content-page li + li { + margin-top: 0.25em; +} + +/* Inline code */ +.content-page code { + font-family: + ui-monospace, + SFMono-Regular, + SF Mono, + Menlo, + Consolas, + Liberation Mono, + monospace; + font-size: 85%; + padding: 0.2em 0.4em; + margin: 0; + border-radius: var(--radius-sm); + background-color: rgba(127, 127, 127, 0.15); + color: var(--text-bright); +} + +/* Block code (pre) */ +.content-page pre { + padding: 16px; + overflow: auto; + font-size: 85%; + line-height: 1.45; + /* 代码块背景需要与内容卡片区分开:避免与 card-bg 过于接近 */ + background-color: rgba(127, 127, 127, 0.08); + border-radius: var(--radius-md); + margin-top: 0; + margin-bottom: 16px; + border: 1px solid var(--border-color); +} + +.content-page pre code { + background-color: transparent; + padding: 0; + font-size: 100%; + color: inherit; + word-break: normal; + border-radius: 0; +} + +.content-page hr { + height: 0.25em; + padding: 0; + margin: 24px 0; + background-color: var(--border-color); + border: 0; +} + +/* Tables */ +.content-page table { + border-spacing: 0; + border-collapse: collapse; + margin-top: 0; + margin-bottom: 16px; + display: block; + width: max-content; + max-width: 100%; + overflow: auto; +} + +.content-page table th, +.content-page table td { + padding: 6px 13px; + border: 1px solid var(--border-color); +} + +.content-page table th { + font-weight: 600; + background-color: rgba(var(--card-bg-rgb), 0.3); +} + +.content-page table tr { + background-color: transparent; + border-top: 1px solid var(--border-color); +} + +.content-page table tr:nth-child(2n) { + background-color: rgba(127, 127, 127, 0.04); +} + +.content-page img { + max-width: 100%; + box-sizing: content-box; + background-color: transparent; + border-radius: var(--radius-sm); +} + +.content-page a { + color: var(--accent-color); + text-decoration: none; +} + +.content-page a:hover { + text-decoration: underline; +} + +/* Task lists */ +.content-page ul.contains-task-list { + list-style-type: none; + padding-left: 0; +} + +.content-page .task-list-item input { + margin-right: 0.5em; + vertical-align: middle; +} + +/* GitHub Calendar Fixes (HTML Table Version) + * 注:此处样式已合并到上方「projects:GitHub 热力图(github-calendar.js)」区域,避免重复维护。 + */ diff --git a/assets/styles/_dashboard.css b/assets/styles/_dashboard.css new file mode 100644 index 0000000..d163d13 --- /dev/null +++ b/assets/styles/_dashboard.css @@ -0,0 +1,371 @@ +/* Dashboard (Clock & Todo) */ + +/* ========================================= + Home Dashboard Styles + ========================================= */ + +.dashboard-grid { + display: grid; + grid-template-columns: 1fr; + /* Mobile first: stack vertically */ + gap: var(--spacing-xl); + margin-bottom: var(--spacing-xl); +} + +@media (min-width: 992px) { + .dashboard-grid { + grid-template-columns: 5fr 7fr; + /* Desktop: 5/12 - 7/12 ratio like 1.html */ + align-items: stretch; + /* Stretch to align bottoms */ + gap: var(--spacing-lg); + /* Reduced gap */ + margin-bottom: var(--spacing-lg); + /* Reduced margin */ + } +} + +/* --- Left Column: Welcome & Clock --- */ +.dashboard-intro { + display: flex; + flex-direction: column; + height: 100%; + /* Match grid row height */ + gap: var(--spacing-md); + /* Reduced gap */ + justify-content: space-between; + /* Spread welcome and clock */ +} + +.dashboard-welcome { + display: flex; + flex-direction: column; + gap: var(--spacing-md); +} + +.welcome-title { + font-size: 3.5rem; + font-family: var(--font-heading, var(--font-body, sans-serif)); + font-weight: 800; + /* Extra Bold */ + font-style: normal; + /* Remove italic */ + text-transform: uppercase; + /* Pop Style */ + letter-spacing: -0.03em; + /* Tight spacing */ + color: var(--text-color); + /* Use primary text color, accent reserved for highlights */ + line-height: 0.95; + margin: 0; + padding-left: var(--spacing-xl); + /* Shift right */ +} + +.welcome-subtitle { + font-size: 0.9rem; + letter-spacing: 0.1em; + text-transform: uppercase; + color: var(--accent-color); + /* Accent color for subtitle */ + font-weight: 600; + margin-top: 1rem; + padding-left: var(--spacing-xl); + opacity: 0.9; +} + +@media (min-width: 768px) { + .welcome-title { + font-size: 3.5rem; + padding-left: 2rem; + /* Reduced from 5rem */ + } + + .welcome-subtitle { + font-size: 1.125rem; + padding-left: 2rem; + } +} + +/* Clock Card - Apple Style: Flat + Soft Shadow */ +.dashboard-clock-card { + position: relative; + background-color: var(--card-bg-gradient-1); + /* Solid color, no gradient needed for flat look */ + border: 0.5px solid var(--border-color); + /* Very subtle border */ + border-radius: var(--radius-xl); + display: flex; + flex-direction: column; + justify-content: space-between; + flex: 1; + box-shadow: 0 8px 24px var(--shadow-color); + /* Soft, diffused shadow */ + transition: + transform var(--transition-normal), + box-shadow var(--transition-normal); + overflow: hidden; + padding: var(--spacing-xl); + /* More padding for spatial luxury */ +} + +body.light-theme .dashboard-clock-card { + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08); + /* Lighter shadow for light mode */ +} + +.clock-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + z-index: 1; +} + +.clock-meta { + display: flex; + flex-direction: column; +} + +.clock-main { + align-self: flex-end; + /* Time at bottom right */ + z-index: 1; +} + +.clock-time { + font-size: 3.5rem; + /* Reduced from 4.5rem to prevent overflow */ + font-weight: 700; + color: var(--text-bright); + line-height: 1; + font-family: var(--font-body); + letter-spacing: -0.02em; +} + +.clock-greeting { + font-size: 0.85rem; + color: var(--accent-color); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.1em; + margin-bottom: 0.2rem; +} + +.clock-week { + font-size: 0.75rem; + color: var(--text-muted); + border: 1px solid var(--border-color); + padding: 2px 8px; + border-radius: 12px; +} + +.clock-date { + font-size: 1.25rem; + /* Reduced from 1.5rem */ + color: var(--text-muted); + font-family: var(--font-body); +} + +/* --- Right Column: Stats / Todo --- */ +.dashboard-stats { + height: 100%; + min-height: 300px; +} + +.dashboard-panel { + background-color: var(--card-bg-gradient-1); + border: 1px solid var(--border-color); + border-radius: var(--radius-xl); + display: flex; + height: 310px; + /* Increased from 280px to align with clock card better */ + overflow: hidden; + box-shadow: 4px 4px 0px 0px rgba(255, 255, 255, 0.15); + transition: box-shadow 0.2s ease; +} + +body.light-theme .dashboard-panel { + box-shadow: 4px 4px 0px 0px rgba(0, 0, 0, 0.2); +} + +.panel-sidebar { + width: 4rem; + background-color: var(--sidebar-bg); + border-right: 4px solid var(--border-color); + display: flex; + flex-direction: column; + justify-content: space-between; + /* Icon at top, button at bottom */ + align-items: center; + padding: var(--spacing-md) 0; +} + +.panel-static-icon { + color: var(--text-muted); + font-size: 1.5rem; + padding: 0.5rem; +} + +.panel-icon-btn { + background: none; + border: none; + color: var(--text-muted); + font-size: 1.5rem; + cursor: pointer; + padding: 0.5rem; + border-radius: var(--radius-md); + transition: color 0.2s; +} + +.panel-icon-btn:hover { + color: var(--accent-color); +} + +.panel-content-wrapper { + flex: 1; + display: flex; + flex-direction: column; + overflow: hidden; + height: 100%; +} + +.panel-content { + flex: 1; + padding: var(--spacing-lg); + overflow-y: auto; + display: flex; + flex-direction: column; + gap: var(--spacing-md); +} + +/* Todo Items */ +.todo-item { + display: flex; + align-items: center; + gap: var(--spacing-md); + padding: 4px 0; + /* Tighter spacing */ + cursor: pointer; + transition: opacity 0.2s; + opacity: 1; + position: relative; +} + +.todo-item:hover .todo-delete-btn { + opacity: 1; + pointer-events: auto; +} + +.todo-checkbox { + width: 1.25rem; + height: 1.25rem; + border: 2px solid var(--text-muted); + border-radius: var(--radius-sm); + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + transition: all 0.2s; +} + +.todo-checkbox.checked { + background-color: var(--accent-color); + border-color: var(--accent-color); + color: white; +} + +.todo-checkbox.checked span { + font-size: 0.8rem; +} + +.todo-text { + font-size: 1.1rem; + color: var(--text-bright); + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.todo-item.done .todo-text { + text-decoration: line-through; + opacity: 0.5; +} + +/* Delete Button */ +.todo-delete-btn { + opacity: 0; + pointer-events: none; + background: none; + border: none; + color: var(--error-color); + padding: 0 0.5rem; + cursor: pointer; + transition: opacity 0.2s; + font-size: 0.85rem; +} + +/* Todo Input Area */ +.todo-input-container { + padding-top: var(--spacing-sm); + border-top: 1px solid var(--border-color); + display: flex; + align-items: center; + gap: 0.5rem; + width: 100%; + /* Ensure full width */ + margin-top: auto; + /* Push to bottom if flex child */ +} + +.todo-input { + flex: 1; + background: transparent; + border: none; + border-bottom: 2px solid var(--border-color); + color: var(--text-bright); + padding: 0.4rem 0; + font-size: 1rem; + font-family: var(--font-body); +} + +.todo-input:focus { + outline: none; + border-bottom-color: var(--accent-color); +} + +.todo-add-btn-small { + background: none; + border: none; + color: var(--accent-color); + cursor: pointer; + font-size: 1.2rem; +} + +/* Light Mode Overrides for Specific Dashboard Colors if needed */ + +@media (max-width: 768px) { + /* 移动端隐藏首页的时间卡片和Todo面板 */ + .dashboard-clock-card, + .dashboard-stats { + display: none !important; + } + + /* 调整移动端首页欢迎语布局 */ + .dashboard-intro { + height: auto; + gap: 0; + margin-bottom: var(--spacing-md); + } + + /* 适当减小欢迎语字号 */ + .welcome-title { + font-size: 2.5rem; + padding-left: 1rem; + } + + .welcome-subtitle { + padding-left: 1rem; + margin-top: 0.5rem; + } +} diff --git a/assets/styles/_layout.css b/assets/styles/_layout.css new file mode 100644 index 0000000..41a88e3 --- /dev/null +++ b/assets/styles/_layout.css @@ -0,0 +1,101 @@ +/* ============================================ + Page Layout & Containers + ============================================ */ + +/* 页面容器 */ +.page { + position: relative; + width: 100%; + display: none; + flex-direction: column; + align-items: center; + padding-top: 2rem; + padding-left: 0.5rem; + padding-right: 0.5rem; +} + +.page.active { + display: flex; +} + +/* 页面模板容器(friends/articles/projects 等) */ +.page-template { + width: 100%; + max-width: var(--page-max-width); + margin: 0 auto; +} + +/* 欢迎区域 - Design A (Minimalist) */ +.welcome-section { + width: 100%; + max-width: var(--page-max-width); + margin: 0 auto 1.2rem auto; + padding: 0 var(--spacing-lg); + text-align: left; + position: relative; + z-index: 5; + display: flex; + justify-content: space-between; + align-items: flex-end; + flex-wrap: wrap; + gap: var(--spacing-md); +} + +.welcome-section-main { + flex: 1; + min-width: 220px; +} + +.welcome-section-side { + flex: 0 0 auto; +} + +.welcome-section h2 { + font-size: 1.75rem; + color: var(--text-bright); + margin-bottom: 0.25rem; + letter-spacing: 0.5px; + transition: color 0.3s ease; +} + +.welcome-section h3 { + font-family: var(--font-body); + font-weight: 400; + font-size: 1rem; + margin-bottom: 0.5rem; + letter-spacing: 0.3px; + color: var(--text-muted); + position: relative; + display: block; +} + +.welcome-section h3::before { + display: none; +} + +.welcome-section .subtitle { + color: var(--text-muted); + font-size: 0.95rem; + line-height: 1.5; + transition: color 0.3s ease; +} + +/* bookmarks:标题后追加"更新时间"小字 */ +.welcome-title-row { + display: flex; + align-items: baseline; + flex-wrap: wrap; + gap: 0.6rem; + margin-bottom: 0.5rem; +} + +.welcome-title-row h2 { + margin: 0; +} + +.page-updated-inline { + color: var(--text-muted); + font-size: 0.9rem; + opacity: 0.85; + white-space: nowrap; +} diff --git a/assets/styles/_main.css b/assets/styles/_main.css new file mode 100644 index 0000000..1fb9258 --- /dev/null +++ b/assets/styles/_main.css @@ -0,0 +1,1448 @@ +/* ============================================ + Main CSS - 分类层级、热力图、响应式 + ============================================ + + 此文件包含以下未独立拆分的样式: + - 分类层级样式 (.category, .category-level-*, .group-*) + - GitHub 热力图 (.gh-*) + - 全局响应式设计 (@media) + - 搜索结果区域 (#search-results) + + ============================================ */ + +/* 分类样式 */ +.category { + background: linear-gradient(145deg, var(--card-bg-gradient-1), var(--card-bg-gradient-2)); + border-radius: var(--radius-xl); + padding: 1rem; + margin: 0 auto 1.2rem auto; + width: 100%; + max-width: var(--page-max-width); + position: relative; + z-index: 1; + opacity: 1; + box-shadow: 0 4px 20px var(--shadow-color); + border: 1px solid var(--border-color); + transition: + background var(--transition-normal), + box-shadow var(--transition-normal); +} + +/* 分类标题容器 */ +.category-header { + border-radius: var(--radius-md); + padding: 0.4rem; + margin: -0.4rem -0.4rem 0.8rem -0.4rem; + transition: all var(--transition-normal); +} + +/* 标题前图标固定宽度:避免不同图标宽度导致标题文本不对齐 */ +.category-header [data-editable='category-name'] > i, +.group-header [data-editable='group-name'] > i { + width: 1.25em; + min-width: 1.25em; + text-align: center; + flex: 0 0 1.25em; +} + +/* 分组标题容器:与分类保持一致的悬浮动效基础 */ +.group-header { + border-radius: var(--radius-md); + transition: all var(--transition-normal); +} + +/* 仅可折叠的标题显示交互态 */ +.category-header[data-toggle='category'], +.group-header[data-toggle='group'] { + cursor: pointer; + user-select: none; +} + +.category-header[data-toggle='category']:hover { + transform: translateY(-2px); + background: linear-gradient(145deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0.01)); +} + +.group-header[data-toggle='group']:hover { + transform: translateY(-2px); + background: linear-gradient(145deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0.01)); +} + +.category-header[data-toggle='category']:active { + transform: translateY(0); +} + +.group-header[data-toggle='group']:active { + transform: translateY(0); +} + +.category h2 { + font-size: 1.2rem; + margin-bottom: 0; + color: var(--text-bright); + display: flex; + align-items: center; + gap: 0.8rem; + letter-spacing: 0.3px; + transition: color 0.3s ease; +} + +.category h2 > i { + color: var(--accent-color); + font-size: 1.3rem; + transition: all 0.3s ease; +} + +.category-header[data-toggle='category']:hover h2 > i { + transform: scale(1.1); + color: var(--accent-hover); +} + +/* 多层级嵌套样式 - 扁平化设计 */ + +/* 通用重置:移除所有嵌套层级的卡片背景和边框 */ +.category-level-2, +.category-level-3, +.category-level-4, +.group-level-3, +.group-level-4 { + background: none; + border: none; + box-shadow: none; + padding: 0; + width: 100%; + margin: 0; +} + +/* 嵌套层级指示线 (Hierarchy Indicator A) */ +.category-level-2::before, +.category-level-3::before, +.group-level-3::before, +.category-level-4::before, +.group-level-4::before { + content: ''; + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 2px; + background-color: var(--border-color); + opacity: 0.6; +} + +/* 层级2: 子分类 */ +.category-level-2 { + margin-top: 0; + margin-bottom: 0; + padding-left: 1rem; + border-left: none; + position: relative; +} + +/* 层级2: 标题样式 */ +.category-level-2 .category-header { + margin: 0 -0.5rem 1rem -0.5rem; + padding: 0.5rem; + background: none; + border-radius: var(--radius-md); +} + +.category-level-2 .category-header h3 { + font-size: 1.1rem; + font-weight: 600; + color: var(--text-bright); + display: flex; + align-items: center; + gap: 0.8rem; +} + +.category-level-2 .category-header h3 > i { + color: var(--accent-color); + font-size: 1.2rem; + opacity: 0.9; +} + +/* 层级3: 分组 */ +.group-level-3, +.category-level-3 { + margin-top: 0; + margin-bottom: 0; + padding-left: 1rem; + position: relative; +} + +/* 层级3: 标题样式 */ +.group-level-3 .group-header, +.category-level-3 .category-header { + margin: 0 0 0.8rem 0; + padding: 0.3rem 0; + background: none; +} + +.group-level-3 .group-header h4, +.category-level-3 .category-header h4 { + font-size: 1rem; + font-weight: 500; + color: var(--text-color); + display: flex; + align-items: center; + gap: 0.6rem; +} + +.group-level-3 .group-header h4 i, +.category-level-3 .category-header h4 i { + color: var(--text-muted); + font-size: 1rem; +} + +/* 层级4: 子分组 */ +.group-level-4, +.category-level-4 { + margin-top: 0; + margin-bottom: 0; + padding-left: 1rem; + position: relative; +} + +/* 嵌套层级间距:仅在同级相邻时增加间距,避免首项被额外下推 */ +.subcategories-container > .category-level-2 + .category-level-2 { + margin-top: 1rem; +} + +.groups-container > .group-level-3 + .group-level-3, +.groups-container > .category-level-3 + .category-level-3 { + margin-top: 0.8rem; +} + +.subgroups-container > .group-level-4 + .group-level-4, +.subcategories-container > .category-level-4 + .category-level-4 { + margin-top: 0.6rem; +} + +/* 层级4: 标题样式 */ +.group-level-4 .group-header, +.category-level-4 .category-header { + margin: 0 0 0.6rem 0; + padding: 0.2rem 0; + background: none; +} + +.group-level-4 .group-header h5, +.category-level-4 .category-header h5 { + font-size: 0.9rem; + font-weight: 500; + color: var(--text-muted); + display: flex; + align-items: center; + gap: 0.5rem; +} + +.group-level-4 .group-header h5 i, +.category-level-4 .category-header h5 i { + font-size: 0.9rem; + opacity: 0.7; +} + +/* 移除悬停时的缩放效果,保持简洁 */ +.category-level-2 .category-header:hover h3 > i, +.group-level-3 .group-header:hover h4 i, +.category-level-3 .category-header:hover h4 i, +.group-level-4 .group-header:hover h5 i, +.category-level-4 .category-header:hover h5 i { + transform: none; +} + +/* 切换图标样式 */ +.category-header .toggle-icon, +.group-header .toggle-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + margin-left: auto; + color: var(--text-muted); + font-size: 0.9rem; +} + +.category-header .toggle-icon i, +.group-header .toggle-icon i { + transition: + transform 0.3s ease, + color 0.3s ease; + transform: rotate(0deg); +} + +/* 展开态:图标旋转 180°(类似参考样式1) */ +.category:not(.collapsed) > .category-header .toggle-icon i, +.group:not(.collapsed) > .group-header .toggle-icon i { + transform: rotate(180deg); + color: var(--text-bright); +} + +.category-header[data-toggle='category']:hover .toggle-icon i, +.group-header[data-toggle='group']:hover .toggle-icon i { + color: var(--accent-color); +} + +/* 分类/分组折叠图标:桌面端默认隐藏,悬停/收起时显示,避免按钮过多 */ +@media (hover: hover) and (pointer: fine) { + .category-header .toggle-icon, + .group-header .toggle-icon { + opacity: 0; + transition: opacity 0.2s ease; + } + + .category-header[data-toggle='category']:hover .toggle-icon, + .category.collapsed > .category-header .toggle-icon, + .group-header[data-toggle='group']:hover .toggle-icon, + .group.collapsed > .group-header .toggle-icon { + opacity: 1; + } +} + +/* 展开/折叠动画 */ +.category-content, +.group-content { + overflow: visible; + transition: + max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1), + opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1); + max-height: 5000px; + opacity: 1; +} + +.category.collapsed .category-content, +.group.collapsed .group-content { + overflow: hidden; + max-height: 0; + opacity: 0; + margin-top: 0; +} + +/* 收起状态下调整header的下边距 */ +.category.collapsed > .category-header { + margin-bottom: -0.5rem; +} + +.category-level-2.collapsed > .category-header { + margin-bottom: 0; + border-bottom: none; +} + +.group-level-3.collapsed > .group-header, +.category-level-3.collapsed > .category-header { + margin-bottom: 0; +} + +.group-level-4.collapsed > .group-header, +.category-level-4.collapsed > .category-header { + margin-bottom: 0; +} + +/* 收起态默认向下,无需额外旋转(保持 0deg) */ + +/* 空内容提示 */ +.empty-content { + color: var(--text-muted); + font-style: italic; + text-align: center; + padding: 1rem; + font-size: 0.9rem; +} + +/* 子容器样式 */ +.subcategories-container, +.groups-container { + width: 100%; +} + +/* 当分类同时包含子分类和站点时的样式优化 */ +.category-content .subcategories-container + .sites-grid { + margin-top: 1.2rem; + padding-top: 1rem; + border-top: 1px solid var(--border-color); +} + +/* 当分类同时包含分组和站点时的样式优化 */ +.category-content .groups-container + .sites-grid { + margin-top: 1.2rem; + padding-top: 1rem; + border-top: 1px solid var(--border-color); +} + +/* 子分类容器底部间距调整 */ +.category-content .subcategories-container:not(:last-child), +.category-content .groups-container:not(:last-child) { + margin-bottom: 0.6rem; +} + +/* 确保嵌套的网站网格正确显示 */ +.category-level-2 .sites-grid, +.group-level-3 .sites-grid, +.category-level-3 .sites-grid, +.group-level-4 .sites-grid, +.category-level-4 .sites-grid { + margin-top: 0; + gap: 0.75rem; + /* 保持与顶层一致的网格布局 */ + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); +} + +/* 响应式设计 - 嵌套结构 */ +@media (max-width: 768px) { + .category-level-2 { + padding-left: 0.75rem; + } + + .group-level-3, + .category-level-3 { + padding-left: 0.75rem; + } + + .group-level-4, + .category-level-4 { + padding-left: 0.75rem; + } + + .subcategories-container > .category-level-2 + .category-level-2 { + margin-top: 0.8rem; + } + + .groups-container > .group-level-3 + .group-level-3, + .groups-container > .category-level-3 + .category-level-3 { + margin-top: 0.7rem; + } + + .subgroups-container > .group-level-4 + .group-level-4, + .subcategories-container > .category-level-4 + .category-level-4 { + margin-top: 0.55rem; + } + + .category-level-2 .sites-grid, + .group-level-3 .sites-grid, + .category-level-3 .sites-grid, + .group-level-4 .sites-grid, + .category-level-4 .sites-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: var(--spacing-sm); + } +} + +@media (max-width: 480px) { + .category { + margin-left: 0.5rem; + margin-right: 0.5rem; + padding: 1rem; + } + + .category-level-2, + .group-level-3, + .category-level-3 { + margin-left: 0; + padding-left: 0.75rem; + width: 100%; + } + + .group-level-4, + .category-level-4 { + margin-left: 0; + padding-left: 0.75rem; + width: 100%; + } + + .category-level-2 .sites-grid, + .group-level-3 .sites-grid, + .category-level-3 .sites-grid, + .group-level-4 .sites-grid, + .category-level-4 .sites-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.5rem; + } +} + +/* projects:GitHub 热力图(github-calendar.js,底部展示) */ +.page-template-projects .gh-heatmap-category { + /* 外层已复用一级分类卡片(.category),这里仅保留热力图内部布局/色阶 */ + --gh-text: var(--text-color); + --gh-text-muted: var(--text-muted); + --gh-level-0: rgba(255, 255, 255, 0.08); + --gh-level-1: rgba(55, 178, 77, 0.35); + --gh-level-2: rgba(55, 178, 77, 0.55); + --gh-level-3: rgba(55, 178, 77, 0.75); + --gh-level-4: rgba(55, 178, 77, 0.95); + --gh-radius: 3px; + + margin: 0 auto 1.2rem auto; +} + +.page-template-projects .gh-heatmap-wrapper { + margin-top: 0; +} + +/* 浅色主题:更接近 GitHub 原色阶 */ +html.theme-preload .page-template-projects .gh-heatmap-category, +body.light-theme .page-template-projects .gh-heatmap-category { + /* 浅色主题下,空格子需要比背景更明显一点 */ + --gh-level-0: #d8dee4; + --gh-level-1: #9be9a8; + --gh-level-2: #40c463; + --gh-level-3: #30a14e; + --gh-level-4: #216e39; +} + +/* 标题中的用户名(@xxx)更弱化一点,像副标题 */ +.page-template-projects .gh-heatmap-username { + color: var(--text-muted); + font-weight: 400; + margin-left: 0.35rem; +} + +/* 使用一级分类标题的排版节奏,略收紧热力图区域 */ +.page-template-projects .gh-heatmap-category .category-header { + margin-bottom: 0.8rem; +} + +/* 标题行:左侧标题 + 右侧 legend(不占内容区高度) */ +.page-template-projects .gh-heatmap-category .gh-heatmap-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.8rem; +} + +.page-template-projects .gh-heatmap-category .gh-heatmap-header h2 { + margin: 0; +} + +/* 让 legend 与标题体系保持一致:放在标题区右侧 */ +.page-template-projects .gh-heatmap-category .gh-legend { + justify-content: flex-end; + margin: 0; +} + +.page-template-projects .gh-header { + display: none; +} + +.page-template-projects .gh-legend { + display: flex; + align-items: center; + gap: 4px; + font-size: 0.75rem; + color: var(--gh-text-muted); + white-space: nowrap; +} + +/* heatmap:移动端标题/legend 文本简写 */ +.gh-text-mobile { + display: none; +} + +@media (max-width: 480px) { + .gh-text-desktop { + display: none; + } + + .gh-text-mobile { + display: inline; + } + + .page-template-projects .gh-heatmap-category .gh-heatmap-header { + flex-wrap: wrap; + } + + .page-template-projects .gh-heatmap-category .gh-legend { + gap: 2px; + font-size: 0.7rem; + } + + .page-template-projects .gh-legend-item { + width: 8px; + height: 8px; + } +} + +.page-template-projects .gh-legend-item { + width: 10px; + height: 10px; + border-radius: 2px; +} + +.page-template-projects .gh-legend .level-0 { + background-color: var(--gh-level-0); +} + +.page-template-projects .gh-legend .level-1 { + background-color: var(--gh-level-1); +} + +.page-template-projects .gh-legend .level-2 { + background-color: var(--gh-level-2); +} + +.page-template-projects .gh-legend .level-3 { + background-color: var(--gh-level-3); +} + +.page-template-projects .gh-legend .level-4 { + background-color: var(--gh-level-4); +} + +/* github-calendar 注入的内容容器 */ +.page-template-projects .gh-calendar { + border: none !important; + min-height: 0; + width: 100%; + /* 构建期注入:避免 flex 居中导致内容超宽“撑破卡片” */ + display: block; +} + +/* 顶部统计标题:XXX contributions in the last year */ +.page-template-projects .gh-calendar #js-contribution-activity-description { + /* 注意:全局 .category h2 会把 h2 设为 flex,导致“看起来左对齐”。这里强制回退为 block。 */ + display: block; + width: 100%; + text-align: center; + margin: 0 0 12px 0; +} + +/* 外层包裹:强制占满卡片宽度,滚动发生在内部 */ +.page-template-projects .gh-calendar .graph-before-activity-overview { + width: 100%; +} + +/* 允许移动端横向滚动查看(GitHub 风格) */ +.page-template-projects .gh-calendar .js-calendar-graph { + width: 100%; + /* 构建期注入 GitHub 原生 table:滚动交给内层容器,避免裁剪 */ + display: block; +} + +/* GitHub 原生 markup:通常在 .js-calendar-graph 内有一个 div 设置 overflow-x */ +.page-template-projects .gh-calendar .js-calendar-graph > div { + width: 100%; + max-width: 100%; + overflow-x: auto; + overflow-y: hidden; + -webkit-overflow-scrolling: touch; + /* 由 table 的 margin:auto 来实现“可居中 + 可滚动时左对齐起始列” */ + display: block; + padding-bottom: 10px; +} + +.page-template-projects .gh-calendar .js-calendar-graph-svg { + width: 100%; + height: auto; +} + +/* 覆盖每个方块的颜色(依赖 github-calendar 的 data-level) */ +.page-template-projects .gh-calendar .day { + rx: var(--gh-radius); + ry: var(--gh-radius); + outline: none; +} + +.page-template-projects .gh-calendar .day[data-level='0'] { + fill: var(--gh-level-0); +} + +.page-template-projects .gh-calendar .day[data-level='1'] { + fill: var(--gh-level-1); +} + +.page-template-projects .gh-calendar .day[data-level='2'] { + fill: var(--gh-level-2); +} + +.page-template-projects .gh-calendar .day[data-level='3'] { + fill: var(--gh-level-3); +} + +.page-template-projects .gh-calendar .day[data-level='4'] { + fill: var(--gh-level-4); +} + +.page-template-projects .gh-calendar text { + fill: var(--gh-text-muted); + font-size: 10px; +} + +/* 去掉库自带 footer(更简洁) */ +.page-template-projects .gh-calendar .contrib-footer { + display: none !important; +} + +.page-template-projects .gh-calendar.gh-calendar-error { + color: var(--gh-text-muted); + font-size: 0.85rem; +} + +/* github-calendar(HTML table 版):适配 ContributionCalendar-* 类名 */ +.page-template-projects .gh-calendar table { + /* 让热力图在卡片内尽量铺满宽度;需要时仍可横向滚动 */ + /* 关键:避免 table 按列拉伸导致 day 变成长方形 */ + display: table; + /* 不强制占满:保持自然宽度,并在容器内居中 */ + width: max-content; + min-width: max-content; + max-width: none; + table-layout: auto; + border-collapse: separate; + border-spacing: 5px !important; + /* table 未超宽时居中;超宽时 margin auto 会退化为 0(滚动起始列左对齐) */ + margin: 0 auto; +} + +/* GitHub 原生 table:thead 行内写死 height:15px,需强制更高以避免月份 label 压到格子 */ +.page-template-projects .gh-calendar table thead tr { + height: 20px !important; +} + +/* GitHub 原生 table 的月份 label 使用 absolute 定位,需要为 thead 行预留高度,避免与格子重叠 */ +.page-template-projects .gh-calendar .ContributionCalendar-label { + height: 16px; + position: relative; + padding-bottom: 4px; + font-size: 10px; + line-height: 10px; + font-weight: 400; + vertical-align: bottom; +} + +@media (max-width: 600px) { + /* 移动端:格子更紧凑,减少横向滚动压力 */ + .page-template-projects .gh-calendar table { + border-spacing: 3px !important; + } + + .page-template-projects .gh-calendar .ContributionCalendar-day { + width: 12px; + height: 12px; + min-width: 12px; + min-height: 12px; + } + + .page-template-projects .gh-calendar #js-contribution-activity-description { + font-size: 0.95rem; + } +} + +/* GitHub 原生 footer:保留“Learn how we count contributions”,隐藏右侧自带 legend(避免与自定义 legend 重复) */ +.page-template-projects .gh-calendar .float-right.color-fg-muted.d-flex.flex-items-center { + display: none !important; +} + +/* 按需求:去除 “Learn how we count contributions” */ +.page-template-projects .gh-calendar .float-left { + display: none !important; +} + +/* Link--muted 目前不展示(float-left 已隐藏);保留基础链接色由下方 a 规则兜底 */ + +.page-template-projects .gh-calendar .ContributionCalendar-day { + /* 固定正方形,防止被 table 列宽拉伸 */ + width: 15px; + height: 15px; + min-width: 15px; + min-height: 15px; + aspect-ratio: 1 / 1; + border-radius: var(--gh-radius); + background-color: var(--gh-level-0); +} + +.page-template-projects .gh-calendar .ContributionCalendar-day[data-level='0'] { + background-color: var(--gh-level-0) !important; +} + +.page-template-projects .gh-calendar .ContributionCalendar-day[data-level='1'] { + background-color: var(--gh-level-1) !important; +} + +.page-template-projects .gh-calendar .ContributionCalendar-day[data-level='2'] { + background-color: var(--gh-level-2) !important; +} + +.page-template-projects .gh-calendar .ContributionCalendar-day[data-level='3'] { + background-color: var(--gh-level-3) !important; +} + +.page-template-projects .gh-calendar .ContributionCalendar-day[data-level='4'] { + background-color: var(--gh-level-4) !important; +} + +/* a11y 跳转链接:视觉隐藏(保留可访问性) */ +.page-template-projects .gh-calendar a[href^='#year-list'], +.page-template-projects .gh-calendar a[href*='year-list'], +.page-template-projects .gh-calendar a[href*='contributions-year'] { + /* GitHub 注入的 "Skip to contributions year list"(常见为 show-on-focus) */ + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +/* 响应式设计 */ +@media (max-width: 1200px) { + .welcome-section { + padding: 0 var(--spacing-lg); + margin-bottom: 2rem; + } + + .category { + max-width: 1100px; + margin: 0 auto 2.5rem auto; + } +} + +@media (max-width: 768px) { + .mobile-buttons { + display: flex; + } + + :root { + /* 与移动端搜索框高度更贴合(搜索框更高一些,菜单按钮同步放大) */ + --mobile-top-button-size: 2.9rem; + } + + .menu-toggle { + width: var(--mobile-top-button-size); + height: var(--mobile-top-button-size); + background: rgba(var(--card-bg-rgb), 0.65); + border: 1px solid var(--border-color); + border-radius: var(--radius-lg); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + box-shadow: 0 4px 16px var(--shadow-color); + } + + /* 移动端:右下角磁贴与侧边栏按钮磁贴统一风格 */ + .theme-toggle, + .category-toggle { + width: var(--mobile-top-button-size); + height: var(--mobile-top-button-size); + background: rgba(var(--card-bg-rgb), 0.65); + border: 1px solid var(--border-color); + border-radius: var(--radius-lg); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + box-shadow: 0 4px 16px var(--shadow-color); + transition: all var(--transition-normal); + transition-timing-function: var(--transition-bounce); + } + + .theme-toggle:hover, + .category-toggle:hover { + transform: translateY(-2px); + background: rgba(var(--card-bg-rgb), 0.75); + box-shadow: 0 6px 20px var(--shadow-color); + color: var(--accent-color); + } + + .theme-toggle:active, + .category-toggle:active { + transform: translateY(0); + box-shadow: 0 2px 8px var(--shadow-color); + } + + main.content { + margin-left: 0; + width: 100vw; + max-width: 100vw; + padding-top: calc(var(--spacing-md) + var(--mobile-top-button-size) + var(--spacing-sm)); + padding-top: calc( + env(safe-area-inset-top) + var(--spacing-md) + var(--mobile-top-button-size) + + var(--spacing-sm) + ); + /* 缩短分类卡片与页面边缘的左右留白,扩大分类卡片可用宽度 */ + padding-left: calc(var(--spacing-sm) + var(--spacing-xs)); + padding-right: calc(var(--spacing-sm) + var(--spacing-xs)); + } + + .sidebar { + transform: translateX(-100%); + box-shadow: none; + transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); + max-width: 100vw; + overflow-x: hidden; + } + + .sidebar .logo { + padding-top: 1.5rem; + display: flex; + align-items: center; + height: 60px; + } + + /* 移动端下隐藏侧边栏折叠按钮 */ + .sidebar-toggle { + display: none; + } + + .sidebar.active { + transform: translateX(0); + box-shadow: 2px 0 10px var(--shadow-color); + z-index: 1000; + /* 增加侧边栏激活时的z-index,确保显示在按钮之上 */ + } + + /* 重置移动端下的侧边栏展开状态 */ + .sidebar.collapsed { + width: var(--sidebar-width); + } + + .sidebar.collapsed .logo h1, + .sidebar.collapsed .nav-item .nav-text, + .sidebar.collapsed .nav-item .external-icon { + opacity: 1; + transform: none; + width: auto; + } + + .sidebar.collapsed .sidebar-footer { + height: auto; + padding: 1rem 1.2rem; + visibility: visible; + pointer-events: auto; + border-top: 1px solid var(--border-color); + } + + .sidebar.collapsed .sidebar-social { + padding: 0.2rem 1.2rem 0.8rem; + flex-direction: row; + } + + .sidebar.collapsed .nav-item { + padding: 0.6rem 0.8rem; + justify-content: flex-start; + } + + .sidebar.collapsed .nav-item .icon-container { + margin-right: 1rem; + } + + /* 移动端:搜索框常驻显示(与侧边栏按钮同一行,无需“悬浮磁贴”) */ + .search-container { + position: fixed; + top: var(--spacing-md); + top: calc(env(safe-area-inset-top) + var(--spacing-md)); + /* 给左侧菜单按钮留出空间 */ + left: calc(var(--spacing-md) + var(--mobile-top-button-size) + var(--spacing-sm)); + right: var(--spacing-md); + left: calc( + env(safe-area-inset-left) + var(--spacing-md) + var(--mobile-top-button-size) + + var(--spacing-sm) + ); + right: calc(env(safe-area-inset-right) + var(--spacing-md)); + width: auto; + padding: 0; + margin-bottom: 0; + box-shadow: none; + z-index: 900; + } + + .search-box { + max-width: 100%; + } + + .search-box input { + padding: 0.8rem 3rem 0.8rem 1rem; + font-size: 0.95rem; + } + + .search-box::after { + right: 0.8rem; + } + + .search-shortcut-hint { + right: 1.2rem; + font-size: 0.72rem; + padding: 0.1rem 0.35rem; + } + + .search-engine-button { + width: 104px; + flex: 0 0 104px; + padding: 0 0.6rem; + } + + .sidebar .logo h1, + .sidebar .nav-item span { + opacity: 1; + display: block; + } + + /* 欢迎区域样式 */ + .welcome-section { + padding: 0 1rem; + margin-top: 1rem; + /* 增加顶部间距 */ + } + + .page { + padding-left: 0.15rem; + padding-right: 0.15rem; + } + + .welcome-section h2 { + font-size: 1.5rem; + } + + .welcome-section h3 { + font-size: 1rem; + background: none; + -webkit-background-clip: border-box; + background-clip: border-box; + animation: none; + color: var(--text-muted); + } + + /* 移动端分类切换按钮 */ + .category-toggle { + bottom: 4rem; + bottom: calc(env(safe-area-inset-bottom) + 4rem); + right: 1rem; + right: calc(env(safe-area-inset-right) + 1rem); + } + + /* 移动端:隐藏搜索按钮(未删除,仅隐藏;搜索框常驻) */ + .search-toggle { + display: none; + } + + /* 分类样式优化 */ + .category { + margin: 0 auto var(--spacing-lg) auto; + padding: var(--spacing-md); + width: 100%; + } + + .sites-grid { + gap: var(--spacing-sm); + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .site-card { + /* 移动端保持与客户端一致:横排卡片(图标在左,文本左对齐) */ + flex-direction: row; + align-items: center; + text-align: left; + padding: 0.75rem 0.65rem; + gap: 0.6rem; + } + + .site-card-icon { + width: 2.2rem; + height: 2.2rem; + } + + .site-card .site-icon { + font-size: 1.5rem; + } + + .site-card .favicon-icon, + .site-card .icon-placeholder, + .site-card .icon-fallback, + .site-card .icon-container { + width: 1.5rem; + height: 1.5rem; + } + + .site-card .icon-placeholder, + .site-card .icon-fallback { + line-height: 1.5rem; + font-size: 1.3rem; + } + + .site-card-content { + text-align: left; + } + + .site-card h3 { + font-size: 1rem; + margin-bottom: 0.25rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; + } + + .site-card p { + font-size: 0.9rem; + line-height: 1.4; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + /* 在移动端的主题切换按钮 */ + .theme-toggle { + bottom: 1rem; + bottom: calc(env(safe-area-inset-bottom) + 1rem); + right: 1rem; + right: calc(env(safe-area-inset-right) + 1rem); + } + + .sidebar .submenu { + margin-left: 1rem; + } + + .sidebar.active .submenu-item { + padding: 0.5rem 0.6rem; + } + + /* 确保移动设备上子菜单不会出现漏出问题 */ + .sidebar.collapsed .submenu { + display: none; + } +} + +@media (max-width: 480px) { + .welcome-section { + padding: 0 1rem; + margin-bottom: 1rem; + } + + .category { + margin: 0 auto 1.3rem auto; + padding: 0.95rem; + width: 100%; + } + + .search-container { + left: calc(var(--spacing-md) + var(--mobile-top-button-size) + var(--spacing-sm)); + right: var(--spacing-md); + left: calc( + env(safe-area-inset-left) + var(--spacing-md) + var(--mobile-top-button-size) + + var(--spacing-sm) + ); + right: calc(env(safe-area-inset-right) + var(--spacing-md)); + } + + .page { + padding-top: 1rem; + padding-left: 0.1rem; + padding-right: 0.1rem; + } + + .sites-grid { + gap: 0.5rem; + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .site-card { + padding: 0.75rem 0.5rem; + gap: 0.5rem; + } + + .site-card-icon { + width: 2rem; + height: 2rem; + } + + .site-card .site-icon { + font-size: 1.3rem; + } + + .site-card .favicon-icon, + .site-card .icon-placeholder, + .site-card .icon-fallback, + .site-card .icon-container { + width: 1.35rem; + height: 1.35rem; + } + + .site-card .icon-placeholder, + .site-card .icon-fallback { + line-height: 1.35rem; + font-size: 1.2rem; + } + + .site-card h3 { + font-size: 1rem; + margin-bottom: 0.3rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; + } + + .site-card p { + font-size: 0.9rem; + line-height: 1.2; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } +} + +@media (max-width: 400px) { + .category { + padding: 0.85rem; + margin: 0 0.05rem 1.2rem 0.05rem; + width: calc(100% - 0.1rem); + } + + .sites-grid { + gap: 0.4rem; + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .site-card { + padding: 0.6rem 0.4rem; + gap: 0.45rem; + } + + .site-card-icon { + width: 1.9rem; + height: 1.9rem; + } + + .site-card .site-icon { + font-size: 1.2rem; + } + + .site-card .favicon-icon, + .site-card .icon-placeholder, + .site-card .icon-fallback, + .site-card .icon-container { + width: 1.25rem; + height: 1.25rem; + } + + .site-card .icon-placeholder, + .site-card .icon-fallback { + line-height: 1.25rem; + font-size: 1.1rem; + } + + .site-card h3 { + font-size: 1rem; + margin-bottom: 0.25rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; + } + + .site-card p { + font-size: 0.9rem; + line-height: 1.15; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } +} + +/* 搜索结果页面 */ +#search-results { + position: relative; + width: 100%; + display: none; + flex-direction: column; + align-items: center; + /* 保持在搜索框之下,避免滚动时覆盖 sticky 的搜索容器 */ + z-index: 1; + transform: none !important; + /* 确保没有变换 */ + min-height: 400px; + /* 确保最小高度,防止内容过少时的布局跳动 */ +} + +#search-results.active { + display: flex; + animation: fadeIn 0.3s ease-out forwards; +} + +/* 搜索结果区域 */ +.search-section { + width: 100%; + max-width: var(--page-max-width); + margin: 0 auto 2.5rem auto; + position: relative; + z-index: 1; + transform: none !important; + opacity: 1 !important; +} + +/* 确保搜索结果中的网格有正确的间距 */ +.search-section .sites-grid { + margin-top: 1rem; +} + +/* 搜索结果页:按来源页面复用对应网格规则(方案 2:复用原卡片 DOM) */ +#search-results [data-section='projects'] .sites-grid { + grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); + gap: 24px; +} + +#search-results [data-section='articles'] .sites-grid { + grid-template-columns: repeat(4, minmax(0, 1fr)); +} + +@media (max-width: 1024px) { + #search-results [data-section='articles'] .sites-grid { + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + } +} + +@media (max-width: 480px) { + #search-results [data-section='articles'] .sites-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.5rem; + } +} + +/* 确保搜索结果中的卡片样式一致 */ +.search-section .site-card { + max-width: 100%; +} + +/* 加载中动画 */ +.page { + opacity: 0; + transition: opacity 0.3s ease; +} + +.page.active { + opacity: 1; +} + +/* 模态框动画 */ +@keyframes modalFadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +@keyframes modalContentShow { + from { + opacity: 0; + transform: scale(0.9); + } + + to { + opacity: 1; + transform: scale(1); + } +} + +.sites-grid { + transition: gap 0.3s ease; +} + +/* 侧边栏底部:社交图标(位于 sidebar-footer 上方) */ +.sidebar-social { + grid-area: social; + padding: 0.2rem 1.2rem 0.8rem; + display: flex; + justify-content: center; + flex-wrap: wrap; + gap: 0.9rem; +} + +.social-icon { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.35rem; + border-radius: var(--radius-full); + color: var(--nav-item-color); + text-decoration: none; + transition: + color var(--transition-fast), + transform var(--transition-fast); +} + +.social-icon:hover { + color: var(--accent-color); + transform: translateY(-1px); +} + +.social-icon:active { + transform: translateY(0); +} + +.social-icon:focus-visible { + outline: 2px solid rgba(118, 148, 185, 0.35); + outline-offset: 2px; +} + +.social-icon i { + width: auto; + font-size: 1.2rem; +} + +/* 侧边栏底部:版权信息 */ +.sidebar-footer { + grid-area: footer; + padding: 1rem 1.2rem; + padding-bottom: calc(1rem + env(safe-area-inset-bottom)); + text-align: center; + color: var(--text-muted); + font-size: 0.85rem; + border-top: 1px solid var(--border-color); + background-color: var(--sidebar-bg); + /* 使用变量 */ + transition: + background-color 0.3s ease, + color 0.3s ease, + opacity 0.3s ease; +} + +.sidebar-footer .copyright { + margin: 0; +} + +.sidebar.collapsed .sidebar-social { + padding: 0.2rem 0.5rem 0.8rem; + flex-direction: column; + align-items: center; + gap: 0.6rem; +} + +.copyright a { + color: var(--accent-color); + text-decoration: none; + transition: all 0.3s ease; +} + +.copyright a:hover { + color: var(--accent-hover); + text-decoration: underline; +} + +/* 导航项包装器 - 包含导航项和子菜单 */ +.nav-item-wrapper { + position: relative; + display: flex; + flex-direction: column; + width: 100%; +} + +/* 子菜单容器 */ +.submenu { + max-height: 0; + overflow: hidden; + transition: max-height 0.3s ease; + margin-left: 1.5rem; + opacity: 0; + visibility: hidden; +} + +/* 子菜单展开状态 */ +.nav-item-wrapper.expanded .submenu { + max-height: none; + overflow: visible; + opacity: 1; + visibility: visible; +} diff --git a/assets/styles/_modal.css b/assets/styles/_modal.css new file mode 100644 index 0000000..198e927 --- /dev/null +++ b/assets/styles/_modal.css @@ -0,0 +1,152 @@ +/* Modal & Forms */ + +/* 模态框样式 */ +.modal { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.6); + display: none; + justify-content: center; + align-items: center; + z-index: 1000; +} + +.modal.active { + display: flex; + animation: modalFadeIn 0.3s ease-out forwards; +} + +.modal-content { + background-color: var(--sidebar-bg); + border-radius: var(--radius-xl); + padding: var(--spacing-xl); + width: 90%; + max-width: 520px; + position: relative; + box-shadow: 0 8px 32px var(--shadow-color); + transform: scale(0.95); + opacity: 0; + animation: modalContentShow 0.3s ease-out forwards; + transition: background-color 0.3s ease; +} + +.modal-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 2rem; +} + +.modal-header h3 { + color: var(--text-bright); + font-size: 1.3rem; + letter-spacing: 0.3px; + font-weight: 500; + transition: color 0.3s ease; +} + +.close-modal { + background: none; + border: none; + color: var(--text-muted); + cursor: pointer; + font-size: 1.5rem; + padding: var(--spacing-sm); + transition: all var(--transition-normal); + border-radius: var(--radius-md); +} + +.close-modal:hover { + color: var(--text-bright); + background-color: var(--secondary-bg); +} + +/* 表单样式 */ +.site-form { + display: flex; + flex-direction: column; + gap: 1.2rem; +} + +.form-group { + display: flex; + flex-direction: column; + gap: 0.6rem; +} + +.form-group label { + color: var(--text-muted); + font-size: 0.95rem; + letter-spacing: 0.2px; + transition: color 0.3s ease; +} + +.form-group input, +.form-group select { + background-color: var(--secondary-bg); + border: 1px solid transparent; + border-radius: var(--radius-md); + padding: var(--spacing-md) var(--spacing-lg); + color: var(--text-color); + font-size: 1rem; + transition: all var(--transition-normal); + box-shadow: 0 2px 6px var(--shadow-color); +} + +.form-group input:focus, +.form-group select:focus { + outline: none; + background-color: var(--secondary-bg); + border-color: var(--accent-color); + box-shadow: 0 2px 8px rgba(118, 148, 185, 0.15); +} + +.form-group input::placeholder { + color: var(--text-muted); +} + +.form-actions { + display: flex; + justify-content: flex-end; + gap: 1rem; + margin-top: 2rem; +} + +.btn { + padding: var(--spacing-md) var(--spacing-xl); + border: none; + border-radius: var(--radius-md); + cursor: pointer; + font-size: 1rem; + font-weight: 500; + letter-spacing: 0.3px; + transition: all var(--transition-normal); + transition-timing-function: var(--transition-bounce); + box-shadow: 0 2px 6px var(--shadow-color); +} + +.btn-primary { + background-color: var(--accent-color); + color: var(--white-color); +} + +.btn-primary:hover { + background-color: var(--accent-hover); + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(118, 148, 185, 0.2); +} + +.btn-secondary { + background-color: var(--secondary-bg); + color: var(--text-muted); +} + +.btn-secondary:hover { + background-color: var(--secondary-bg); + color: var(--text-bright); + transform: translateY(-2px); + box-shadow: 0 4px 12px var(--shadow-color); +} diff --git a/assets/styles/_search.css b/assets/styles/_search.css new file mode 100644 index 0000000..2bc9adf --- /dev/null +++ b/assets/styles/_search.css @@ -0,0 +1,306 @@ +/* ============================================ + Search Box Component + ============================================ */ + +/* 搜索框容器 - 固定在顶部 */ +.search-container { + width: 100%; + display: flex; + justify-content: center; + padding: 0 2rem; + margin-bottom: 1rem; + position: sticky; + top: 0; + /* 搜索框必须始终位于页面内容之上,避免搜索结果卡片滚动时遮挡 */ + z-index: 200; +} + +/* 分类切换按钮 */ +.category-toggle { + position: fixed; + bottom: 5rem; + right: var(--spacing-xl); + width: 2.5rem; + height: 2.5rem; + border-radius: var(--radius-lg); + background: rgba(var(--card-bg-rgb), 0.65); + border: 1px solid var(--border-color); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + color: var(--text-color); + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all var(--transition-normal); + transition-timing-function: var(--transition-bounce); + z-index: 100; + box-shadow: 0 4px 16px var(--shadow-color); +} + +.category-toggle:hover { + transform: translateY(-2px); + background: rgba(var(--card-bg-rgb), 0.75); + box-shadow: 0 6px 20px var(--shadow-color); + color: var(--accent-color); +} + +.category-toggle:active { + transform: translateY(0); + box-shadow: 0 2px 8px var(--shadow-color); +} + +.category-toggle i { + font-size: 18px; +} + +/* 搜索框 */ +.search-box { + position: relative; + width: 100%; + max-width: 600px; + display: flex; + align-items: stretch; + --search-status-right: 0.9rem; + --search-hint-right: 1.6rem; + background: rgba(var(--card-bg-rgb), 0.65); + border: 1px solid var(--border-color); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border-radius: var(--radius-lg); + box-shadow: 0 4px 16px var(--shadow-color); + transition: + background var(--transition-normal), + border-color var(--transition-normal), + box-shadow var(--transition-normal); +} + +.search-box:focus-within { + border-color: rgba(var(--accent-rgb), 0.55); + box-shadow: + 0 0 0 1px rgba(var(--accent-rgb), 0.28), + 0 0 18px rgba(var(--accent-rgb), 0.18), + 0 6px 24px var(--shadow-color); +} + +.search-box::after { + content: ''; + position: absolute; + right: var(--search-status-right); + top: 50%; + transform: translateY(-50%); + width: 6px; + height: 6px; + border-radius: 50%; + opacity: 0; + transition: all var(--transition-normal); + pointer-events: none; +} + +.search-box.has-results::after { + background-color: var(--success-color); + opacity: 1; +} + +.search-box.no-results::after { + background-color: var(--error-color); + opacity: 1; +} + +.search-box input { + flex: 1; + min-width: 0; + width: 100%; + padding: var(--spacing-md) calc(var(--spacing-lg) + 4.8rem) var(--spacing-md) var(--spacing-md); + border: none; + border-radius: 0 var(--radius-lg) var(--radius-lg) 0; + background-color: transparent; + color: var(--text-color); + font-family: inherit; + font-weight: inherit; + font-size: 1rem; + transition: + background-color var(--transition-normal), + color var(--transition-normal); + box-shadow: none; +} + +.search-box input:focus { + outline: none; + background-color: rgba(var(--card-bg-rgb), 0.25); + box-shadow: none; +} + +.search-box input::placeholder { + color: var(--text-muted); + font-family: inherit; + font-weight: inherit; +} + +.search-shortcut-hint { + position: absolute; + top: 50%; + right: var(--search-hint-right); + transform: translateY(-50%); + padding: 0.1rem 0.4rem; + border: 1px solid var(--border-color); + border-radius: var(--radius-md); + background: rgba(var(--card-bg-rgb), 0.25); + font-size: 0.78rem; + line-height: 1.2; + color: var(--text-muted); + opacity: 0.65; + pointer-events: none; + user-select: none; +} + +.search-box:focus-within .search-shortcut-hint { + opacity: 0.85; +} + +/* 搜索引擎前缀按钮(方案B:输入框前缀一体化) */ +.search-engine-button { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0 0.75rem; + width: 120px; + flex: 0 0 120px; + border: none; + border-right: 1px solid var(--border-color); + border-radius: var(--radius-lg) 0 0 var(--radius-lg); + background: transparent; + color: var(--text-muted); + cursor: pointer; + font: inherit; + transition: + background var(--transition-normal), + color var(--transition-normal), + transform var(--transition-normal); +} + +.search-engine-button:hover { + background: rgba(var(--card-bg-rgb), 0.25); +} + +.search-engine-button:focus-visible { + outline: 2px solid var(--accent-color); + outline-offset: 2px; +} + +.search-box:focus-within .search-engine-button { + color: var(--accent-color); +} + +.search-engine-icon { + display: grid; + place-items: center; + height: 1.2em; + width: 1.2em; + min-width: 1.2em; + font-size: 1.25rem; + line-height: 1; + text-align: center; + flex: 0 0 1.2em; +} + +.search-engine-icon.search-engine-icon-svg { + font-size: 1.25rem; +} + +.search-engine-icon.search-engine-icon-svg svg { + width: 100%; + height: 100%; + display: block; +} + +.search-engine-label { + flex: 1; + min-width: 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + font-size: 0.95rem; +} + +.search-box.dropdown-open .search-engine-button { + background: rgba(var(--card-bg-rgb), 0.25); +} + +/* 搜索引擎下拉菜单 */ +.search-engine-dropdown { + position: absolute; + top: calc(100% + 6px); + left: 0; + background: rgba(var(--card-bg-rgb), 0.9); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border-radius: var(--radius-md); + box-shadow: 0 4px 15px var(--shadow-color); + display: none; + z-index: 100; + padding: 0.35rem; + border: 1px solid var(--border-color); + min-width: 190px; + flex-direction: column; + gap: 0.25rem; +} + +.search-engine-dropdown.active { + display: flex; + animation: fadeIn 0.2s ease-out forwards; +} + +.search-engine-option { + display: flex; + align-items: center; + justify-content: flex-start; + gap: 0.6rem; + width: 100%; + height: 40px; + padding: 0 0.75rem; + border: none; + border-radius: var(--radius-md); + cursor: pointer; + transition: all 0.2s ease; + background: transparent; + color: var(--text-color); + font: inherit; +} + +.search-engine-option:hover { + background: rgba(var(--card-bg-rgb), 0.22); +} + +.search-engine-option:focus-visible { + outline: 2px solid var(--accent-color); + outline-offset: 2px; +} + +.search-engine-option.active { + background-color: var(--secondary-bg); + color: var(--text-bright); +} + +.search-engine-option i { + display: grid; + place-items: center; + position: static; + transform: none; + font-size: 1.25rem; + width: 1.35em; + height: 1.35em; + line-height: 1; + text-align: center; + flex: 0 0 1.35em; +} + +.search-engine-option i.search-engine-option-svg svg { + width: 100%; + height: 100%; + display: block; +} + +.search-engine-option-label { + font-size: 0.95rem; +} diff --git a/assets/styles/_sidebar.css b/assets/styles/_sidebar.css new file mode 100644 index 0000000..4546d2c --- /dev/null +++ b/assets/styles/_sidebar.css @@ -0,0 +1,613 @@ +/* ============================================ + Sidebar Component + ============================================ */ + +/* 侧边栏样式 */ +.sidebar { + width: var(--sidebar-width); + background-color: var(--sidebar-bg); + position: fixed; + top: 0; + left: 0; + bottom: 0; + box-shadow: 2px 0 10px var(--shadow-color); + z-index: 100; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + transform: translateZ(0); + height: var(--app-height, 100vh); + display: grid; + grid-template-rows: auto 1fr auto auto; + grid-template-areas: + 'header' + 'content' + 'social' + 'footer'; + scrollbar-width: thin; + scrollbar-color: var(--scrollbar-color) transparent; + overflow-y: hidden; + transition: background-color var(--transition-normal); +} + +/* 侧边栏折叠状态 */ +.sidebar.collapsed { + width: var(--sidebar-collapsed-width); + overflow-x: hidden; +} + +/* 优化侧边栏折叠时的Logo部分 */ +.sidebar.collapsed .logo { + padding: 1.2rem 0.5rem 0.6rem; + justify-content: center; + display: flex; + align-items: center; + height: 3.75rem; + /* 确保与展开状态高度一致 */ + margin-bottom: 0.8rem; + /* 收起态同样拉开与按钮的间距 */ +} + +/* 调整折叠侧边栏的部分元素间距 */ +.sidebar.collapsed .nav-section { + gap: 2px; +} + +/* 折叠状态下隐藏底部版权区域(不占位) */ +.sidebar.collapsed .sidebar-footer { + padding: 0; + height: 0; + min-height: 0; + margin: 0; + overflow: hidden; + border: none; +} + +/* 侧边栏头部区域 */ +.sidebar .logo { + grid-area: header; + padding: 1.2rem 1.2rem 0.6rem; + /* 调整上下padding更紧凑 */ + display: flex; + align-items: center; + overflow: hidden; + /* 防止内容溢出 */ + position: relative; + /* 添加相对定位,作为按钮的参考 */ + height: 3.75rem; + /* 固定高度 60px */ + margin-bottom: 0.8rem; + /* 与下方按钮区域拉开间距 */ + transition: padding 0.3s ease; + /* 添加padding过渡,避免突变 */ +} + +.logo-brand { + display: flex; + align-items: center; + gap: 0.6rem; + min-width: 0; + flex: 1; + padding-right: 2.2rem; + /* 预留右侧折叠按钮空间 */ +} + +.logo-brand h1 { + padding-left: 0; +} + +.logo-image { + width: 26px; + height: 26px; + flex-shrink: 0; +} + +.sidebar.collapsed .logo-image { + display: none; +} + +.logo h1 { + font-size: 1.4rem; + color: var(--text-bright); + margin-bottom: 0; + padding-left: 0.5rem; + letter-spacing: 0.5px; + transition: + opacity 0.3s ease, + transform 0.3s ease; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + flex: 1; +} + +/* 侧边栏折叠按钮 */ +.sidebar-toggle { + background: transparent; + border: none; + color: var(--accent-color); + height: 28px; + width: 28px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: background 0.3s ease; + /* 只过渡背景色,移除all避免位置过渡 */ + padding: 0; + flex-shrink: 0; + /* 防止按钮被压缩 */ + position: absolute; + /* 在两种状态下都使用绝对定位 */ + right: 1.2rem; + /* 展开状态下固定在右侧 */ + top: 60%; + transform: translateY(-50%); + /* 垂直居中 */ +} + +.sidebar-toggle .toggle-icon { + font-size: 0.9rem; + transition: transform 0.3s ease; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; +} + +.sidebar-toggle:hover { + background: var(--secondary-bg); +} + +.sidebar-toggle:active { + background: var(--secondary-bg); +} + +/* 收起状态下按钮居中 */ +.sidebar.collapsed .sidebar-toggle { + left: 50%; + /* 水平居中 */ + right: auto; + /* 移除右侧定位 */ + transform: translate(-50%, -50%); + /* 同时水平和垂直居中 */ +} + +.sidebar.collapsed .sidebar-toggle:hover { + background: var(--secondary-bg); +} + +.sidebar.collapsed .sidebar-toggle:active { + background: var(--secondary-bg); +} + +/* 侧边栏折叠状态下的按钮图标旋转180度 */ +.sidebar.collapsed .toggle-icon { + transform: rotate(180deg); +} + +/* 侧边栏内容区域:导航项常驻显示,分类列表在独立面板内滚动 */ +.sidebar-content { + grid-area: content; + min-height: 0; + /* 允许在 CSS Grid 内正确收缩与滚动,避免把 footer 挤出可视区域 */ + overflow: hidden; + /* 导航项常驻显示,分类列表在独立面板内滚动 */ + padding: 0 1.2rem; + display: flex; + flex-direction: column; + gap: 0.6rem; + /* 从1rem减小到0.6rem */ +} + +.sidebar-content::-webkit-scrollbar { + display: none; + /* Webkit browsers(默认不滚动,保留兼容) */ +} + +/* 展开态:子菜单不在导航项内部展开,改在独立面板展示(避免把"页面列表"挤出首屏) */ +.sidebar:not(.collapsed) .nav-item-wrapper > .submenu { + display: none; +} + +/* 侧边栏:页面分类面板(容器本身可滚动,隐藏滚动条) */ +.sidebar-submenu-panel { + flex: 1 1 auto; + min-height: 0; + overflow-y: auto; + padding: 0 0 0.6rem; + /* 移除顶部 padding,避免标题上方出现缝隙 */ + scrollbar-width: none; + /* Firefox 隐藏滚动条 */ +} + +.sidebar-submenu-panel:empty { + display: none; +} + +.sidebar-submenu-panel::-webkit-scrollbar { + display: none; + /* Webkit 浏览器隐藏滚动条 */ +} + +/* 面板内的 submenu 始终可见(不依赖 wrapper.expanded) */ +.sidebar-submenu-panel .submenu { + max-height: none; + overflow: visible; + opacity: 1; + visibility: visible; + margin-left: 0; + transition: none; +} + +/* 折叠状态下的内容区域调整 */ +.sidebar.collapsed .sidebar-content { + padding: 0 0.5rem; + overflow-y: auto; + overflow-x: hidden; + scrollbar-width: none; + /* 隐藏滚动条 */ +} + +.sidebar.collapsed .sidebar-content::-webkit-scrollbar { + display: none; + /* 隐藏WebKit浏览器的滚动条 */ +} + +.sidebar.collapsed .sidebar-submenu-panel { + display: none; +} + +/* 子菜单标题:默认隐藏(在导航栏内折叠时) */ +.submenu-header { + display: none; + font-size: 0.85rem; + font-weight: 500; + text-transform: uppercase; + color: var(--text-muted); + letter-spacing: 0.5px; + padding: 0.8rem 1rem 0.6rem; + margin-bottom: 0.2rem; + border-bottom: 1px solid var(--border-color); + transition: + color var(--transition-normal), + background-color var(--transition-normal), + border-bottom-color var(--transition-normal); + opacity: 0.8; +} + +/* 当子菜单在面板中显示时:显示标题并固定在顶部 */ +.sidebar-submenu-panel .submenu-header { + display: block; + position: sticky; + top: 0; + margin-top: 0; + margin-bottom: 0.2rem; + /* 覆盖基础样式的 margin-bottom */ + background-color: var(--sidebar-bg); + opacity: 1; + /* 覆盖基础样式的半透明,确保背景完全不透明 */ + z-index: 1; + /* 确保标题在滚动时覆盖下方内容 */ +} + +/* 子菜单项样式优化 */ +.submenu-item { + display: flex; + align-items: center; + gap: 0.8rem; + padding: 0.6rem 1rem; + color: var(--nav-item-color); + text-decoration: none; + border-radius: var(--radius-md); + transition: all var(--transition-normal); + margin-bottom: 2px; + font-size: 0.95rem; + position: relative; + overflow: hidden; +} + +.submenu-item i { + width: 1.4rem; + text-align: center; + font-size: 1rem; + opacity: 0.8; + transition: transform var(--transition-normal); +} + +.submenu-item span { + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +/* 悬浮状态 */ +.submenu-item:hover { + background-color: var(--secondary-bg); + color: var(--text-bright); + padding-left: 1.2rem; + /* 悬浮时轻微右移增加动感 */ +} + +.submenu-item:hover i { + transform: scale(1.1); + color: var(--accent-color); + opacity: 1; +} + +/* 激活状态 */ +.submenu-item.active { + background-color: rgba(var(--accent-rgb), 0.15); + color: var(--accent-color); + font-weight: 500; +} + +.submenu-item.active i { + color: var(--accent-color); + opacity: 1; +} + +/* 在激活状态左侧添加指示条 */ +.submenu-item.active::before { + content: ''; + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + height: 60%; + width: 3px; + background-color: var(--accent-color); + border-radius: 0 2px 2px 0; +} + +/* 折叠状态下的Logo文本 */ +.sidebar.collapsed .logo h1 { + opacity: 0; + transform: translateX(-20px); + width: 0; + visibility: hidden; + /* 确保完全隐藏,防止干扰布局 */ + pointer-events: none; + /* 禁用交互,避免影响布局 */ +} + +/* 导航区域样式 */ +.nav-section { + display: flex; + flex-direction: column; + gap: 0; + /* wrapper 之间不需要 gap,由 nav-item 的 margin 控制 */ + flex: 0 0 auto; + /* 不伸缩,根据内容大小 */ + overflow: visible; + /* 导航项不滚动,保持常驻显示 */ +} + +.section-title { + font-size: 1rem; + color: var(--accent-color); + padding: 0.4rem 0.5rem; + /* 减小上下padding */ + margin-bottom: 0.2rem; + /* 增大与下方按钮组的间距 */ + display: flex; + align-items: center; + gap: 0.5rem; + transition: color 0.3s ease; +} + +.section-title i { + font-size: 1.2rem; +} + +/* 调整侧边栏折叠状态下的章节标题 */ +.sidebar.collapsed .section-title { + justify-content: center; + /* 统一与展开态的垂直间距 */ + padding: 0.4rem 0; + text-align: center; + margin-bottom: 0.2rem; + /* 与展开态保持一致且更大 */ +} + +.sidebar.collapsed .section-title i { + margin: 0 auto; + font-size: 1.2rem; +} + +/* 折叠状态下的导航项布局优化 */ +.sidebar.collapsed .nav-section { + gap: 0.4rem; + align-items: center; +} + +.sidebar.collapsed .nav-item { + padding: 0; + justify-content: center; + width: 2.75rem; + /* 增大按钮方块尺寸 44px */ + height: 2.75rem; + /* 增大按钮方块尺寸 44px */ + text-align: center; + margin-left: auto; + margin-right: auto; + border-radius: var(--radius-md); + /* 略增圆角 */ + display: flex; + align-items: center; + box-sizing: border-box; +} + +.sidebar.collapsed .nav-item i { + font-size: 1.25rem; + width: auto; + margin: 0; + padding: 0; +} + +.sidebar.collapsed .nav-item .icon-container { + margin: 0; + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; +} + +/* 折叠状态下的导航项文本 */ +.sidebar.collapsed .nav-item .nav-text, +.sidebar.collapsed .nav-item .external-icon { + opacity: 0; + transform: translateX(-10px); + width: 0; + display: none; + /* 完全移除,防止干扰布局 */ + visibility: hidden; +} + +.nav-item { + display: flex; + align-items: center; + height: 44px; + padding: 0 0.9rem; + margin-bottom: 0.4rem; + /* 导航按钮之间的间距 */ + color: var(--nav-item-color); + text-decoration: none; + border-radius: var(--radius-md); + transition: + background-color var(--transition-normal), + color var(--transition-normal), + box-shadow var(--transition-normal); + position: relative; +} + +.nav-item-wrapper:last-child .nav-item { + margin-bottom: 0; + /* 最后一个导航按钮不需要底部间距 */ +} + +.nav-item .icon-container { + width: 24px; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + margin-right: var(--spacing-md); + transition: margin var(--transition-normal); +} + +.nav-item .nav-text { + flex: 1; + transition: + opacity var(--transition-normal), + transform var(--transition-normal); + white-space: nowrap; + overflow: hidden; +} + +.nav-item .external-icon { + font-size: 0.9rem; + opacity: 0.6; + margin-left: 0.5rem; + transition: all var(--transition-normal); +} + +.nav-item:hover { + background-color: var(--secondary-bg); + color: var(--text-bright); +} + +.nav-item:hover .external-icon { + opacity: 1; + transform: translateX(2px); +} + +.nav-item.active { + background-color: var(--secondary-bg); + color: var(--text-bright); +} + +.nav-item i { + width: 20px; + text-align: center; +} + +/* 折叠状态下:底部区域不可见且不可交互 */ +.sidebar.collapsed .sidebar-footer { + visibility: hidden; + pointer-events: none; +} + +/* 主内容区域 - 修复滚动条问题 */ +main.content { + flex: 1; + margin-left: var(--sidebar-width); + padding: 1.5rem 1rem; + background-color: var(--bg-color); + position: relative; + height: var(--app-height, 100vh); + /* 固定高度(移动端避免 100vh 问题) */ + overflow-y: auto; + /* 使用auto替代scroll,只在需要时显示滚动条 */ + overflow-x: hidden; + width: calc(100vw - var(--sidebar-width)); + display: flex; + flex-direction: column; + align-items: center; + /* 防止"有无滚动条"导致内容横向平移(支持的浏览器会稳定预留滚动条槽位) */ + scrollbar-gutter: stable; + /* 自定义滚动条颜色(Firefox) */ + scrollbar-width: thin; + scrollbar-color: var(--scrollbar-color) transparent; +} + +/* 自定义滚动条(Chromium / Safari) */ +main.content::-webkit-scrollbar { + width: 8px; +} + +main.content::-webkit-scrollbar-track { + background: transparent; +} + +main.content::-webkit-scrollbar-thumb { + background-color: var(--scrollbar-color); + border-radius: var(--radius-full); + /* 用透明边框制造"内边距",更贴合卡片阴影风格 */ + border: 2px solid transparent; + background-clip: content-box; +} + +main.content::-webkit-scrollbar-thumb:hover { + background-color: var(--scrollbar-hover-color); +} + +/* 回退:不支持 scrollbar-gutter 的浏览器,强制始终显示滚动条以避免横向抖动 */ +@supports not (scrollbar-gutter: stable) { + main.content { + overflow-y: scroll; + } +} + +/* 优化内容区域在侧边栏折叠状态下的边距 */ +body main.content.expanded { + margin-left: var(--sidebar-collapsed-width); + width: calc(100vw - var(--sidebar-collapsed-width)); +} + +/* 仅在交互时启用布局相关过渡,避免首帧闪烁 */ +.with-anim .sidebar { + transition: + width 0.3s ease, + background-color 0.3s ease; +} + +.with-anim main.content { + transition: + background-color 0.3s ease, + margin-left 0.3s ease, + width 0.3s ease; +} diff --git a/assets/styles/_variables.css b/assets/styles/_variables.css new file mode 100644 index 0000000..7d6b6c2 --- /dev/null +++ b/assets/styles/_variables.css @@ -0,0 +1,147 @@ +/* ============================================ + CSS Variables & Theme System + ============================================ */ + +/* 主题颜色变量 - Apple Design System */ +:root { + /* 深色主题 (iOS Dark Mode Inspired) */ + --bg-color: #000000; + /* Pure Black background */ + --sidebar-bg: #1c1c1e; + /* System Gray 6 */ + --secondary-bg: #2c2c2e; + /* System Gray 5 */ + + /* 卡片背景 - 仪表盘卡片 */ + --card-bg-gradient-1: #1c1c1e; + --card-bg-gradient-2: #1c1c1e; + + /* 站点卡片 - 提升亮度以区分层级 (Optimize: Use System Gray 5 for cards on black bg) */ + --site-card-bg-gradient-1: #2c2c2e; + --site-card-bg-gradient-2: #2c2c2e; + --site-card-hover-bg: #3a3a3c; + /* System Gray 4 for hover */ + + /* 文字颜色 */ + --text-color: #ffffff; + --text-muted: #8e8e93; + /* System Gray */ + --text-bright: #ffffff; + + /* 边框与阴影 */ + --border-color: rgba(255, 255, 255, 0.12); + --shadow-color: rgba(0, 0, 0, 0.3); + + /* 功能色 */ + --highlight-bg: rgba(118, 148, 185, 0.3); + /* Restore original Highlight */ + --scrollbar-color: rgba(255, 255, 255, 0.2); + --scrollbar-hover-color: rgba(255, 255, 255, 0.3); + + /* 恢复原有强调色 (Restore Original Accent) */ + --accent-color: #7694b9; + --accent-hover: #6684a9; + --accent-rgb: 118, 148, 185; + + --nav-item-color: #98989d; + --success-color: #30d158; + --error-color: #ff453a; + --white-color: #ffffff; + + /* 恢复原有渐变 (Restore Original Gradient) */ + --gradient-color: linear-gradient(135deg, #7694b9 0%, #a855f7 50%, #ff6b6b 100%); + --gradient-color-simple: linear-gradient(135deg, #7694b9 0%, #a855f7 100%); + + --sidebar-width: 240px; + --sidebar-collapsed-width: 60px; + --app-height: 100vh; + + /* Spacing System */ + --spacing-xs: 0.25rem; + --spacing-sm: 0.5rem; + --spacing-md: 1rem; + --spacing-lg: 1.5rem; + --spacing-xl: 2rem; + --spacing-2xl: 3rem; + + --page-max-width: 1300px; + + /* UI Tuning - Apple Style (Kept) */ + --radius-sm: 6px; + --radius-md: 10px; + --radius-lg: 14px; + --radius-xl: 20px; + --radius-full: 9999px; + + /* Transitions - Kept iOS Spring */ + --transition-fast: 0.2s ease; + --transition-normal: 0.35s cubic-bezier(0.25, 1, 0.5, 1); + --transition-slow: 0.5s cubic-bezier(0.25, 1, 0.5, 1); + --transition-bounce: cubic-bezier(0.175, 0.885, 0.32, 1.275); + + --card-bg-rgb: 28, 28, 30; +} + +/* 浅色主题 - 恢复原有配色 (Restored Morandi/Warm) */ +html.theme-preload, +body.light-theme { + --bg-color: #e0e0d8; + --sidebar-bg: #f0f0eb; + --secondary-bg: #e6e6e1; + /* Slightly darker than sidebar for hover state */ + --card-bg-gradient-1: #f0f0eb; + --card-bg-gradient-2: #e9e9e4; + --site-card-bg-gradient-1: #ffffff; + --site-card-bg-gradient-2: #f4f5f0; + --site-card-hover-bg: linear-gradient(145deg, #fafaf8, #eef0eb); + + --text-color: #333333; + --text-muted: #666666; + --text-bright: #000000; + + --border-color: rgba(0, 0, 0, 0.08); + --shadow-color: rgba(0, 0, 0, 0.1); + + --highlight-bg: rgba(118, 148, 185, 0.15); + --scrollbar-color: rgba(0, 0, 0, 0.1); + --scrollbar-hover-color: rgba(0, 0, 0, 0.2); + + --accent-color: #7694b9; + --accent-hover: #6684a9; + --accent-rgb: 118, 148, 185; + + --nav-item-color: #666666; + --success-color: #4caf50; + --error-color: #f44336; + --white-color: #ffffff; + + /* Restore original gradients */ + --gradient-color: linear-gradient(135deg, #7694b9 0%, #a855f7 50%, #ff6b6b 100%); + --gradient-color-simple: linear-gradient(135deg, #7694b9 0%, #a855f7 100%); + + --card-bg-rgb: 240, 240, 235; +} + +/* 预加载主题 - 在JS完全加载前显示正确的主题 */ +html.theme-preload body { + background-color: #e0e0d8; + color: #333333; +} + +/* 预加载侧边栏状态 - 在JS完全加载前显示正确的侧边栏宽度 */ +html.sidebar-collapsed-preload .sidebar { + width: var(--sidebar-collapsed-width); +} + +html.sidebar-collapsed-preload main.content { + margin-left: var(--sidebar-collapsed-width); +} + +/* 控制页面预加载状态 */ +html.preload .layout { + opacity: 0; +} + +html.preload * { + transition: none !important; +} diff --git a/src/generator/main.js b/src/generator/main.js index 13c603a..b94518c 100644 --- a/src/generator/main.js +++ b/src/generator/main.js @@ -125,6 +125,65 @@ function generateHTML(config) { } } +/** + * 使用 esbuild bundle 模式合并 CSS @import + * 注意:transformSync 不支持 bundle,必须用 buildSync + * @param {string} srcPath - 源 CSS 文件路径 + * @param {string} destPath - 目标文件路径 + * @returns {boolean} 是否成功 + */ +function tryBundleCss(srcPath, destPath) { + let esbuild; + try { + esbuild = require('esbuild'); + } catch { + return false; + } + + try { + // buildSync 需要绝对路径 + const absoluteSrc = path.resolve(srcPath); + const absoluteDest = path.resolve(destPath); + + esbuild.buildSync({ + entryPoints: [absoluteSrc], + outfile: absoluteDest, + bundle: true, // 关键:合并 @import + minify: true, + logLevel: 'silent', + }); + return true; + } catch (error) { + const log = createLogger('assets'); + log.warn('CSS bundle 失败,降级为复制', { + message: error && error.message ? error.message : String(error), + }); + if (isVerbose() && error && error.stack) console.error(error.stack); + return false; + } +} + +/** + * 递归复制目录(降级方案:当 esbuild 不可用时复制 styles 目录) + * @param {string} src - 源目录 + * @param {string} dest - 目标目录 + */ +function copyDirRecursive(src, dest) { + if (!fs.existsSync(src)) return; + fs.mkdirSync(dest, { recursive: true }); + + for (const entry of fs.readdirSync(src, { withFileTypes: true })) { + const srcPath = path.join(src, entry.name); + const destPath = path.join(dest, entry.name); + + if (entry.isDirectory()) { + copyDirRecursive(srcPath, destPath); + } else { + fs.copyFileSync(srcPath, destPath); + } + } +} + function tryMinifyStaticAsset(srcPath, destPath, loader) { let esbuild; try { @@ -162,10 +221,13 @@ function copyStaticFiles(config) { fs.mkdirSync('dist', { recursive: true }); } - // 复制 CSS 文件 + // 复制 CSS 文件(支持模块化 @import) try { - if (!tryMinifyStaticAsset('assets/style.css', 'dist/style.css', 'css')) { + if (!tryBundleCss('assets/style.css', 'dist/style.css')) { + // 降级:复制入口 + styles 目录 fs.copyFileSync('assets/style.css', 'dist/style.css'); + copyDirRecursive('assets/styles', 'dist/styles'); + log.warn('CSS 未合并,浏览器将发起多个请求'); } } catch (e) { log.error('复制 style.css 失败', { message: e && e.message ? e.message : String(e) }); diff --git a/templates/README.md b/templates/README.md index 8d1bb0b..30a3df6 100644 --- a/templates/README.md +++ b/templates/README.md @@ -143,6 +143,7 @@ templates/ **主要组件**: - `page-header.hbs` - 统一页面标题区(首页/非首页/书签更新时间/项目热力图) +- `home-dashboard.hbs` - 首页仪表盘(时钟卡片、TODO 待办卡片) - `navigation.hbs` - 导航菜单 - `site-card.hbs` - 站点卡片 - `category.hbs` - 分类容器(支持多层级嵌套)