From 52c4370b471d7f541ecbddf804955b855bfbcc09 Mon Sep 17 00:00:00 2001 From: Ziphyrien <2697860027@qq.com> Date: Sun, 30 Nov 2025 16:41:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=20Citizen=20?= =?UTF-8?q?=E7=9A=AE=E8=82=A4=E9=A3=8E=E6=A0=BC=20(=E5=9E=82=E7=9B=B4?= =?UTF-8?q?=E4=BE=A7=E8=BE=B9=E6=A0=8F=E3=80=81=E6=90=9C=E7=B4=A2=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=E3=80=81=E6=8F=90=E7=A4=BA=E6=A1=86=E4=BC=98=E5=8C=96?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/css/base/theme.css | 509 ++------------ src/css/base/variables.css | 283 ++++---- src/css/components/alert.css | 15 + src/css/components/layout.css | 75 +++ src/css/components/navbar.css | 458 ++++--------- src/css/components/sidebar.css | 29 +- src/css/custom.css | 21 + src/css/utilities/search.css | 321 ++++----- src/pages/index.module.scss | 629 ++++-------------- src/pages/index.tsx | 212 ++---- src/theme/Navbar/ColorModeToggle/index.tsx | 27 + .../Navbar/ColorModeToggle/styles.module.css | 3 + src/theme/Navbar/Content/index.tsx | 107 +++ src/theme/Navbar/Content/styles.module.css | 16 + src/theme/Navbar/Layout/index.tsx | 65 ++ src/theme/Navbar/Layout/styles.module.css | 7 + src/theme/Navbar/Logo/index.tsx | 12 + .../Navbar/MobileSidebar/Header/index.tsx | 33 + .../Navbar/MobileSidebar/Layout/index.tsx | 63 ++ .../MobileSidebar/PrimaryMenu/index.tsx | 31 + .../MobileSidebar/SecondaryMenu/index.tsx | 32 + .../Navbar/MobileSidebar/Toggle/index.tsx | 23 + src/theme/Navbar/MobileSidebar/index.tsx | 44 ++ src/theme/Navbar/Search/index.tsx | 13 + src/theme/Navbar/Search/styles.module.css | 20 + src/theme/Navbar/index.tsx | 37 +- 26 files changed, 1331 insertions(+), 1754 deletions(-) create mode 100644 src/css/components/layout.css create mode 100644 src/theme/Navbar/ColorModeToggle/index.tsx create mode 100644 src/theme/Navbar/ColorModeToggle/styles.module.css create mode 100644 src/theme/Navbar/Content/index.tsx create mode 100644 src/theme/Navbar/Content/styles.module.css create mode 100644 src/theme/Navbar/Layout/index.tsx create mode 100644 src/theme/Navbar/Layout/styles.module.css create mode 100644 src/theme/Navbar/Logo/index.tsx create mode 100644 src/theme/Navbar/MobileSidebar/Header/index.tsx create mode 100644 src/theme/Navbar/MobileSidebar/Layout/index.tsx create mode 100644 src/theme/Navbar/MobileSidebar/PrimaryMenu/index.tsx create mode 100644 src/theme/Navbar/MobileSidebar/SecondaryMenu/index.tsx create mode 100644 src/theme/Navbar/MobileSidebar/Toggle/index.tsx create mode 100644 src/theme/Navbar/MobileSidebar/index.tsx create mode 100644 src/theme/Navbar/Search/index.tsx create mode 100644 src/theme/Navbar/Search/styles.module.css diff --git a/src/css/base/theme.css b/src/css/base/theme.css index 4b8497d1b..333aef511 100644 --- a/src/css/base/theme.css +++ b/src/css/base/theme.css @@ -1,224 +1,23 @@ /* ====================================== - NitWikit 主题系统 - 暗色模式 - 借鉴 Nuxt 深邃暗色设计 + NitWikit Theme System - Animations & Overrides + Citizen Skin Adaptation ====================================== */ /* ====================================== - 暗色模式变量覆盖 + Theme Transition Animations + (Waterfall effect from previous theme) ====================================== */ -[data-theme="dark"] { - /* 主色调 - 暗色模式稍亮以保持对比 */ - --primary: var(--green-500); - --primary-dark: var(--green-600); - --primary-light: var(--green-400); - /* 暗色模式下文字主色更亮 */ - --primary-text: var(--green-400); - /* 文字颜色 - 提升对比度 */ - --text-primary: var(--slate-100); - --text-secondary: var(--slate-300); - --text-light: var(--slate-400); - --text-muted: var(--slate-400); - - /* 背景颜色 - 深邃层次 (Nuxt 风格) */ - --bg-base: var(--slate-950); - --bg-light: var(--slate-950); - --bg-muted: var(--slate-900); - --bg-card: var(--slate-900); - --bg-elevated: var(--slate-800); - --bg-dark: var(--slate-950); - --bg-footer: var(--slate-950); - - /* 边框颜色 */ - --border: var(--slate-800); - --border-light: var(--slate-900); - --border-dark: var(--slate-700); - - /* 阴影 - 暗色模式下更柔和 */ - --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.3); - --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.4), 0 1px 2px rgba(0, 0, 0, 0.3); - --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.3); - --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.3); - --shadow-glow: 0 0 30px rgba(0, 220, 130, 0.12); - - /* 提示框暗色 - 增强可见度 */ - --alert-info: #60a5fa; - --alert-info-bg: rgba(96, 165, 250, 0.15); - --alert-warning: #fbbf24; - --alert-warning-bg: rgba(251, 191, 36, 0.15); - --alert-danger: #f87171; - --alert-danger-bg: rgba(248, 113, 113, 0.15); - --alert-success: #34d399; - --alert-success-bg: rgba(52, 211, 153, 0.15); - --alert-note: #a78bfa; - --alert-note-bg: rgba(167, 139, 250, 0.15); - - /* Docusaurus 变量覆盖 */ - --ifm-background-color: var(--bg-light); - --ifm-background-surface-color: var(--bg-card); - --ifm-navbar-background-color: rgba(2, 6, 23, 1); - --ifm-font-color-base: var(--text-primary); - --ifm-heading-color: var(--text-primary); - - --ifm-color-primary: var(--primary); - --ifm-color-primary-dark: var(--primary-dark); - --ifm-color-primary-light: var(--primary-light); - - --ifm-menu-color: var(--text-secondary); - --ifm-toc-border-color: var(--border); -} - -/* ====================================== - 亮色模式背景应用 -====================================== */ -[data-theme="light"] body, -[data-theme="light"] .main-wrapper, -[data-theme="light"] .homepage, -[data-theme="light"] .docMainContainer_gTbr, -[data-theme="light"] article, -[data-theme="light"] .theme-doc-markdown { - background-color: var(--bg-light); -} - -[data-theme="light"] .container { - background-color: transparent; -} - -/* ====================================== - 暗色模式背景应用 -====================================== */ -[data-theme="dark"] body, -[data-theme="dark"] .main-wrapper, -[data-theme="dark"] .docMainContainer_gTbr, -[data-theme="dark"] article, -[data-theme="dark"] .theme-doc-markdown { - background-color: var(--bg-dark); -} - -[data-theme="dark"] .container { - background-color: transparent; -} - -/* ====================================== - 区域渐变分割 (Nuxt 风格) -====================================== */ -.section-gradient { - background: linear-gradient(180deg, var(--bg-muted) 0%, var(--bg-light) 100%); - border-top: 1px solid var(--border); -} - -[data-theme="dark"] .section-gradient { - background: linear-gradient(180deg, rgba(15, 23, 42, 0.4) 0%, var(--bg-dark) 100%); -} - -/* ====================================== - 卡片主题适配 -====================================== */ -[data-theme="dark"] .card { - background-color: var(--bg-card); - border-color: var(--border); -} - -[data-theme="dark"] .card:hover { - border-color: var(--primary-alpha-border); - box-shadow: var(--shadow-glow); -} - -/* ====================================== - 页脚主题适配 -====================================== */ -[data-theme="dark"] .footer__copyright { - border-top-color: var(--border); -} - -/* ====================================== - 代码块主题 -====================================== */ -[data-theme="dark"] pre { - background-color: var(--slate-900) !important; -} - -[data-theme="dark"] :not(pre) > code { - background-color: var(--primary-alpha-15); - color: var(--primary-light); -} - -/* ====================================== - 滚动条主题 -====================================== */ -[data-theme="dark"] ::-webkit-scrollbar-thumb { - background: var(--slate-700); -} - -[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { - background: var(--slate-600); -} - -/* ====================================== - 选择文本主题 -====================================== */ -::selection { - background: var(--primary-alpha-20); - color: inherit; -} - -[data-theme="dark"] ::selection { - background: var(--primary-alpha-30); -} - -/* ====================================== - 链接悬停发光效果 -====================================== */ -[data-theme="dark"] a:hover { - text-shadow: 0 0 10px var(--primary-alpha-30); -} - -/* ====================================== - Ant Design Timeline 暗色模式适配 -====================================== */ -[data-theme="dark"] .ant-timeline { - color: var(--text-primary); -} - -[data-theme="dark"] .ant-timeline-item-content { - color: var(--text-primary); -} - -[data-theme="dark"] .ant-timeline-item-label { - color: var(--text-secondary); -} - -[data-theme="dark"] .ant-timeline-item-tail { - border-inline-start-color: var(--border); -} - -[data-theme="dark"] .ant-timeline-item-head { - background-color: var(--bg-dark); -} - -[data-theme="dark"] .ant-timeline-item-pending .ant-timeline-item-content { - color: var(--text-muted); -} - -/* ====================================== - 主题切换瀑布流动画 - 从上到下的流动过渡效果 -====================================== */ - -/* 定义瀑布流变量 */ :root { --theme-transition-duration: 400ms; --theme-transition-timing: cubic-bezier(0.4, 0, 0.2, 1); } -/* 基础过渡:为所有主题相关属性添加过渡 */ html { transition: background-color var(--theme-transition-duration) var(--theme-transition-timing); - /* 平滑滚动,但尊重用户的动画偏好设置 */ scroll-behavior: smooth; } -/* 如果用户偏好减少动画,则禁用平滑滚动 */ @media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; @@ -229,294 +28,90 @@ body { transition: background-color var(--theme-transition-duration) var(--theme-transition-timing), color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 20ms; } -/* 导航栏 - 最先开始过渡 */ +/* Navbar Transition */ .navbar { transition: background-color var(--theme-transition-duration) var(--theme-transition-timing), border-color var(--theme-transition-duration) var(--theme-transition-timing), - box-shadow var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 0ms; -} - -.navbar__brand, -.navbar__title { - transition: color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 30ms; + backdrop-filter var(--theme-transition-duration) var(--theme-transition-timing); } -.navbar__link { - transition: - color var(--theme-transition-duration) var(--theme-transition-timing), - background-color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 50ms; -} - -/* 主内容区 - 稍后开始 */ -.main-wrapper { - transition: background-color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 40ms; -} - -/* 侧边栏 - 与内容同步 */ -.theme-doc-sidebar-container, -.menu { - transition: - background-color var(--theme-transition-duration) var(--theme-transition-timing), - border-color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 60ms; -} - -.menu__link { - transition: - color var(--theme-transition-duration) var(--theme-transition-timing), - background-color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 80ms; -} - -/* 文档容器 - 主要内容区域 */ -.docMainContainer_gTbr, -article, -.theme-doc-markdown { - transition: background-color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 80ms; -} - -/* 标题层叠过渡 */ -h1, -h2, -h3, -h4, -h5, -h6 { - transition: color var(--theme-transition-duration) var(--theme-transition-timing); -} - -h1 { - transition-delay: 100ms; -} -h2 { - transition-delay: 120ms; -} -h3 { - transition-delay: 140ms; -} -h4 { - transition-delay: 150ms; -} -h5 { - transition-delay: 160ms; -} -h6 { - transition-delay: 170ms; -} - -/* 段落和文字 */ -p, -li, -span, -td, -th { - transition: color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 130ms; -} - -/* 链接 */ -a { - transition: - color var(--theme-transition-duration) var(--theme-transition-timing), - text-shadow var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 140ms; -} - -/* 卡片元素 - 波浪式过渡 */ +/* Card Transitions */ .card { transition: background-color var(--theme-transition-duration) var(--theme-transition-timing), border-color var(--theme-transition-duration) var(--theme-transition-timing), - box-shadow var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 100ms; -} - -/* 为多个卡片添加瀑布延迟 */ -.card:nth-child(1) { - transition-delay: 100ms; -} -.card:nth-child(2) { - transition-delay: 130ms; -} -.card:nth-child(3) { - transition-delay: 160ms; -} -.card:nth-child(4) { - transition-delay: 190ms; -} -.card:nth-child(5) { - transition-delay: 220ms; -} -.card:nth-child(6) { - transition-delay: 250ms; -} -.card:nth-child(7) { - transition-delay: 280ms; -} -.card:nth-child(8) { - transition-delay: 310ms; -} - -/* 代码块 */ -pre, -code { - transition: - background-color var(--theme-transition-duration) var(--theme-transition-timing), - color var(--theme-transition-duration) var(--theme-transition-timing), - border-color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 150ms; -} - -/* 表格 */ -table, -thead, -tbody, -tr, -td, -th { - transition: - background-color var(--theme-transition-duration) var(--theme-transition-timing), - border-color var(--theme-transition-duration) var(--theme-transition-timing), - color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 160ms; + box-shadow var(--theme-transition-duration) var(--theme-transition-timing), + transform 0.2s ease; } -/* 引用块和提示框 */ -blockquote, -.alert, -.admonition { - transition: - background-color var(--theme-transition-duration) var(--theme-transition-timing), - border-color var(--theme-transition-duration) var(--theme-transition-timing), - color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 170ms; -} - -/* 目录导航 */ -.table-of-contents, -.table-of-contents__link { - transition: - color var(--theme-transition-duration) var(--theme-transition-timing), - border-color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 120ms; -} - -/* 页脚 - 最后完成过渡 */ -.footer { - transition: - background-color var(--theme-transition-duration) var(--theme-transition-timing), - border-color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 200ms; -} +/* ====================================== + Component Overrides for Citizen Look +====================================== */ -.footer__link-item, -.footer__copyright { - transition: - color var(--theme-transition-duration) var(--theme-transition-timing), - border-color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 220ms; +/* Code Blocks */ +[data-theme="dark"] pre { + background-color: var(--color-surface-1) !important; + border: 1px solid var(--color-surface-2); } -/* 滚动条 */ -::-webkit-scrollbar-thumb { - transition: background-color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 250ms; +/* Scrollbars */ +::-webkit-scrollbar { + width: 8px; + height: 8px; } ::-webkit-scrollbar-track { - transition: background-color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 260ms; + background: transparent; } -/* 搜索框 */ -.DocSearch, -.DocSearch-Button { - transition: - background-color var(--theme-transition-duration) var(--theme-transition-timing), - border-color var(--theme-transition-duration) var(--theme-transition-timing), - color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 70ms; +::-webkit-scrollbar-thumb { + background: var(--color-surface-3); + border-radius: 4px; } -/* 分页导航 */ -.pagination-nav__link { - transition: - background-color var(--theme-transition-duration) var(--theme-transition-timing), - border-color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 180ms; +::-webkit-scrollbar-thumb:hover { + background: var(--color-surface-4); } -/* 面包屑导航 */ -.breadcrumbs__item, -.breadcrumbs__link { - transition: color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 90ms; +/* Selection */ +::selection { + background: var(--color-progressive); + color: #fff; + background-color: oklch(var(--color-progressive-oklch__l) var(--color-progressive-oklch__c) var(--color-progressive-oklch__h) / 0.3); } -/* 标签 */ -.tag, -.badge { - transition: - background-color var(--theme-transition-duration) var(--theme-transition-timing), - color var(--theme-transition-duration) var(--theme-transition-timing); - transition-delay: 160ms; +/* Links */ +a { + transition: color 0.2s ease; } -/* 主题切换按钮发光效果 */ -button[class*="colorModeToggle"] { - position: relative; +/* Admonitions / Alerts */ +.alert { + border-radius: var(--border-radius-base); + border: 1px solid transparent; } -button[class*="colorModeToggle"]::after { - content: ""; - position: absolute; - inset: -4px; - border-radius: 50%; - background: radial-gradient(circle, var(--primary-alpha-30) 0%, transparent 70%); - opacity: 0; - transform: scale(0.8); - transition: - opacity 300ms ease, - transform 300ms ease; - pointer-events: none; - z-index: -1; +.alert--info { + background-color: oklch(from var(--color-progressive) l c h / 0.1); + border-color: oklch(from var(--color-progressive) l c h / 0.2); + color: var(--color-progressive); } -button[class*="colorModeToggle"]:active::after { - opacity: 1; - transform: scale(1.5); - transition: - opacity 100ms ease, - transform 100ms ease; +/* ====================================== + Image Zoom Recipe +====================================== */ +img { + transition: transform 0.3s ease; } -/* 主题切换涟漪动画 */ -@keyframes themeRipple { - 0% { - transform: scale(0); - opacity: 0.5; - } - 100% { - transform: scale(4); - opacity: 0; - } +img:hover { + transform: var(--transform-image-hover); } -/* 尊重用户减少动画偏好 */ -@media (prefers-reduced-motion: reduce) { - *, - *::before, - *::after { - transition-delay: 0ms !important; - transition-duration: 0.01ms !important; - } +/* Disable zoom for small icons or specific classes if needed */ +.navbar__logo:hover, .footer__logo:hover { + transform: none; } diff --git a/src/css/base/variables.css b/src/css/base/variables.css index 8b84093f6..adb686132 100644 --- a/src/css/base/variables.css +++ b/src/css/base/variables.css @@ -1,159 +1,184 @@ /* ====================================== - NitWikit 设计系统 - CSS 变量 - 借鉴 Nuxt 设计系统 + Citizen Skin Variables for NitWikit + Based on MediaWiki Citizen Skin ====================================== */ :root { /* ====================================== - 主色调 - Nuxt Green (完整色阶) + Citizen: Primary Color (OKLCH) + Default: Purple-ish from documentation example ====================================== */ - --green-50: #effdf5; - --green-100: #d9fbe8; - --green-200: #b3f5d1; - --green-300: #75edae; - --green-400: #00dc82; - --green-500: #00c16a; - --green-600: #00a155; - --green-700: #007f45; - --green-800: #016538; - --green-900: #0a5331; - --green-950: #052e16; - - /* 主色语义化变量 */ - --primary: var(--green-500); - --primary-dark: var(--green-600); - --primary-darker: var(--green-700); - --primary-light: var(--green-400); - --primary-lighter: var(--green-300); - /* 文字专用主色 - 对比度更高 (WCAG AA) */ - --primary-text: var(--green-600); - - /* 主色透明度变体 (简化) */ - --primary-alpha-5: rgba(0, 220, 130, 0.05); - --primary-alpha-8: rgba(0, 220, 130, 0.08); - --primary-alpha-10: rgba(0, 220, 130, 0.1); - --primary-alpha-15: rgba(0, 220, 130, 0.15); - --primary-alpha-20: rgba(0, 220, 130, 0.2); - --primary-alpha-30: rgba(0, 220, 130, 0.3); - --primary-alpha-border: rgba(0, 220, 130, 0.25); + --color-progressive-oklch__l: 53.25%; + --color-progressive-oklch__c: 0.1679; + --color-progressive-oklch__h: 262.29; - /* ====================================== - 中性色 - Slate (完整色阶) - ====================================== */ - --slate-50: #f8fafc; - --slate-100: #f1f5f9; - --slate-200: #e2e8f0; - --slate-300: #cbd5e1; - --slate-400: #94a3b8; - --slate-500: #64748b; - --slate-600: #475569; - --slate-700: #334155; - --slate-800: #1e293b; - --slate-900: #0f172a; - --slate-950: #020617; + --color-progressive: oklch( + var(--color-progressive-oklch__l) + var(--color-progressive-oklch__c) + var(--color-progressive-oklch__h) + ); /* ====================================== - 语义化颜色 (亮色模式) + Citizen: Surface Colors (Light Mode) ====================================== */ - --text-primary: var(--slate-900); - --text-secondary: var(--slate-700); - --text-light: var(--slate-500); - --text-muted: var(--slate-500); - - --bg-base: var(--slate-50); - --bg-light: var(--slate-100); - --bg-muted: var(--slate-200); - --bg-card: #ffffff; - --bg-elevated: #ffffff; - --bg-dark: var(--slate-900); - --bg-footer: var(--slate-100); - - --border: var(--slate-200); - --border-light: var(--slate-100); - --border-dark: var(--slate-300); + --color-surface-0: #ffffff; + --color-surface-1: #f8f9fa; + --color-surface-2: #eaecf0; + --color-surface-3: #dee2e6; + --color-surface-4: #ced4da; /* ====================================== - 阴影系统 + Citizen: Text Colors (Light Mode) ====================================== */ - --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.05); - --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.04); - --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.08), 0 2px 4px -1px rgba(0, 0, 0, 0.04); - --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.08), 0 4px 6px -2px rgba(0, 0, 0, 0.04); - --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.08), 0 10px 10px -5px rgba(0, 0, 0, 0.02); - --shadow-glow: 0 0 20px rgba(0, 220, 130, 0.15); + --color-base: #202122; + --color-emphasized: #000000; + --color-subtle: #54595d; /* ====================================== - 圆角系统 + Citizen: Typography ====================================== */ - --radius-xs: 0.125rem; - --radius-sm: 0.25rem; - --radius-md: 0.375rem; - --radius-lg: 0.5rem; - --radius-xl: 0.75rem; - --radius-2xl: 1rem; - --radius-full: 9999px; + --font-family-citizen-base: 'Inter', 'Roboto', system-ui, -apple-system, sans-serif; + --font-family-citizen-serif: 'Roboto Serif', serif; + --font-family-citizen-monospace: 'JetBrains Mono', 'Roboto Mono', monospace; /* ====================================== - 过渡动画 + Citizen: Layout ====================================== */ - --transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1); - --transition-base: 200ms cubic-bezier(0.4, 0, 0.2, 1); - --transition-slow: 300ms cubic-bezier(0.4, 0, 0.2, 1); - --transition-smooth: 300ms cubic-bezier(0.34, 1.56, 0.64, 1); + --width-layout: 1200px; /* Adjusted for Docusaurus container */ /* ====================================== - 字体系统 + Citizen: Recipes / Customization ====================================== */ - --font-sans: - "Public Sans", "Noto Sans SC", -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", - "Microsoft YaHei", system-ui, sans-serif; - --font-mono: - "Maple Mono NF CN", "JetBrains Mono", "Fira Code", SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", - monospace; + --transform-image-hover: scale(1.02); + --backdrop-filter-frosted-glass: blur(20px) saturate(180%); + --opacity-glass: 0.75; + --border-radius-base: 12px; /* ====================================== - Docusaurus/Infima 变量映射 + Docusaurus / Infima Mapping ====================================== */ - --ifm-color-primary: var(--primary); - --ifm-color-primary-dark: var(--primary-dark); - --ifm-color-primary-darker: var(--primary-darker); - --ifm-color-primary-light: var(--primary-light); - --ifm-color-primary-lighter: var(--primary-lighter); - --ifm-color-primary-lightest: #99f2cd; - - --ifm-code-font-size: 90%; - --ifm-font-family-base: var(--font-sans); - --ifm-font-family-monospace: var(--font-mono); - - --ifm-background-color: var(--bg-light); - --ifm-background-surface-color: var(--bg-card); - - --ifm-navbar-background-color: rgba(255, 255, 255, 1); + --ifm-color-primary: var(--color-progressive); + + /* Generate shades using color-mix (Modern CSS) or calc with OKLCH */ + --ifm-color-primary-dark: oklch(calc(var(--color-progressive-oklch__l) - 5%) var(--color-progressive-oklch__c) var(--color-progressive-oklch__h)); + --ifm-color-primary-darker: oklch(calc(var(--color-progressive-oklch__l) - 10%) var(--color-progressive-oklch__c) var(--color-progressive-oklch__h)); + --ifm-color-primary-darkest: oklch(calc(var(--color-progressive-oklch__l) - 15%) var(--color-progressive-oklch__c) var(--color-progressive-oklch__h)); + --ifm-color-primary-light: oklch(calc(var(--color-progressive-oklch__l) + 5%) var(--color-progressive-oklch__c) var(--color-progressive-oklch__h)); + --ifm-color-primary-lighter: oklch(calc(var(--color-progressive-oklch__l) + 10%) var(--color-progressive-oklch__c) var(--color-progressive-oklch__h)); + --ifm-color-primary-lightest: oklch(calc(var(--color-progressive-oklch__l) + 15%) var(--color-progressive-oklch__c) var(--color-progressive-oklch__h)); + + --ifm-background-color: var(--color-surface-0); + --ifm-background-surface-color: var(--color-surface-1); + + --ifm-font-color-base: var(--color-base); + --ifm-heading-color: var(--color-emphasized); + + --ifm-font-family-base: var(--font-family-citizen-base); + --ifm-font-family-monospace: var(--font-family-citizen-monospace); + + --ifm-navbar-background-color: var(--color-surface-1); --ifm-navbar-height: 4rem; - --ifm-navbar-shadow: none; - --ifm-navbar-padding-vertical: 0; - --ifm-navbar-padding-horizontal: 1.5rem; - - --ifm-menu-color: var(--text-secondary); - --ifm-menu-color-active: var(--primary); - --ifm-menu-color-background-active: var(--primary-alpha-10); - --ifm-menu-color-background-hover: var(--primary-alpha-5); - - --ifm-toc-border-color: var(--border); - --ifm-heading-color: var(--text-primary); - --ifm-font-color-base: var(--text-primary); + + /* Borders */ + --ifm-border-color: var(--color-surface-3); /* ====================================== - 提示框颜色 (亮色模式) + Missing Variables Mapping + (Added to fix missing borders and styles) ====================================== */ - --alert-info: #2563eb; - --alert-info-bg: rgba(37, 99, 235, 0.08); - --alert-warning: #d97706; - --alert-warning-bg: rgba(217, 119, 6, 0.08); - --alert-danger: #dc2626; - --alert-danger-bg: rgba(220, 38, 38, 0.08); - --alert-success: #059669; - --alert-success-bg: rgba(5, 150, 105, 0.08); - --alert-note: #7c3aed; - --alert-note-bg: rgba(124, 58, 237, 0.08); + --border: var(--ifm-border-color); + --radius-sm: 4px; + --radius-md: 8px; + --radius-lg: 12px; + + --bg-light: var(--color-surface-0); + --bg-card: var(--color-surface-1); + --bg-muted: var(--color-surface-2); + --bg-elevated: var(--color-surface-2); + + --text-primary: var(--color-base); + --text-secondary: var(--color-subtle); + --text-light: var(--color-subtle); + --text-muted: var(--color-surface-4); + + --primary: var(--color-progressive); + --primary-dark: var(--ifm-color-primary-dark); + --primary-text: var(--color-progressive); + + --primary-alpha-5: oklch(from var(--color-progressive) l c h / 0.05); + --primary-alpha-8: oklch(from var(--color-progressive) l c h / 0.08); + --primary-alpha-10: oklch(from var(--color-progressive) l c h / 0.1); + --primary-alpha-border: oklch(from var(--color-progressive) l c h / 0.2); + + --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); + + --transition-fast: 150ms ease; + --transition-base: 300ms ease; + + /* Alert Colors */ + --alert-info: #2979ff; + --alert-info-bg: rgba(41, 121, 255, 0.1); + --alert-warning: #ff9100; + --alert-warning-bg: rgba(255, 145, 0, 0.1); + --alert-danger: #ff1744; + --alert-danger-bg: rgba(255, 23, 68, 0.1); + --alert-success: #00e676; + --alert-success-bg: rgba(0, 230, 118, 0.1); + --alert-note: #651fff; + --alert-note-bg: rgba(101, 31, 255, 0.1); +} + +/* ====================================== + Dark Mode Overrides +====================================== */ +[data-theme='dark'] { + /* Citizen: Surface Colors (Dark Mode) */ + --color-surface-0: #0f1216; /* Deep dark */ + --color-surface-1: #1a1e23; /* Card bg */ + --color-surface-2: #262b32; + --color-surface-3: #343b44; + --color-surface-4: #434c56; + + /* Citizen: Text Colors (Dark Mode) */ + --color-base: #c8ccd1; + --color-emphasized: #ffffff; + --color-subtle: #89919a; + + /* Adjust Primary for Dark Mode if needed */ + /* Keeping same hue/chroma but ensuring lightness is sufficient */ + --color-progressive-oklch__l: 60%; + + --ifm-border-color: var(--color-surface-2); + + /* Update Mappings for Dark Mode */ + --border: var(--ifm-border-color); + --bg-light: var(--color-surface-0); + --bg-card: var(--color-surface-1); + --bg-muted: var(--color-surface-2); + --bg-elevated: var(--color-surface-3); + + --text-primary: var(--color-base); + --text-secondary: var(--color-subtle); + + /* Alert Colors for Dark Mode (Slightly adjusted for contrast if needed) */ + --alert-info: #448aff; + --alert-info-bg: rgba(68, 138, 255, 0.15); + --alert-warning: #ffb74d; + --alert-warning-bg: rgba(255, 183, 77, 0.15); + --alert-danger: #ff5252; + --alert-danger-bg: rgba(255, 82, 82, 0.15); + --alert-success: #69f0ae; + --alert-success-bg: rgba(105, 240, 174, 0.15); + --alert-note: #b388ff; + --alert-note-bg: rgba(179, 136, 255, 0.15); +} + +/* ====================================== + Pure Black Mode (Optional Recipe) + .citizen-feature-pure-black-clientpref-1 +====================================== */ +[data-theme='dark'][data-pure-black='true'] { + --color-surface-0: #000000; + --color-surface-1: #101010; + --color-surface-2: #202020; } diff --git a/src/css/components/alert.css b/src/css/components/alert.css index 20eec510f..f6fc28cb6 100644 --- a/src/css/components/alert.css +++ b/src/css/components/alert.css @@ -163,12 +163,18 @@ blockquote p:last-child { [data-theme="dark"] .alert--info, [data-theme="dark"] .theme-admonition-info { background-color: var(--alert-info-bg); + border-left-color: var(--alert-info); + --ifm-alert-color: var(--color-emphasized); + color: var(--color-emphasized); } [data-theme="dark"] .alert--warning, [data-theme="dark"] .theme-admonition-warning, [data-theme="dark"] .theme-admonition-caution { background-color: var(--alert-warning-bg); + border-left-color: var(--alert-warning); + --ifm-alert-color: var(--color-emphasized); + color: var(--color-emphasized); } [data-theme="dark"] .alert--warning .alert__heading, @@ -180,6 +186,9 @@ blockquote p:last-child { [data-theme="dark"] .alert--danger, [data-theme="dark"] .theme-admonition-danger { background-color: var(--alert-danger-bg); + border-left-color: var(--alert-danger); + --ifm-alert-color: var(--color-emphasized); + color: var(--color-emphasized); } [data-theme="dark"] .alert--danger .alert__heading, @@ -191,6 +200,9 @@ blockquote p:last-child { [data-theme="dark"] .theme-admonition-success, [data-theme="dark"] .theme-admonition-tip { background-color: var(--alert-success-bg); + border-left-color: var(--alert-success); + --ifm-alert-color: var(--color-emphasized); + color: var(--color-emphasized); } [data-theme="dark"] .alert--success .alert__heading, @@ -202,6 +214,9 @@ blockquote p:last-child { [data-theme="dark"] .alert--secondary, [data-theme="dark"] .theme-admonition-note { background-color: var(--alert-note-bg); + border-left-color: var(--alert-note); + --ifm-alert-color: var(--color-emphasized); + color: var(--color-emphasized); } [data-theme="dark"] .alert--secondary .alert__heading, diff --git a/src/css/components/layout.css b/src/css/components/layout.css new file mode 100644 index 000000000..df5e65511 --- /dev/null +++ b/src/css/components/layout.css @@ -0,0 +1,75 @@ +/* ====================================== + Citizen Layout System + Implements the "Card" look for content +====================================== */ + +/* ====================================== + Desktop Layout (Card Style) +====================================== */ +@media (min-width: 997px) { + /* + Make the Main Content Area look like a "Card" + floating on the background + */ + + /* 1. Ensure the global background is the deepest surface */ + body { + background-color: var(--color-surface-0); + } + + /* 2. Style the DocMainContainer (The content area) */ + /* Use generic selector for the main content column in docs */ + main[class*="docMainContainer"] { + background-color: var(--color-surface-1); + border-radius: var(--border-radius-base); + + /* Add margin around the card */ + /* Top, Right, Bottom, Left */ + /* Left margin creates space between Sidebar and Content */ + margin: 1rem 1rem 1rem 1rem; + + box-shadow: 0 0 0 1px var(--ifm-border-color), + 0 10px 30px -10px rgba(0, 0, 0, 0.3); + + /* Ensure it takes height */ + min-height: calc(100vh - 2rem); + } + + /* 3. Adjust the DocSidebar to blend or stand out */ + /* In Citizen, the sidebar is often transparent or same as bg */ + .theme-doc-sidebar-container { + background-color: transparent !important; /* Let body bg show through */ + border-right: none !important; /* Remove border between sidebar and content */ + backdrop-filter: none !important; + } + + /* 4. Style the Sidebar Menu Items to look like pills */ + .menu__link { + border-radius: var(--radius-md); + } + + /* 5. Adjust the Main Wrapper to allow the card to float */ + /* We already shifted it by 72px in custom.css */ + + /* 6. Fix the TOC (Right Sidebar) */ + /* It's inside the card, so it should be fine. */ + + /* 7. Footer */ + .footer { + background-color: transparent; + border-top: none; + } +} + +/* ====================================== + Mobile Layout +====================================== */ +@media (max-width: 996px) { + /* Revert to standard full width */ + [class^="docMainContainer"] { + background-color: var(--color-surface-1); + margin: 0; + border-radius: 0; + box-shadow: none; + } +} diff --git a/src/css/components/navbar.css b/src/css/components/navbar.css index 4acdbe754..62ff3f439 100644 --- a/src/css/components/navbar.css +++ b/src/css/components/navbar.css @@ -1,22 +1,20 @@ /* ====================================== NitWikit 导航栏样式 - 毛玻璃效果 + 渐变底线 + 垂直侧边栏 (Citizen 风格) ====================================== */ +/* 移动端基础样式 (保持不变) */ .navbar { height: var(--ifm-navbar-height); padding: 0 var(--ifm-navbar-padding-horizontal); display: flex; align-items: center; - background: var(--ifm-navbar-background-color); + background: var(--color-surface-1); + border-bottom: 1px solid var(--ifm-border-color); transition: all var(--transition-base); box-shadow: none !important; - position: relative; } -/* ====================================== - 品牌区域 -====================================== */ .navbar__brand { font-weight: 700; color: var(--text-primary); @@ -25,370 +23,176 @@ gap: 0.5rem; } -.navbar__title { - font-size: 1.125rem; - letter-spacing: -0.01em; - font-weight: 700; - background: linear-gradient(135deg, var(--text-primary) 0%, var(--text-secondary) 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - .navbar__logo { height: 1.75rem; width: 1.75rem; - transition: transform var(--transition-base); -} - -.navbar__brand:hover .navbar__logo { - transform: scale(1.05) rotate(5deg); -} - -.navbar__brand:hover .navbar__title { - background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%); - -webkit-background-clip: text; - background-clip: text; -} - -/* ====================================== - 导航链接 -====================================== */ -.navbar__link { - display: flex; - align-items: center; - font-size: 0.9375rem; - padding: 0.5rem 0.875rem; - border-radius: var(--radius-md); - color: var(--text-secondary); - transition: all var(--transition-fast); - font-weight: 500; - position: relative; -} - -.navbar__link::before { - content: ""; - position: absolute; - bottom: 0; - left: 50%; - transform: translateX(-50%); - width: 0; - height: 2px; - background: var(--primary); - transition: width var(--transition-fast); - border-radius: 1px; -} - -.navbar__link:hover { - color: var(--primary-text); - background-color: transparent; - text-decoration: none; -} - -.navbar__link:hover::before { - width: 60%; -} - -.navbar__link--active { - font-weight: 600; - color: var(--primary-text); -} - -.navbar__link--active::before { - width: 60%; -} - -/* ====================================== - 导航项 -====================================== */ -.navbar__item { - margin: 0 0.125rem; -} - -.navbar__items { - display: flex; - align-items: center; - height: 100%; -} - -.navbar__items--right { - gap: 0.25rem; -} - -/* ====================================== - 导航栏内部布局 -====================================== */ -.navbar__inner { - display: flex; - align-items: center; - height: 100%; - width: 100%; - justify-content: space-between; } /* ====================================== - 搜索框 + Desktop Vertical Rail (Citizen Style) + 屏幕宽度 >= 997px 时启用垂直侧边栏 ====================================== */ -.navbar__search { - margin-left: 0.5rem; -} - -.navbar__search-input { - height: 2.25rem; - border-radius: var(--radius-lg); - background-color: var(--bg-muted); - border: 1px solid var(--border); - transition: all var(--transition-fast); - padding: 0 0.875rem; - font-size: 0.875rem; - width: 10rem; - color: var(--text-primary); -} - -.navbar__search-input::placeholder { - color: var(--text-light); -} - -.navbar__search-input:focus { - background-color: var(--bg-card); - border-color: var(--primary); - box-shadow: - 0 0 0 3px var(--primary-alpha-10), - var(--shadow-glow); - outline: none; - width: 12rem; -} - -/* ====================================== - GitHub 链接 -====================================== */ -.header-github-link { - @apply hidden md:flex items-center justify-center; - width: 2rem; - height: 2rem; - border-radius: 50%; - color: var(--text-secondary); - transition: all var(--transition-fast); - position: relative; -} - -.header-github-link:hover { - background-color: var(--ifm-color-emphasis-200); -} - -.header-github-link::before { - content: ""; - width: 1.25rem; - height: 1.25rem; - background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") - no-repeat; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); -} - -.header-github-link:hover::before { - width: 1.25rem !important; - height: 1.25rem !important; -} - -[data-theme="dark"] .header-github-link::before { - background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='white' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") - no-repeat; -} - -/* ====================================== - 主题切换按钮 -====================================== */ -button[class*="colorModeToggle"] { - border-radius: var(--radius-md); - transition: all var(--transition-fast); -} - -/* ====================================== - 移动端响应式 -====================================== */ -@media (max-width: 996px) { +@media (min-width: 997px) { .navbar { - height: auto; - min-height: var(--ifm-navbar-height); - padding: 0.75rem 1rem; + position: fixed; + left: 0; + top: 0; + bottom: 0; + width: 60px; /* 调整为 Citizen 标准宽度 (3.75rem) */ + height: 100vh; + flex-direction: column; + padding: 1rem 0; + border-right: 1px solid var(--border); + border-bottom: none; + background-color: var(--color-surface-0); /* 深色背景 */ + z-index: 200; + align-items: center; } .navbar__inner { - position: relative; display: flex; - justify-content: space-between; + flex-direction: column; + height: 100%; + width: 100%; align-items: center; + gap: 1rem; + padding: 0; } - /* - * 核心:隐藏导航链接(通用、Java、Bedrock、关于我们) - * 导航链接同时具有 .navbar__item 和 .navbar__link 类 - */ - .navbar__item.navbar__link { - display: none !important; - } - - /* 隐藏下拉菜单类型的导航项 */ - .navbar__item.dropdown { - display: none !important; + /* 使用 display: contents 打平结构,以便重新排序 */ + .navbar__items, + .navbar__items--right { + display: contents; } - /* 品牌居中显示 */ + /* 1. Logo (顶部) */ .navbar__brand { - display: flex !important; - position: absolute; - left: 50%; - transform: translateX(-50%); - z-index: 1; + order: 1; + margin-right: 0; + width: 44px; + height: 44px; + justify-content: center; + border-radius: var(--radius-md); + transition: background-color var(--transition-fast); + /* Ensure text is hidden even if selector fails */ + font-size: 0 !important; + } + + .navbar__brand:hover { + background-color: var(--color-surface-2); } .navbar__title { - font-size: 1.0625rem; + display: none !important; /* 强制隐藏文字 */ } - + .navbar__logo { - height: 1.5rem; - width: 1.5rem; + width: 28px; + height: 28px; + margin: 0; } - /* 汉堡菜单按钮 */ - .navbar__toggle { - position: relative; - z-index: 10; + /* 2. 搜索 (Logo 下方) */ + .navbar__search { + order: 2; + margin-left: 0; + display: flex; + justify-content: center; + width: 100%; } - /* 右侧搜索和 GitHub */ - .navbar__items--right { - position: relative; - z-index: 10; - margin-left: auto; + /* 强制搜索按钮为图标样式 - 使用 search.css 中的通用样式,此处仅做微调 */ + /* 移除强制的 width/height,依赖 search.css 的 max-width/height 和 flex 布局 */ + + /* 3. 菜单按钮 (搜索下方) */ + /* 隐藏菜单按钮,因为我们使用原生侧边栏 */ + .navbar__toggle { + display: none !important; } - - /* 显示搜索 */ - .navbar__search, - .DocSearch-Button { - display: flex !important; + + /* 隐藏普通文本链接 (仅在 Rail 中隐藏) */ + /* Exclude .header-github-link from being hidden */ + .navbar__inner .navbar__item.navbar__link:not(.header-github-link) { + display: none; } - - /* 移动端隐藏 GitHub 链接 */ - .header-github-link { - display: none !important; + + /* 隐藏下拉菜单 (仅在 Rail 中隐藏) */ + .navbar__inner .navbar__item.dropdown { + display: none; } - /* 侧边栏样式 */ - .navbar-sidebar { - z-index: 15 !important; - height: 100vh !important; - max-height: none !important; - background: var(--bg-card); + /* 4. 底部设置区域 (颜色切换等) */ + /* 这是一个 hack,尝试将最后一个元素推到底部 */ + /* 通常颜色切换按钮在 items--right 的最后 */ + + /* 针对颜色切换按钮 */ + .navbar__item { + order: 10; /* 默认顺序 */ } - .navbar-sidebar__backdrop { - background: rgba(0, 0, 0, 0.5); - backdrop-filter: blur(4px); + /* 尝试选中颜色切换按钮容器 */ + div[class*="colorModeToggle"] { + order: 100; + margin-top: 0.5rem !important; /* 紧跟在 GitHub 按钮下方 */ + margin-bottom: 1rem; } - - .navbar__link::before { - display: none; + + /* GitHub 链接样式 */ + .header-github-link { + order: 99; + margin-top: auto !important; /* 将自己和后面的元素推到底部 */ + margin-bottom: 0; + width: 44px; + height: 44px; + display: flex !important; /* Force display */ + justify-content: center; + align-items: center; + border-radius: var(--radius-md); + } + + .header-github-link:hover { + background-color: var(--color-surface-2); } -} - -/* ====================================== - 移动端侧边栏导航 -====================================== */ -.navbar-sidebar__brand { - padding: 1rem; - border-bottom: 1px solid var(--border); -} - -.navbar-sidebar__close { - color: var(--text-secondary); - /* 增大触摸区域 */ - min-width: 44px; - min-height: 44px; - display: flex; - align-items: center; - justify-content: center; -} - -.navbar-sidebar__items { - /* 移除 padding,由子元素控制边距 */ - padding: 0; -} - -/* 移动端返回按钮样式 */ -.navbar-sidebar__back { - background: transparent; - border: none; - color: var(--text-secondary); - padding: 0.75rem 1rem; - display: flex; - align-items: center; - /* 确保与其他菜单项对齐 */ - width: calc(100% - 2rem); - margin: 0 1rem 0.5rem 1rem; - font-weight: 600; - border-radius: var(--radius-md); - transition: background-color var(--transition-fast); -} - -.navbar-sidebar__back:hover { - background-color: var(--bg-muted); - color: var(--text-primary); -} -/* 移动端侧边栏链接优化触摸目标 */ -.navbar-sidebar__item { - min-height: 44px; - display: block; /* 改为 block 避免 flex 挤压 */ -} + .header-github-link::before { + content: ''; + width: 24px; + height: 24px; + display: block; + background-color: var(--text-secondary); + mask: url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat center; + mask-size: contain; + -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat center; + -webkit-mask-size: contain; + } -.navbar-sidebar .menu__link { - min-height: 44px; - padding: 0.75rem 1rem; - display: flex; - align-items: center; - width: 100%; /* 确保占满宽度 */ - white-space: nowrap; /* 防止文字换行 */ + /* ====================================== + Desktop Drawer (Mobile Sidebar on Desktop) + REMOVED: User requested to use native left sidebar instead. + ====================================== */ } /* ====================================== - 小屏幕额外优化 + 移动端样式 (保持原有逻辑) ====================================== */ -@media (max-width: 540px) { - .navbar { - padding: 0.5rem 0.75rem; - } - - .navbar__title { - font-size: 1rem; - } - - .navbar__logo { - height: 1.375rem; - width: 1.375rem; - } - - /* 汉堡菜单触摸区域 */ - .navbar__toggle { - min-width: 44px; - min-height: 44px; - padding: 0.5rem; +@media (max-width: 996px) { + .navbar__inner { + display: flex; + justify-content: space-between; } - - .navbar-sidebar { - width: 85vw; - max-width: 320px; + + .navbar__brand { + position: absolute; + left: 50%; + transform: translateX(-50%); } - - .navbar-sidebar__brand { - padding: 0.875rem; + + .navbar__items { + display: flex; } - - .navbar-sidebar__items { - padding: 0; + + .navbar__items--right { + display: flex; + margin-left: auto; } } diff --git a/src/css/components/sidebar.css b/src/css/components/sidebar.css index 94efca55b..6115c00b9 100644 --- a/src/css/components/sidebar.css +++ b/src/css/components/sidebar.css @@ -5,14 +5,21 @@ .theme-doc-sidebar-container { border: none !important; - border-right: 1px solid var(--border) !important; - background-color: var(--bg-card); + border-right: 1px solid var(--ifm-border-color) !important; + background-color: color-mix(in srgb, var(--color-surface-1), transparent calc(100% - var(--opacity-glass) * 100%)); + backdrop-filter: var(--backdrop-filter-frosted-glass); + -webkit-backdrop-filter: var(--backdrop-filter-frosted-glass); transition: background-color var(--transition-base); display: block; min-width: 0; flex-shrink: 0; } +[data-theme="dark"] .theme-doc-sidebar-container { + background-color: color-mix(in srgb, var(--color-surface-1), transparent calc(100% - var(--opacity-glass) * 100%)); + border-right: 1px solid var(--ifm-border-color) !important; +} + /* ====================================== 菜单容器 ====================================== */ @@ -229,3 +236,21 @@ [data-theme="dark"] .menu__list .menu__list { border-left-color: var(--border); } + +/* Catch Docusaurus hashed classes for Sidebar Logo */ +[class*="sidebarLogo"], +/* Fallback for the image itself if container isn't caught */ +.theme-doc-sidebar-container img[alt="Logo"], +/* Target the link wrapper specifically */ +a[class*="sidebarLogo"], +/* Target the bold text inside */ +a[class*="sidebarLogo"] b, +/* Target the image inside */ +a[class*="sidebarLogo"] img { + display: none !important; + visibility: hidden !important; + opacity: 0 !important; + width: 0 !important; + height: 0 !important; + pointer-events: none !important; +} diff --git a/src/css/custom.css b/src/css/custom.css index c6ed2347e..af9099443 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -34,6 +34,7 @@ @import "./components/table.css"; @import "./components/alert.css"; @import "./components/footer.css"; +@import "./components/layout.css"; /* ====================================== 工具类样式 @@ -41,3 +42,23 @@ @import "./utilities/scrollbar.css"; @import "./utilities/responsive.css"; @import "./utilities/search.css"; + +/* ====================================== + Layout Adjustment for Vertical Sidebar +====================================== */ +@media (min-width: 997px) { + :root { + --ifm-navbar-height: 0px; + } + + .main-wrapper { + margin-left: 60px; /* Matches sidebar width (3.75rem) */ + width: calc(100% - 60px); + } + + /* Adjust footer to respect sidebar */ + .footer { + margin-left: 60px; + width: calc(100% - 60px); + } +} diff --git a/src/css/utilities/search.css b/src/css/utilities/search.css index a8ab6a9db..0be3db0bc 100644 --- a/src/css/utilities/search.css +++ b/src/css/utilities/search.css @@ -1,201 +1,222 @@ /* ====================================== NitWikit 搜索样式 - Algolia DocSearch 适配 + Algolia DocSearch 适配 (Citizen 风格) ====================================== */ +:root { + --docsearch-primary-color: var(--color-progressive); + --docsearch-text-color: var(--color-base); + --docsearch-spacing: 12px; + --docsearch-icon-stroke-width: 1.4; + --docsearch-highlight-color: var(--docsearch-primary-color); + --docsearch-muted-color: var(--color-subtle); + --docsearch-container-background: rgba(0, 0, 0, 0.6); + --docsearch-logo-color: var(--docsearch-primary-color); + + /* Modal */ + --docsearch-modal-width: 600px; + --docsearch-modal-height: 600px; + --docsearch-modal-background: var(--color-surface-0); + --docsearch-modal-shadow: 0 0 0 1px var(--border), 0 20px 60px rgba(0,0,0,0.4); + + /* Searchbox */ + --docsearch-searchbox-height: 56px; + --docsearch-searchbox-background: var(--color-surface-2); + --docsearch-searchbox-focus-background: var(--color-surface-2); + --docsearch-searchbox-shadow: none; + + /* Hit */ + --docsearch-hit-height: 64px; + --docsearch-hit-color: var(--color-base); + --docsearch-hit-active-color: var(--color-emphasized); + --docsearch-hit-background: transparent; + --docsearch-hit-shadow: none; + + /* Footer */ + --docsearch-footer-height: 44px; + --docsearch-footer-background: var(--color-surface-0); + --docsearch-footer-shadow: 0 -1px 0 0 var(--border); +} + +[data-theme='dark'] { + --docsearch-modal-background: #0b0d10; /* Deepest black/blue */ + --docsearch-searchbox-background: #15171b; + --docsearch-searchbox-focus-background: #15171b; + --docsearch-hit-background: transparent; + --docsearch-hit-active-background: #1a1d21; + --docsearch-footer-background: #0b0d10; + --docsearch-key-gradient: #262b32; + --docsearch-key-shadow: none; + --docsearch-text-color: #b0b8c4; + --docsearch-muted-color: #6e7681; +} + /* ====================================== - 搜索按钮 + Modal Layout ====================================== */ -.DocSearch-Button { - background: var(--bg-card) !important; - border: 1px solid var(--border) !important; - border-radius: var(--radius-md) !important; - padding: 0 0.75rem !important; - height: 2rem !important; - transition: all var(--transition-fast) !important; - color: var(--text-secondary) !important; - font-weight: 400 !important; - gap: 0.5rem !important; +.DocSearch-Modal { + border-radius: 12px !important; + overflow: hidden !important; } -.DocSearch-Button:hover { - background: var(--bg-muted) !important; - border-color: var(--primary-alpha-border) !important; - box-shadow: 0 0 0 2px var(--primary-alpha-10) !important; +/* ====================================== + Search Bar +====================================== */ +.DocSearch-SearchBar { + padding: 16px !important; + border-bottom: 1px solid var(--border); } -.DocSearch-Button-Placeholder { - font-size: 0.8125rem !important; - color: var(--text-light) !important; +.DocSearch-Form { + border-radius: 8px !important; + background-color: var(--docsearch-searchbox-background) !important; + box-shadow: none !important; + border: 1px solid transparent !important; } -.DocSearch-Button-Keys { - display: flex !important; - gap: 0.125rem !important; - min-width: auto !important; +.DocSearch-Form:focus-within { + border-color: var(--color-progressive) !important; + box-shadow: 0 0 0 2px rgba(var(--color-progressive), 0.2) !important; } -.DocSearch-Button-Key { - background: var(--bg-muted) !important; - border: 1px solid var(--border-light) !important; - border-radius: var(--radius-sm) !important; - padding: 0 0.25rem !important; - font-size: 0.625rem !important; - color: var(--text-light) !important; - box-shadow: none !important; - width: auto !important; - height: 1.25rem !important; - line-height: 1.25rem !important; +.DocSearch-Input { + font-size: 16px !important; + padding-left: 12px !important; } /* ====================================== - 搜索模态框 + Results (Hits) ====================================== */ -.DocSearch-Modal { - --docsearch-modal-background: var(--bg-card) !important; - --docsearch-text-color: var(--text-primary) !important; - --docsearch-muted-color: var(--text-secondary) !important; - --docsearch-searchbox-background: var(--bg-muted) !important; - --docsearch-searchbox-focus-background: var(--bg-card) !important; - --docsearch-hit-background: var(--bg-muted) !important; - --docsearch-hit-color: var(--text-primary) !important; - --docsearch-highlight-color: var(--primary-text) !important; - --docsearch-footer-background: var(--bg-muted) !important; - --docsearch-key-gradient: var(--bg-elevated) !important; - --docsearch-key-shadow: none !important; - border-radius: var(--radius-lg) !important; - border: 1px solid var(--border) !important; - box-shadow: var(--shadow-lg) !important; +.DocSearch-Dropdown { + padding: 0 12px !important; } -.DocSearch-SearchBar { - padding: 0.875rem !important; +.DocSearch-Hit { + padding-bottom: 4px !important; } -.DocSearch-Form { - border-radius: var(--radius-md) !important; - border: 1px solid var(--border) !important; +.DocSearch-Hit a { + border-radius: 8px !important; + background: transparent !important; + box-shadow: none !important; + border: 1px solid transparent !important; + padding: 12px !important; } -.DocSearch-Input { - font-size: 0.9375rem !important; - padding-left: 0.5rem !important; +.DocSearch-Hit[aria-selected="true"] a { + background-color: var(--docsearch-hit-active-background) !important; + border-color: var(--border) !important; } -.DocSearch-Hit a { - border-radius: var(--radius-md) !important; - padding: 0.75rem !important; +/* Icon */ +.DocSearch-Hit-icon { + width: 32px !important; + height: 32px !important; + color: var(--text-secondary) !important; } -.DocSearch-Hit[aria-selected="true"] a { - background: var(--primary-alpha-10) !important; - border-color: var(--primary-alpha-border) !important; +/* Content */ +.DocSearch-Hit-content-wrapper { + margin: 0 12px !important; } .DocSearch-Hit-title { - font-weight: 500 !important; - font-size: 0.875rem !important; + font-size: 15px !important; + font-weight: 600 !important; + color: var(--color-emphasized) !important; } .DocSearch-Hit-path { - color: var(--text-light) !important; - font-size: 0.75rem !important; + font-size: 13px !important; + color: var(--color-subtle) !important; + margin-top: 2px !important; } -.DocSearch-Footer { - border-top: 1px solid var(--border) !important; +/* Action (The "Page" badge) */ +.DocSearch-Hit-action { + display: flex !important; + color: var(--text-secondary) !important; +} + +.DocSearch-Hit-action-button { + border-radius: 4px !important; + padding: 2px 6px !important; + font-size: 11px !important; + font-weight: 600 !important; + background: var(--color-surface-2) !important; + color: var(--text-secondary) !important; + border: 1px solid var(--border) !important; + text-transform: uppercase !important; + letter-spacing: 0.5px !important; + visibility: visible !important; } /* ====================================== - 暗色模式 + Footer ====================================== */ -[data-theme="dark"] .DocSearch-Button { - background: var(--bg-card) !important; - border-color: var(--border) !important; +.DocSearch-Footer { + height: auto !important; + padding: 12px 24px !important; + background: var(--docsearch-footer-background) !important; + box-shadow: none !important; + border-top: 1px solid var(--border) !important; } -[data-theme="dark"] .DocSearch-Button:hover { - background: var(--bg-elevated) !important; - border-color: var(--primary-alpha-border) !important; +.DocSearch-Commands { + display: flex !important; + gap: 16px !important; } -[data-theme="dark"] .DocSearch-Button-Key { - background: var(--bg-elevated) !important; - border-color: var(--border) !important; +.DocSearch-Label { + font-size: 12px !important; + color: var(--text-secondary) !important; } -[data-theme="dark"] .DocSearch-Modal { - --docsearch-highlight-color: var(--primary) !important; +/* ====================================== + Button (Trigger) + Keep it minimal as requested before +====================================== */ +.DocSearch-Button { + /* Remove fixed dimensions to allow native adaptation */ + /* width: 44px !important; */ + /* height: 44px !important; */ + padding: 0 !important; + margin: 0 !important; + border-radius: 50% !important; + background: transparent !important; + box-shadow: none !important; + display: flex !important; + justify-content: center !important; + align-items: center !important; + overflow: hidden !important; + border: none !important; + /* Ensure it takes full width of container if needed, or auto */ + width: 100% !important; + height: 100% !important; + max-width: 44px !important; /* Limit max size for icon look */ + max-height: 44px !important; } -[data-theme="dark"] .DocSearch-Form { - border-color: var(--border) !important; +.DocSearch-Button:hover { + background-color: var(--color-surface-2) !important; } -/* ====================================== - 移动端响应式 -====================================== */ -@media (max-width: 996px) { - .DocSearch-Button { - padding: 0 0.625rem !important; - /* 确保触摸目标足够大 */ - min-height: 36px !important; - min-width: 36px !important; - } - - .DocSearch-Button-Placeholder { - display: none !important; - } - - .DocSearch-Button-Keys { - display: none !important; - } - - .DocSearch-Search-Icon { - width: 18px !important; - height: 18px !important; - } -} - -@media (max-width: 540px) { - .DocSearch-Button { - min-height: 40px !important; - min-width: 40px !important; - padding: 0 0.5rem !important; - border-radius: var(--radius-md) !important; - } - - /* 搜索模态框移动端全屏优化 */ - .DocSearch-Modal { - border-radius: 0 !important; - max-width: 100vw !important; - margin: 0 !important; - height: 100vh !important; - max-height: 100vh !important; - } - - .DocSearch-SearchBar { - padding: 0.75rem !important; - } - - .DocSearch-Input { - font-size: 16px !important; /* 防止 iOS 缩放 */ - padding-left: 0.375rem !important; - } - - .DocSearch-Hit a { - padding: 0.625rem !important; - } - - .DocSearch-Hit-title { - font-size: 0.8125rem !important; - } - - .DocSearch-Hit-path { - font-size: 0.6875rem !important; - } - - .DocSearch-Footer { - padding: 0.625rem 0.75rem !important; - } +.DocSearch-Button-Placeholder, +.DocSearch-Button-Keys, +.DocSearch-Button-Key { + display: none !important; +} + +.DocSearch-Button-Container { + display: flex !important; + align-items: center !important; + justify-content: center !important; + margin: 0 !important; + padding: 0 !important; +} + +.DocSearch-Search-Icon { + width: 24px !important; + height: 24px !important; + color: var(--text-secondary); } diff --git a/src/pages/index.module.scss b/src/pages/index.module.scss index e926fa676..8c38df401 100644 --- a/src/pages/index.module.scss +++ b/src/pages/index.module.scss @@ -1,561 +1,173 @@ /* ====================================== - NitWikit 主页样式 - 借鉴 Nuxt 设计系统 - 包含渐变、装饰圆、动画效果 + NitWikit Bento Grid Homepage ====================================== */ -/* ====================================== - 页面容器 -====================================== */ .page { min-height: 100vh; - background: var(--bg-dark); - color: var(--text-primary); + background: var(--color-surface-0); + color: var(--color-base); + padding-top: var(--ifm-navbar-height); display: flex; - align-items: center; justify-content: center; - margin-top: calc(-1 * var(--ifm-navbar-height, 60px)); - padding-top: var(--ifm-navbar-height, 60px); - position: relative; - overflow: hidden; - animation: pageEnter 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards; -} - -// 页面进入动画 -@keyframes pageEnter { - from { - opacity: 0; - transform: translateY(20px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -// 页面退出动画 -.pageExit { - animation: pageExit 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards !important; + padding-bottom: 4rem; } -@keyframes pageExit { - from { - opacity: 1; - transform: translateY(0) scale(1); - } - to { - opacity: 0; - transform: translateY(-20px) scale(0.98); - } -} - -[data-theme="light"] .page { - background: var(--bg-light); -} - -/* ====================================== - 顶部渐变装饰 -====================================== */ -.page::before { - content: ""; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 400px; - background: linear-gradient(180deg, rgba(0, 220, 130, 0.08) 0%, rgba(0, 220, 130, 0.03) 40%, transparent 100%); - pointer-events: none; - z-index: 0; -} - -/* 顶部横向渐变线 */ -.page::after { - content: ""; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 1px; - background: linear-gradient(90deg, transparent 0%, rgba(0, 220, 130, 0.4) 50%, transparent 100%); - pointer-events: none; - z-index: 1; -} - -/* ====================================== - Hero 区域 - 左右分栏布局 -====================================== */ -.hero { +.bentoGrid { display: grid; - grid-template-columns: 1.4fr 1fr; - gap: 64px; - max-width: 1400px; + grid-template-columns: repeat(4, 1fr); + grid-template-rows: auto auto; + gap: 1.5rem; + max-width: var(--width-layout); width: 100%; + padding: 2rem; margin: 0 auto; - padding: 80px 48px; - align-items: center; - position: relative; - z-index: 2; +} - @media (max-width: 1200px) { - gap: 48px; - padding: 60px 32px; +@media (max-width: 1024px) { + .bentoGrid { + grid-template-columns: repeat(2, 1fr); } +} - @media (max-width: 996px) { +@media (max-width: 640px) { + .bentoGrid { grid-template-columns: 1fr; - padding: 80px 24px 60px; - gap: 40px; - } - - @media (max-width: 540px) { - padding: 60px 20px 48px; - gap: 32px; + padding: 1rem; } } /* ====================================== - 左侧内容区 + Bento Cards ====================================== */ -.heroCopy { +.card { + background: color-mix(in srgb, var(--color-surface-1), transparent calc(100% - var(--opacity-glass) * 100%)); + backdrop-filter: var(--backdrop-filter-frosted-glass); + -webkit-backdrop-filter: var(--backdrop-filter-frosted-glass); + border: 1px solid var(--ifm-border-color); + border-radius: 24px; + padding: 2rem; display: flex; flex-direction: column; - gap: 32px; - - h1 { - margin: 0; - font-size: clamp(48px, 6vw, 72px); - font-weight: 800; - letter-spacing: -0.03em; - line-height: 1.1; - color: var(--text-primary); - - // 高亮文字使用主色 - :global(.text-primary) { - color: var(--primary); - background: linear-gradient(135deg, var(--primary) 0%, var(--primary-light) 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; - } - } - - p { - margin: 0; - max-width: 560px; - font-size: 18px; - line-height: 1.85; - color: var(--text-secondary); - - @media (max-width: 540px) { - font-size: 16px; - max-width: none; - } - } - - @media (max-width: 996px) { - gap: 28px; - text-align: center; - align-items: center; - - p { - max-width: 600px; - } - } + transition: transform var(--transition-base), box-shadow var(--transition-base); + overflow: hidden; + position: relative; } -/* ====================================== - 按钮组 -====================================== */ -.heroButtons { - display: flex; - flex-wrap: wrap; - gap: 16px; - - @media (max-width: 996px) { - justify-content: center; - } +[data-theme="dark"] .card { + background: color-mix(in srgb, var(--color-surface-1), transparent calc(100% - var(--opacity-glass) * 100%)); + border: 1px solid var(--ifm-border-color); +} - @media (max-width: 540px) { - flex-direction: column; - width: 100%; - gap: 12px; - } +.card:hover { + transform: translateY(-4px); + box-shadow: var(--shadow-lg); } -.primaryButton, -.secondaryButton { - display: inline-flex; - align-items: center; +/* Card Sizes */ +.cardHero { + grid-column: span 2; + grid-row: span 2; + display: flex; + flex-direction: column; justify-content: center; - padding: 11px 22px; - border-radius: 8px; - text-decoration: none; - font-weight: 600; - font-size: 14px; - transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); - border: none; - cursor: pointer; - // 确保移动端触摸目标足够大 (最小 44px) - min-height: 44px; - - @media (max-width: 540px) { - width: 100%; - padding: 14px 20px; - font-size: 15px; - } } -.primaryButton { - background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%); - color: #020617 !important; - box-shadow: - 0 4px 14px rgba(0, 220, 130, 0.25), - 0 0 0 0 rgba(0, 220, 130, 0); - position: relative; - overflow: hidden; - - // 光泽效果 - &::before { - content: ""; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); - transition: left 0.5s ease; - } - - &:hover { - background: linear-gradient(135deg, var(--primary-light) 0%, var(--primary) 100%); - box-shadow: - 0 6px 20px rgba(0, 220, 130, 0.35), - 0 0 0 4px rgba(0, 220, 130, 0.1); - transform: translateY(-2px); - text-decoration: none; - - &::before { - left: 100%; - } - } - - &:active { - transform: translateY(0); - } +.cardFeature { + grid-column: span 1; + grid-row: span 1; } -.secondaryButton { - background: rgba(255, 255, 255, 0.05); - color: var(--text-primary) !important; - border: 1px solid var(--border); - backdrop-filter: blur(8px); - - &:hover { - background: var(--primary-alpha-10); - border-color: var(--primary); - color: var(--primary) !important; - text-decoration: none; - } +.cardWide { + grid-column: span 2; + grid-row: span 1; } -[data-theme="light"] .secondaryButton { - background: rgba(0, 0, 0, 0.02); -} - -/* ====================================== - 统计数据 -====================================== */ -.heroMetrics { - display: flex; - gap: 48px; - padding-top: 32px; - border-top: 1px solid var(--border); - - div { - display: flex; - flex-direction: column; - gap: 4px; - } - - strong { - font-size: 32px; - font-weight: 700; - background: linear-gradient(135deg, var(--primary) 0%, var(--primary-light) 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; - letter-spacing: -0.02em; - } - - span { - font-size: 14px; - color: var(--text-secondary); - font-weight: 500; +@media (max-width: 1024px) { + .cardHero, .cardWide { + grid-column: span 2; } +} - @media (max-width: 996px) { - justify-content: center; - } - - @media (max-width: 540px) { - gap: 24px; - padding-top: 24px; - - strong { - font-size: 28px; - } - - span { - font-size: 13px; - } +@media (max-width: 640px) { + .cardHero, .cardWide, .cardFeature { + grid-column: span 1; } } /* ====================================== - 右侧导航面板 + Content Styles ====================================== */ -.heroPanel { - border-radius: 16px; - border: 1px solid var(--border); - background: var(--bg-card); - overflow: hidden; - display: flex; - flex-direction: column; - backdrop-filter: blur(12px); - box-shadow: - 0 20px 50px rgba(0, 0, 0, 0.1), - 0 0 0 1px rgba(255, 255, 255, 0.05) inset; - - @media (max-width: 996px) { - max-width: 500px; - margin: 0 auto; - width: 100%; - } - - @media (max-width: 540px) { - border-radius: 12px; - box-shadow: - 0 10px 30px rgba(0, 0, 0, 0.08), - 0 0 0 1px rgba(255, 255, 255, 0.03) inset; - } +.heroTitle { + font-size: 3rem; + font-weight: 800; + margin-bottom: 1rem; + background: linear-gradient(135deg, var(--color-progressive) 0%, var(--ifm-color-primary-light) 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; } -[data-theme="dark"] .heroPanel { - background: rgba(15, 23, 42, 0.8); - box-shadow: - 0 20px 50px rgba(0, 0, 0, 0.3), - 0 0 0 1px rgba(255, 255, 255, 0.03) inset; +.heroDesc { + font-size: 1.25rem; + color: var(--color-subtle); + margin-bottom: 2rem; + line-height: 1.6; } -.panelHeader { - padding: 20px 24px; - border-bottom: 1px solid var(--border); - font-size: 12px; - font-weight: 600; - color: var(--text-secondary); - text-transform: uppercase; - letter-spacing: 0.1em; - display: flex; - align-items: center; - gap: 8px; - - // 小圆点装饰 - &::before { - content: ""; - width: 6px; - height: 6px; - border-radius: 50%; - background: var(--primary); - animation: pulse 2s ease-in-out infinite; - } - - @media (max-width: 540px) { - padding: 16px 20px; - font-size: 11px; - } +.cardTitle { + font-size: 1.5rem; + font-weight: 700; + margin-bottom: 0.5rem; + color: var(--color-emphasized); } -@keyframes pulse { - 0%, - 100% { - opacity: 1; - transform: scale(1); - } - 50% { - opacity: 0.5; - transform: scale(0.9); - } +.cardDesc { + font-size: 1rem; + color: var(--color-subtle); + margin-bottom: 1.5rem; } -.linkList { - list-style: none; - margin: 0; - padding: 0; +.buttonGroup { display: flex; - flex-direction: column; - - li { - display: flex; - - & + li { - border-top: 1px solid var(--border); - } - } - - // 列表项入场动画 - .linkItem { - opacity: 0; - animation: slideInFromRight 0.5s cubic-bezier(0.4, 0, 0.2, 1) forwards; - } - - a { - position: relative; - display: flex; - align-items: center; - justify-content: space-between; - gap: 16px; - padding: 20px 24px; - padding-left: 28px; - text-decoration: none; - color: inherit; - width: 100%; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - // 确保触摸目标足够大 - min-height: 72px; - overflow: hidden; - - // 左侧指示条 - &::before { - content: ""; - position: absolute; - left: 0; - top: 50%; - transform: translateY(-50%); - width: 3px; - height: 0; - background: linear-gradient(180deg, var(--primary) 0%, var(--primary-light) 100%); - border-radius: 0 2px 2px 0; - transition: height 0.3s cubic-bezier(0.4, 0, 0.2, 1); - } - - // 点击波纹效果 - &::after { - content: ""; - position: absolute; - top: 50%; - left: 50%; - width: 0; - height: 0; - border-radius: 50%; - background: rgba(0, 220, 130, 0.2); - transform: translate(-50%, -50%); - transition: - width 0.4s ease, - height 0.4s ease, - opacity 0.4s ease; - opacity: 0; - pointer-events: none; - } - - &:hover { - background: var(--primary-alpha-5); - text-decoration: none; - transform: translateX(4px); - - &::before { - height: 60%; - } - - span:last-child { - transform: translateX(6px); - color: var(--primary); - } - - h3 { - color: var(--primary); - } - } - - // 点击动画 - &:active { - background: var(--primary-alpha-10); - transform: translateX(2px) scale(0.98); - - &::after { - width: 300px; - height: 300px; - opacity: 1; - transition: - width 0.3s ease, - height 0.3s ease, - opacity 0.3s ease 0.1s; - } - - &::before { - height: 80%; - } - - span:last-child { - transform: translateX(8px) scale(1.1); - } - } - - // 箭头图标 - span:last-child { - font-size: 18px; - color: var(--text-light); - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - flex-shrink: 0; - } - - @media (max-width: 540px) { - padding: 16px 20px; - padding-left: 24px; - gap: 12px; - min-height: 64px; - } - } - - h3 { - margin: 0 0 6px; - font-size: 16px; - font-weight: 600; - color: var(--text-primary); - transition: color 0.3s cubic-bezier(0.4, 0, 0.2, 1); + gap: 1rem; + margin-top: auto; +} - @media (max-width: 540px) { - font-size: 15px; - margin-bottom: 4px; - } - } +.primaryButton { + background: var(--color-progressive); + color: white; + padding: 0.75rem 1.5rem; + border-radius: 12px; + font-weight: 600; + text-decoration: none; + transition: background var(--transition-fast); +} - p { - margin: 0; - font-size: 14px; - color: var(--text-secondary); - line-height: 1.5; - transition: color 0.3s cubic-bezier(0.4, 0, 0.2, 1); +.primaryButton:hover { + background: var(--ifm-color-primary-dark); + color: white; + text-decoration: none; +} - @media (max-width: 540px) { - font-size: 13px; - line-height: 1.4; - } - } +.secondaryButton { + background: transparent; + border: 1px solid var(--ifm-border-color); + color: var(--color-base); + padding: 0.75rem 1.5rem; + border-radius: 12px; + font-weight: 600; + text-decoration: none; + transition: background var(--transition-fast); } -// 列表项入场动画 -@keyframes slideInFromRight { - from { - opacity: 0; - transform: translateX(20px); - } - to { - opacity: 1; - transform: translateX(0); - } +.secondaryButton:hover { + background: var(--color-surface-2); + color: var(--color-emphasized); + text-decoration: none; } /* ====================================== - 入场动画 + Animations ====================================== */ .fadeInUp { animation: fadeInUp 0.6s ease-out forwards; @@ -573,18 +185,7 @@ } } -.delay1 { - animation-delay: 0.1s; -} -.delay2 { - animation-delay: 0.2s; -} -.delay3 { - animation-delay: 0.3s; -} -.delay4 { - animation-delay: 0.4s; -} -.delay5 { - animation-delay: 0.5s; -} +.delay1 { animation-delay: 0.1s; } +.delay2 { animation-delay: 0.2s; } +.delay3 { animation-delay: 0.3s; } +.delay4 { animation-delay: 0.4s; } diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 3840d186e..23b0d9762 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,182 +1,98 @@ import Link from "@docusaurus/Link"; -import { useHistory } from "@docusaurus/router"; import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; import Layout from "@theme/Layout"; -import React, { useRef } from "react"; +import React, { type ReactNode } from "react"; import styles from "./index.module.scss"; -interface Stat { - label: string; - value: string; -} - -interface NavLink { - title: string; - description: string; - to: string; -} - -function StatsMetrics({ stats }: { stats: Stat[] }) { - return ( -
- {stats.map((item) => ( -
- {item.value} - {item.label} -
- ))} -
- ); -} - -function HeroHeader() { +function HeroCard() { return ( - <> -

+
+

Cubic Wiki

-

+

主要针对高版本 Java 版和基岩版服务器的开服指南。从零开始,手把手教你搭建和运营 Minecraft 服务器。

- - ); -} - -function HeroButtons() { - return ( -
- - 立即开始 - - - 参与贡献 - +
+ + 立即开始 + + + 参与贡献 + +
); } -function QuickNavPanel({ - quickLinks, - onLinkClick -}: { - quickLinks: NavLink[]; - onLinkClick: (e: React.MouseEvent, to: string) => void; -}) { +function FeatureCard({ title, description, to, delay }: { title: string; description: string; to: string; delay: string }) { return ( - + ); } -function HeroCopy({ stats }: { stats: Stat[] }) { +function StatsCard() { return ( -
- - - +
+

项目统计

+
+
+ 1200+ +
文档篇章
+
+
+ 50+ +
活跃贡献者
+
+
); } -function HeroSection({ - stats, - quickLinks, - onLinkClick -}: { - stats: Stat[]; - quickLinks: NavLink[]; - onLinkClick: (e: React.MouseEvent, to: string) => void; -}) { - return ( -
- - -
- ); -} - -function usePageNavigation() { - const pageRef = useRef(null); - const history = useHistory(); - - const handleLinkClick = (e: React.MouseEvent, to: string) => { - e.preventDefault(); - const pageElement = pageRef.current; - - if (pageElement) { - // 添加退出动画类 - pageElement.classList.add(styles.pageExit); - - // 延迟导航,让退出动画完成 - setTimeout(() => { - history.push(to); - }, 300); - } else { - // 如果找不到元素,直接导航 - history.push(to); - } - }; - - return handleLinkClick; -} - -function useHomeData() { - // TODO: 引用真实数据 - const stats: Stat[] = [ - { label: "文档篇章", value: "1200+" }, - { label: "活跃贡献者", value: "50+" } - ]; - - const quickLinks: NavLink[] = [ - { title: "新手入门", description: "了解教程定位、阅读指引与基础要求", to: "/intro" }, - { title: "Java 版核心", description: "高版本 Java 版服务器开服指南", to: "/Java/intro" }, - { title: "基岩版核心", description: "基岩版服务器开服指南", to: "/Bedrock/intro" } - ]; - - return { stats, quickLinks }; -} - -/** - * 首页主组件 - */ -const Home: React.FC = () => { +export default function Home(): ReactNode { const { - siteConfig: { customFields, tagline } + siteConfig: { customFields, tagline }, } = useDocusaurusContext(); const { description } = customFields as { description: string }; - const handleLinkClick = usePageNavigation(); - const { stats, quickLinks } = useHomeData(); - return ( -
-
- +
+
+ + + + + +
); -}; - -export default Home; +} diff --git a/src/theme/Navbar/ColorModeToggle/index.tsx b/src/theme/Navbar/ColorModeToggle/index.tsx new file mode 100644 index 000000000..45e106c41 --- /dev/null +++ b/src/theme/Navbar/ColorModeToggle/index.tsx @@ -0,0 +1,27 @@ +import React, {type ReactNode} from 'react'; +import {useColorMode, useThemeConfig} from '@docusaurus/theme-common'; +import ColorModeToggle from '@theme/ColorModeToggle'; +import type {Props} from '@theme/Navbar/ColorModeToggle'; +import styles from './styles.module.css'; + +export default function NavbarColorModeToggle({className}: Props): ReactNode { + const navbarStyle = useThemeConfig().navbar.style; + const {disableSwitch, respectPrefersColorScheme} = useThemeConfig().colorMode; + const {colorModeChoice, setColorMode} = useColorMode(); + + if (disableSwitch) { + return null; + } + + return ( + + ); +} diff --git a/src/theme/Navbar/ColorModeToggle/styles.module.css b/src/theme/Navbar/ColorModeToggle/styles.module.css new file mode 100644 index 000000000..7bd077a6b --- /dev/null +++ b/src/theme/Navbar/ColorModeToggle/styles.module.css @@ -0,0 +1,3 @@ +.darkNavbarColorModeToggle:hover { + background: var(--ifm-color-gray-800); +} diff --git a/src/theme/Navbar/Content/index.tsx b/src/theme/Navbar/Content/index.tsx new file mode 100644 index 000000000..af079baaf --- /dev/null +++ b/src/theme/Navbar/Content/index.tsx @@ -0,0 +1,107 @@ +import React, {type ReactNode} from 'react'; +import clsx from 'clsx'; +import { + useThemeConfig, + ErrorCauseBoundary, + ThemeClassNames, +} from '@docusaurus/theme-common'; +import { + splitNavbarItems, + useNavbarMobileSidebar, +} from '@docusaurus/theme-common/internal'; +import NavbarItem, {type Props as NavbarItemConfig} from '@theme/NavbarItem'; +import NavbarColorModeToggle from '@theme/Navbar/ColorModeToggle'; +import SearchBar from '@theme/SearchBar'; +import NavbarMobileSidebarToggle from '@theme/Navbar/MobileSidebar/Toggle'; +import NavbarLogo from '@theme/Navbar/Logo'; +import NavbarSearch from '@theme/Navbar/Search'; + +import styles from './styles.module.css'; + +function useNavbarItems() { + // TODO temporary casting until ThemeConfig type is improved + return useThemeConfig().navbar.items as NavbarItemConfig[]; +} + +function NavbarItems({items}: {items: NavbarItemConfig[]}): ReactNode { + return ( + <> + {items.map((item, i) => ( + + new Error( + `A theme navbar item failed to render. +Please double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config: +${JSON.stringify(item, null, 2)}`, + {cause: error}, + ) + }> + + + ))} + + ); +} + +function NavbarContentLayout({ + left, + right, +}: { + left: ReactNode; + right: ReactNode; +}) { + return ( +
+
+ {left} +
+
+ {right} +
+
+ ); +} + +export default function NavbarContent(): ReactNode { + const mobileSidebar = useNavbarMobileSidebar(); + + const items = useNavbarItems(); + const [leftItems, rightItems] = splitNavbarItems(items); + + const searchBarItem = items.find((item) => item.type === 'search'); + + return ( + + {!mobileSidebar.disabled && } + + + + } + right={ + // TODO stop hardcoding items? + // Ask the user to add the respective navbar items => more flexible + <> + + + {!searchBarItem && ( + + + + )} + + } + /> + ); +} diff --git a/src/theme/Navbar/Content/styles.module.css b/src/theme/Navbar/Content/styles.module.css new file mode 100644 index 000000000..9f080ff96 --- /dev/null +++ b/src/theme/Navbar/Content/styles.module.css @@ -0,0 +1,16 @@ +/* +Hide color mode toggle in small viewports + */ +@media (max-width: 996px) { + .colorModeToggle { + display: none; + } +} + +/* +Restore some Infima style that broke with CSS Cascade Layers +See https://github.com/facebook/docusaurus/pull/11142 + */ +:global(.navbar__items--right) > :last-child { + padding-right: 0; +} diff --git a/src/theme/Navbar/Layout/index.tsx b/src/theme/Navbar/Layout/index.tsx new file mode 100644 index 000000000..9ca34c63e --- /dev/null +++ b/src/theme/Navbar/Layout/index.tsx @@ -0,0 +1,65 @@ +import React, {type ComponentProps, type ReactNode} from 'react'; +import clsx from 'clsx'; +import {ThemeClassNames, useThemeConfig} from '@docusaurus/theme-common'; +import { + useHideableNavbar, + useNavbarMobileSidebar, +} from '@docusaurus/theme-common/internal'; +import {translate} from '@docusaurus/Translate'; +import NavbarMobileSidebar from '@theme/Navbar/MobileSidebar'; +import type {Props} from '@theme/Navbar/Layout'; + +import styles from './styles.module.css'; + +function NavbarBackdrop(props: ComponentProps<'div'>) { + return ( +
+ ); +} + +export default function NavbarLayout({children}: Props): ReactNode { + const { + navbar: {hideOnScroll, style}, + } = useThemeConfig(); + const mobileSidebar = useNavbarMobileSidebar(); + const {navbarRef, isNavbarVisible} = useHideableNavbar(hideOnScroll); + return ( + + ); +} diff --git a/src/theme/Navbar/Layout/styles.module.css b/src/theme/Navbar/Layout/styles.module.css new file mode 100644 index 000000000..e72891a44 --- /dev/null +++ b/src/theme/Navbar/Layout/styles.module.css @@ -0,0 +1,7 @@ +.navbarHideable { + transition: transform var(--ifm-transition-fast) ease; +} + +.navbarHidden { + transform: translate3d(0, calc(-100% - 2px), 0); +} diff --git a/src/theme/Navbar/Logo/index.tsx b/src/theme/Navbar/Logo/index.tsx new file mode 100644 index 000000000..72d320a0a --- /dev/null +++ b/src/theme/Navbar/Logo/index.tsx @@ -0,0 +1,12 @@ +import React, {type ReactNode} from 'react'; +import Logo from '@theme/Logo'; + +export default function NavbarLogo(): ReactNode { + return ( + + ); +} diff --git a/src/theme/Navbar/MobileSidebar/Header/index.tsx b/src/theme/Navbar/MobileSidebar/Header/index.tsx new file mode 100644 index 000000000..dc093540b --- /dev/null +++ b/src/theme/Navbar/MobileSidebar/Header/index.tsx @@ -0,0 +1,33 @@ +import React, {type ReactNode} from 'react'; +import {useNavbarMobileSidebar} from '@docusaurus/theme-common/internal'; +import {translate} from '@docusaurus/Translate'; +import NavbarColorModeToggle from '@theme/Navbar/ColorModeToggle'; +import IconClose from '@theme/Icon/Close'; +import NavbarLogo from '@theme/Navbar/Logo'; + +function CloseButton() { + const mobileSidebar = useNavbarMobileSidebar(); + return ( + + ); +} + +export default function NavbarMobileSidebarHeader(): ReactNode { + return ( +
+ + + +
+ ); +} diff --git a/src/theme/Navbar/MobileSidebar/Layout/index.tsx b/src/theme/Navbar/MobileSidebar/Layout/index.tsx new file mode 100644 index 000000000..fa88383dc --- /dev/null +++ b/src/theme/Navbar/MobileSidebar/Layout/index.tsx @@ -0,0 +1,63 @@ +import React, {version, type ReactNode} from 'react'; +import clsx from 'clsx'; +import {useNavbarSecondaryMenu} from '@docusaurus/theme-common/internal'; +import {ThemeClassNames} from '@docusaurus/theme-common'; +import type {Props} from '@theme/Navbar/MobileSidebar/Layout'; + +// TODO Docusaurus v4: remove temporary inert workaround +// See https://github.com/facebook/react/issues/17157 +// See https://github.com/radix-ui/themes/pull/509 +function inertProps(inert: boolean) { + const isBeforeReact19 = parseInt(version!.split('.')[0]!, 10) < 19; + if (isBeforeReact19) { + return {inert: inert ? '' : undefined}; + } + return {inert}; +} + +function NavbarMobileSidebarPanel({ + children, + inert, +}: { + children: ReactNode; + inert: boolean; +}) { + return ( +
+ {children} +
+ ); +} + +export default function NavbarMobileSidebarLayout({ + header, + primaryMenu, + secondaryMenu, +}: Props): ReactNode { + const {shown: secondaryMenuShown} = useNavbarSecondaryMenu(); + return ( +
+ {header} +
+ + {primaryMenu} + + + {secondaryMenu} + +
+
+ ); +} diff --git a/src/theme/Navbar/MobileSidebar/PrimaryMenu/index.tsx b/src/theme/Navbar/MobileSidebar/PrimaryMenu/index.tsx new file mode 100644 index 000000000..d5d0913e6 --- /dev/null +++ b/src/theme/Navbar/MobileSidebar/PrimaryMenu/index.tsx @@ -0,0 +1,31 @@ +import React, {type ReactNode} from 'react'; +import {useThemeConfig} from '@docusaurus/theme-common'; +import {useNavbarMobileSidebar} from '@docusaurus/theme-common/internal'; +import NavbarItem, {type Props as NavbarItemConfig} from '@theme/NavbarItem'; + +function useNavbarItems() { + // TODO temporary casting until ThemeConfig type is improved + return useThemeConfig().navbar.items as NavbarItemConfig[]; +} + +// The primary menu displays the navbar items +export default function NavbarMobilePrimaryMenu(): ReactNode { + const mobileSidebar = useNavbarMobileSidebar(); + + // TODO how can the order be defined for mobile? + // Should we allow providing a different list of items? + const items = useNavbarItems(); + + return ( +
    + {items.map((item, i) => ( + mobileSidebar.toggle()} + key={i} + /> + ))} +
+ ); +} diff --git a/src/theme/Navbar/MobileSidebar/SecondaryMenu/index.tsx b/src/theme/Navbar/MobileSidebar/SecondaryMenu/index.tsx new file mode 100644 index 000000000..eb4f1e9ff --- /dev/null +++ b/src/theme/Navbar/MobileSidebar/SecondaryMenu/index.tsx @@ -0,0 +1,32 @@ +import React, {type ComponentProps, type ReactNode} from 'react'; +import {useThemeConfig} from '@docusaurus/theme-common'; +import {useNavbarSecondaryMenu} from '@docusaurus/theme-common/internal'; +import Translate from '@docusaurus/Translate'; + +function SecondaryMenuBackButton(props: ComponentProps<'button'>) { + return ( + + ); +} + +// The secondary menu slides from the right and shows contextual information +// such as the docs sidebar +export default function NavbarMobileSidebarSecondaryMenu(): ReactNode { + const isPrimaryMenuEmpty = useThemeConfig().navbar.items.length === 0; + const secondaryMenu = useNavbarSecondaryMenu(); + return ( + <> + {/* edge-case: prevent returning to the primaryMenu when it's empty */} + {!isPrimaryMenuEmpty && ( + secondaryMenu.hide()} /> + )} + {secondaryMenu.content} + + ); +} diff --git a/src/theme/Navbar/MobileSidebar/Toggle/index.tsx b/src/theme/Navbar/MobileSidebar/Toggle/index.tsx new file mode 100644 index 000000000..d8f9a530d --- /dev/null +++ b/src/theme/Navbar/MobileSidebar/Toggle/index.tsx @@ -0,0 +1,23 @@ +import React, {type ReactNode} from 'react'; +import {useNavbarMobileSidebar} from '@docusaurus/theme-common/internal'; +import {translate} from '@docusaurus/Translate'; +import IconMenu from '@theme/Icon/Menu'; + +export default function MobileSidebarToggle(): ReactNode { + const {toggle, shown} = useNavbarMobileSidebar(); + return ( + + ); +} diff --git a/src/theme/Navbar/MobileSidebar/index.tsx b/src/theme/Navbar/MobileSidebar/index.tsx new file mode 100644 index 000000000..6ad1ef045 --- /dev/null +++ b/src/theme/Navbar/MobileSidebar/index.tsx @@ -0,0 +1,44 @@ +import React, {type ReactNode} from 'react'; +import { + useLockBodyScroll, + useNavbarMobileSidebar, +} from '@docusaurus/theme-common/internal'; +import NavbarMobileSidebarLayout from '@theme/Navbar/MobileSidebar/Layout'; +import NavbarMobileSidebarHeader from '@theme/Navbar/MobileSidebar/Header'; +import NavbarMobileSidebarPrimaryMenu from '@theme/Navbar/MobileSidebar/PrimaryMenu'; +import NavbarMobileSidebarSecondaryMenu from '@theme/Navbar/MobileSidebar/SecondaryMenu'; + +export default function NavbarMobileSidebar(): ReactNode { + const mobileSidebar = useNavbarMobileSidebar(); + useLockBodyScroll(mobileSidebar.shown); + + // Force render on desktop if we are in the "Citizen" vertical layout mode + // We can check window width or just always render it and let CSS hide it if needed. + // However, useNavbarMobileSidebar hook might return shouldRender=false on desktop. + + // We override the check. + // Note: mobileSidebar.shouldRender is usually true if (mobileSidebar.shown || isMobile) + // But on desktop, isMobile is false, and shown is false initially. + + // If we want it to be renderable so we can toggle it via CSS/JS, we should return it. + // But wait, if we return it, it might be visible if CSS doesn't hide it. + // Our CSS hides it by default on desktop unless .navbar-sidebar--show is present. + + // So let's just render it always, or at least when we want. + // But `useLockBodyScroll` might be annoying if it locks body on desktop when we don't want to. + // Actually, `mobileSidebar.shown` drives the lock. + + // The issue is `if (!mobileSidebar.shouldRender) return null;` + // We will remove this check or modify it. + + // Let's just render it always. The CSS handles visibility. + // But we need to be careful about performance? It's fine. + + return ( + } + primaryMenu={} + secondaryMenu={} + /> + ); +} diff --git a/src/theme/Navbar/Search/index.tsx b/src/theme/Navbar/Search/index.tsx new file mode 100644 index 000000000..4da080c78 --- /dev/null +++ b/src/theme/Navbar/Search/index.tsx @@ -0,0 +1,13 @@ +import React, {type ReactNode} from 'react'; +import clsx from 'clsx'; +import type {Props} from '@theme/Navbar/Search'; + +import styles from './styles.module.css'; + +export default function NavbarSearch({children, className}: Props): ReactNode { + return ( +
+ {children} +
+ ); +} diff --git a/src/theme/Navbar/Search/styles.module.css b/src/theme/Navbar/Search/styles.module.css new file mode 100644 index 000000000..6dfe189df --- /dev/null +++ b/src/theme/Navbar/Search/styles.module.css @@ -0,0 +1,20 @@ +/* +Workaround to avoid rendering empty search container +See https://github.com/facebook/docusaurus/pull/9385 +*/ +.navbarSearchContainer:empty { + display: none; +} + +@media (max-width: 996px) { + .navbarSearchContainer { + position: absolute; + right: var(--ifm-navbar-padding-horizontal); + } +} + +@media (min-width: 997px) { + .navbarSearchContainer { + padding: 0 var(--ifm-navbar-item-padding-horizontal); + } +} diff --git a/src/theme/Navbar/index.tsx b/src/theme/Navbar/index.tsx index 26caa47dd..48ce38adb 100644 --- a/src/theme/Navbar/index.tsx +++ b/src/theme/Navbar/index.tsx @@ -1,28 +1,11 @@ -import { useLocation } from "@docusaurus/router"; -import type { WrapperProps } from "@docusaurus/types"; -import Navbar from "@theme-original/Navbar"; -import type NavbarType from "@theme/Navbar"; -import { type ReactNode } from "react"; -import { HeroBackground } from "../../components/HeroBackground"; - -type Props = WrapperProps; - -export default function NavbarWrapper(props: Props): ReactNode { - const location = useLocation(); - - const combinedClassName = [ - "absolute left-0 w-full text-primary shrink-0 z-1 pointer-events-none transition-all", - location.pathname === "/" ? "opacity-100" : "opacity-30" - ] - .filter(Boolean) - .join(" "); - - return ( -
- -
- -
-
- ); +import React, {type ReactNode} from 'react'; +import NavbarLayout from '@theme/Navbar/Layout'; +import NavbarContent from '@theme/Navbar/Content'; + +export default function Navbar(): ReactNode { + return ( + + + + ); }