From 783779f4ae83e8f54cd4d76e23e1c840afc7b273 Mon Sep 17 00:00:00 2001 From: Chuyaoyuan Date: Thu, 7 May 2026 12:03:58 +0800 Subject: [PATCH] update menu --- docusaurus.config.ts | 74 +++--- package.json | 3 - postcss.config.js | 6 - src/css/custom.css | 482 ++++++++++++++++++++++++++++++++---- src/pages/index.module.css | 418 ++++++++++++++++++++++++++++++- src/pages/index.tsx | 140 ++++++++--- src/snippets/tech-docs.html | 184 ++++++++++++++ tailwind.config.js | 77 ------ 8 files changed, 1155 insertions(+), 229 deletions(-) delete mode 100644 postcss.config.js create mode 100644 src/snippets/tech-docs.html delete mode 100644 tailwind.config.js diff --git a/docusaurus.config.ts b/docusaurus.config.ts index b4cc9a0..f0bf297 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -3,9 +3,16 @@ import type * as Preset from '@docusaurus/preset-classic'; import remarkMath from 'remark-math'; import rehypeKatex from 'rehype-katex'; import { config as loadEnv } from 'dotenv'; +import fs from 'fs'; +import path from 'path'; loadEnv({ path: '.env.local' }); +const techDocsHTML = fs.readFileSync( + path.join(__dirname, 'src/snippets/tech-docs.html'), + 'utf-8', +); + const config: Config = { title: 'CodeDocs 编程文档', tagline: 'CodeDocs 编程文档 -- 这里是一些技术人的编程文档', @@ -35,12 +42,21 @@ const config: Config = { }, themeConfig: { - algolia: { - apiKey: process.env.ALGOLIA_API_KEY ?? '', - appId: process.env.ALGOLIA_APP_ID ?? '', - indexName: 'code-docs', - contextualSearch: true, - searchParameters: {}, + // Only enable Algolia when API keys are provided + ...(process.env.ALGOLIA_API_KEY && process.env.ALGOLIA_APP_ID ? { + algolia: { + apiKey: process.env.ALGOLIA_API_KEY, + appId: process.env.ALGOLIA_APP_ID, + indexName: 'code-docs', + contextualSearch: true, + searchParameters: {}, + }, + } : {}), + // Enable sidebar collapse/expand button (dyte-style) + docs: { + sidebar: { + hideable: true, + }, }, navbar: { title: 'CodeDocs 编程文档', @@ -49,57 +65,33 @@ const config: Config = { src: 'img/logo.svg', }, items: [ + // ── Mega Dropdown: 技术文档 (left-right panel, mirrors dyte SDK dropdown) { + label: '技术文档', type: 'dropdown', - label: '📚 技术文档', + className: 'tech-docs-dropdown', position: 'left', items: [ { - type: 'doc', - docId: 'backend-doc/intro-docs', - label: '⚙️ 后端技术', - }, - { - type: 'doc', - docId: 'frontend-doc/intro-docs', - label: '⚛️ 前端开发', - }, - { - type: 'doc', - docId: 'LeetCode/intro-docs', - label: '🧠 算法与面试', + type: 'html', + value: techDocsHTML, + className: 'tech-docs-dropdown', }, ], }, + // ── Blog { - type: 'dropdown', - label: '🛠️ 工具与资源', + to: '/blog', + label: 'Blog', position: 'left', - items: [ - { - label: '📖 最佳实践', - href: '#', - }, - { - label: '🔗 常用链接', - href: '#', - }, - { - label: '📚 推荐阅读', - href: '#', - }, - ], - }, - { - to: '/blog', - label: '📝 Blog', - position: 'left' }, + // ── GitHub (right) { href: 'https://github.com/chuyaoyuan/code-docs', label: 'GitHub', position: 'right', }, + // ── Language toggle (right) { type: 'localeDropdown', position: 'right', diff --git a/package.json b/package.json index b308264..f5776fe 100644 --- a/package.json +++ b/package.json @@ -27,10 +27,7 @@ }, "devDependencies": { "@docusaurus/tsconfig": "^3.10.1", - "autoprefixer": "^10.5.0", "dotenv": "^16.4.7", - "postcss": "^8.5.14", - "tailwindcss": "^4.2.4", "typescript": "^5.4.5" }, "overrides": { diff --git a/postcss.config.js b/postcss.config.js deleted file mode 100644 index 12a703d..0000000 --- a/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -}; diff --git a/src/css/custom.css b/src/css/custom.css index 3860465..391ef43 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -1,49 +1,88 @@ /* stylelint-disable docusaurus/copyright-header */ -/** - * Any CSS included here will be global. The classic template - * bundles Infima by default. Infima is a CSS framework designed to - * work well for content-centric websites. - */ -/* Import Tailwind CSS */ -@import 'tailwindcss/base'; -@import 'tailwindcss/components'; -@import 'tailwindcss/utilities'; - -/* You can override the default Infima variables here. */ +/* ══════════════════════════════════════════════════ + Base CSS variables (mirrors dyte-io/docs token system) +══════════════════════════════════════════════════ */ :root { + /* Infima primary (matches dyte blue) */ --ifm-color-primary: #2160fd; - --ifm-color-primary-dark: #1850d8; - --ifm-color-primary-darker: #1442c4; - --ifm-color-primary-darkest: #102ca0; - --ifm-color-primary-light: #4d7ffe; - --ifm-color-primary-lighter: #7a9eff; - --ifm-color-primary-lightest: #a8c0ff; - - --docs-color-primary: rgb(33 96 253); - --docs-color-primary-100: rgb(26 144 255); - --docs-color-primary-200: rgb(33 96 253); - - --docs-color-secondary-1000: rgb(0 0 0); - --docs-color-secondary-900: rgb(25 25 25); - --docs-color-secondary-800: rgb(38 38 38); - --docs-color-secondary-700: rgb(71 71 71); - - --docs-color-text: rgb(31 41 55); - --docs-color-text-100: rgb(107 114 128); - --docs-color-text-400: rgb(153 153 153); - - --docs-color-text-secondary: rgb(107 114 128); - - --ifm-code-font-size: 95%; + --ifm-color-primary-dark: #1959fc; + --ifm-color-primary-darker: #0f51f8; + --ifm-color-primary-darkest: #0042e7; + --ifm-color-primary-light: #3d72f8; + --ifm-color-primary-lighter: #477af8; + --ifm-color-primary-lightest: #6791fc; + + /* Docs color tokens */ + --docs-color-primary: #2160fd; + --docs-color-primary-tint: rgba(33, 96, 253, 0.16); + --docs-color-primary-tint-light: rgba(33, 96, 253, 0.24); + + /* Background */ + --docs-color-background: #ffffff; + --docs-color-background-100: #f8f8f8; + --docs-color-background-200: #efefef; + --docs-color-background-300: #dcdcdc; + + /* Text */ + --docs-color-text: #000000; + --docs-color-text-100: #646464; + --docs-color-text-400: #474747; + + /* Border */ + --docs-color-border: #dadde1; + + /* Secondary scale (light mode = lighter greys) */ + --docs-color-secondary-700: 232 232 236; + --docs-color-secondary-800: 245 245 247; + --docs-color-secondary-900: 251 251 251; + --docs-color-secondary-1000: 255 255 255; + + /* Navbar */ + --ifm-navbar-shadow: none; + --ifm-navbar-padding-horizontal: 0.75rem; + + /* Misc */ + --ifm-code-font-size: 92%; + --ifm-toc-border-color: #dedede; + --docusaurus-highlighted-code-line-bg: rgba(147, 178, 244, 0.38); } -[data-theme='dark'] { - --docs-color-text: rgb(243 244 246); - --docs-color-text-secondary: rgb(209 213 219); +html[data-theme='dark'] { + --ifm-color-primary: #1a90ff; + --docs-color-primary: #1a90ff; + + --docs-color-background: #161616; + --docs-color-background-100: #1c1c1c; + --docs-color-background-200: #2a2a2a; + --docs-color-background-300: #2e2e2e; + + --docs-color-text: #ffffff; + --docs-color-text-100: #b4b4b4; + --docs-color-text-400: #999999; + + --docs-color-border: #2e2e2e; + + --docs-color-secondary-700: 71 71 71; + --docs-color-secondary-800: 38 38 38; + --docs-color-secondary-900: 25 25 25; + --docs-color-secondary-1000: 0 0 0; + + --ifm-background-color: #161616; + --ifm-background-surface-color: #161616; + --ifm-footer-background-color: #1c1c1c; + --ifm-toc-border-color: #2e2e2e; + --ifm-color-content: #e7e7e7; + --docusaurus-highlighted-code-line-bg: rgba(105, 105, 105, 0.3); +} + +/* ══════════════════════════════════════════════════ + Base element styles +══════════════════════════════════════════════════ */ +nav.navbar { + border-bottom: 1px solid var(--ifm-toc-border-color); } -/* Code highlighting */ .docusaurus-highlight-code-line { background-color: rgb(72, 77, 91); display: block; @@ -51,7 +90,7 @@ padding: 0 var(--ifm-pre-padding); } -/* Enhanced link hover decoration */ +/* Disable underline-on-hover in nav/sidebar */ .navbar__link, .menu__link, .table-of-contents__link, @@ -61,27 +100,362 @@ } .menu__link { - --ifm-link-hover-color: var(--ifm-color-primary); + --ifm-menu-color-background-active: var(--docs-color-primary-tint); } -/* Smooth transitions */ -* { - @apply transition-colors; +/* Dropdown chevron (matches dyte) */ +.dropdown > .navbar__link { + display: flex; + align-items: center; } -/* Hero section enhancements */ -.hero { - background: linear-gradient( - 135deg, - rgba(33, 96, 253, 0.05) 0%, - rgba(6, 182, 212, 0.05) 100% - ); +.dropdown > .navbar__link:after { + content: ''; + border: none; + position: static; + top: auto; + transform: none; + width: 12px; + height: 12px; + margin-left: 4px; + background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' fill='none' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4.293 8.293a1 1 0 0 1 1.414 0L12 14.586l6.293-6.293a1 1 0 1 1 1.414 1.414l-7 7a1 1 0 0 1-1.414 0l-7-7a1 1 0 0 1 0-1.414Z' fill='%23888888'/%3E%3C/svg%3E"); + background-size: 12px; + background-repeat: no-repeat; } -.hero--primary { - background-color: #f9fafb; +html[data-theme='dark'] .dropdown > .navbar__link:after { + background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' fill='none' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4.293 8.293a1 1 0 0 1 1.414 0L12 14.586l6.293-6.293a1 1 0 1 1 1.414 1.414l-7 7a1 1 0 0 1-1.414 0l-7-7a1 1 0 0 1 0-1.414Z' fill='%23cccccc'/%3E%3C/svg%3E"); } -[data-theme='dark'] .hero--primary { - background-color: #1a1a2e; +.dropdown:hover > .navbar__link:after { + background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' fill='none' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4.293 8.293a1 1 0 0 1 1.414 0L12 14.586l6.293-6.293a1 1 0 1 1 1.414 1.414l-7 7a1 1 0 0 1-1.414 0l-7-7a1 1 0 0 1 0-1.414Z' fill='%232160fd'/%3E%3C/svg%3E") !important; } + +/* ══════════════════════════════════════════════════ + Tech Dropdown: Mega Menu (left panel + right panel) + Mirrors dyte's SDK dropdown pattern exactly +══════════════════════════════════════════════════ */ + +/* Docusaurus wraps the html item in a ul.dropdown__menu */ +.tech-docs-dropdown + ul.dropdown__menu { + padding: 0; + border-radius: 16px; + overflow: hidden; + border: 1px solid var(--docs-color-border); + background: transparent; + min-width: 750px; + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12); +} + +.tech-dropdown { + display: flex; + min-height: 280px; +} + +/* Left Category Panel */ +.tech-dropdown-left { + display: flex; + flex-direction: column; + gap: 0; + background: rgb(var(--docs-color-secondary-1000)); + min-width: 200px; + padding: 0.75rem; + border-right: 1px solid var(--docs-color-border); +} + +.tech-menu-item { + display: flex; + align-items: flex-start; + gap: 0.6rem; + padding: 0.65rem 0.75rem; + border-radius: 8px; + cursor: pointer; + text-decoration: none !important; + color: var(--docs-color-text) !important; + border: 2px solid transparent; + transition: background 0.15s, border-color 0.15s; +} + +.tech-menu-item:hover { + background: rgb(var(--docs-color-secondary-800) / 0.6); + border-color: transparent; + color: var(--docs-color-text) !important; +} + +/* Active category item (matches dyte's left border style) */ +body[data-tech-menu='backend'] [data-dropdown-tech-menu='backend'], +body[data-tech-menu='frontend'] [data-dropdown-tech-menu='frontend'], +body[data-tech-menu='algorithms'] [data-dropdown-tech-menu='algorithms'] { + border-left-color: #2160fd; + background: rgb(var(--docs-color-secondary-800) / 0.5); +} + +.tech-menu-icon { + font-size: 1.2rem; + flex-shrink: 0; + margin-top: 0.1rem; +} + +.tech-menu-item-title { + font-size: 0.875rem; + font-weight: 600; + line-height: 1.3; + color: var(--docs-color-text); +} + +.tech-menu-item-desc { + font-size: 0.75rem; + color: var(--docs-color-text-100); + margin: 0; + line-height: 1.4; +} + +/* Right Content Panel */ +.tech-dropdown-right { + flex: 1; + padding: 1rem 1.25rem; + background: rgb(var(--docs-color-secondary-900)); +} + +/* Panel visibility: dyte's body data-attribute pattern */ +[data-dropdown-tech] { + display: none; +} + +.tech-panel-group { + min-width: 150px; +} + +.tech-panel-heading { + font-size: 0.78rem !important; + font-weight: 700 !important; + text-transform: uppercase; + letter-spacing: 0.06em; + color: var(--docs-color-text-100) !important; + margin-bottom: 0.5rem !important; + margin-top: 0 !important; +} + +.tech-panel-links { + list-style: none; + padding: 0; + margin: 0; + display: flex; + flex-direction: row; + flex-wrap: wrap; + gap: 0.2rem 0.4rem; +} + +.tech-link { + display: flex; + align-items: center; + gap: 0.4rem; + padding: 0.35rem 0.5rem; + border-radius: 6px; + font-size: 0.84rem; + text-decoration: none !important; + color: var(--docs-color-text) !important; + transition: background 0.15s, color 0.15s; +} + +.tech-link:hover { + background: rgba(33, 96, 253, 0.08); + color: #2160fd !important; +} + +[data-theme='dark'] .tech-link:hover { + background: rgba(26, 144, 255, 0.1); + color: #1a90ff !important; +} + +/* ══════════════════════════════════════════════════ + Right panel: groups stack vertically, links flow horizontally +══════════════════════════════════════════════════ */ +body:not([data-tech-menu]) [data-dropdown-tech='backend'], +body[data-tech-menu='backend'] [data-dropdown-tech='backend'], +body[data-tech-menu='frontend'] [data-dropdown-tech='frontend'], +body[data-tech-menu='algorithms'] [data-dropdown-tech='algorithms'] { + display: flex !important; + flex-direction: column; + gap: 1.25rem; + width: 100%; +} + +/* ══════════════════════════════════════════════════ + Sidebar: dyte-style collapse/expand button +══════════════════════════════════════════════════ */ +aside.theme-doc-sidebar-container { + position: relative; + z-index: 2; /* ensure sidebar renders above main content */ + clip-path: inset(0px -140px); +} + +/* ── Collapse button (visible when sidebar is expanded) ── */ +/* Title is translated to Chinese in zh-cn locale, so target both */ +.theme-doc-sidebar-container button[title='Collapse sidebar'], +.theme-doc-sidebar-container button[title='收起侧边栏'] { + position: absolute; + top: 95vh; + right: -14px; + width: 28px; + height: 28px; + padding: 0; + border-radius: 4px; + z-index: 10; + background-size: 16px; + background-position: center; + background-repeat: no-repeat; + background-color: var(--docs-color-border); + border: none; + cursor: pointer; + background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' fill='none' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M15.707 4.293a1 1 0 0 1 0 1.414L9.414 12l6.293 6.293a1 1 0 0 1-1.414 1.414l-7-7a1 1 0 0 1 0-1.414l7-7a1 1 0 0 1 1.414 0Z' fill='%23181818'/%3E%3C/svg%3E"); +} + +html[data-theme='dark'] .theme-doc-sidebar-container button[title='Collapse sidebar'], +html[data-theme='dark'] .theme-doc-sidebar-container button[title='收起侧边栏'] { + background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' fill='none' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M15.707 4.293a1 1 0 0 1 0 1.414L9.414 12l6.293 6.293a1 1 0 0 1-1.414 1.414l-7-7a1 1 0 0 1 0-1.414l7-7a1 1 0 0 1 1.414 0Z' fill='%23ffffff'/%3E%3C/svg%3E"); +} + +/* ── Collapse button: hide Docusaurus default SVG (we use bg-image) ── */ +.theme-doc-sidebar-container button[title='Collapse sidebar'] svg, +.theme-doc-sidebar-container button[title='收起侧边栏'] svg { + display: none; +} + +/* ── Expand button (visible when sidebar is collapsed to 30px strip) ── */ +/* Strategy: keep the div as full-area click target, use ::after for the visible icon */ +.theme-doc-sidebar-container div[title='Expand sidebar'], +.theme-doc-sidebar-container div[title='展开侧边栏'] { + position: absolute !important; + top: 0 !important; + left: 0 !important; + right: 0 !important; + bottom: 0 !important; + width: 100% !important; + height: 100% !important; + background-image: none !important; + background-color: transparent !important; + display: flex !important; + align-items: flex-end !important; + justify-content: center !important; + padding-bottom: 5vh !important; +} + +/* Visible icon at bottom of the strip */ +.theme-doc-sidebar-container div[title='Expand sidebar']::after, +.theme-doc-sidebar-container div[title='展开侧边栏']::after { + content: ''; + display: block; + width: 28px; + height: 28px; + flex-shrink: 0; + border-radius: 4px; + background-color: var(--docs-color-border); + background-size: 16px; + background-position: center; + background-repeat: no-repeat; + background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' fill='none' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8.293 4.293a1 1 0 0 0 0 1.414L14.586 12l-6.293 6.293a1 1 0 1 0 1.414 1.414l7-7a1 1 0 0 0 0-1.414l-7-7a1 1 0 0 0-1.414 0Z' fill='%23181818'/%3E%3C/svg%3E"); +} + +html[data-theme='dark'] .theme-doc-sidebar-container div[title='Expand sidebar']::after, +html[data-theme='dark'] .theme-doc-sidebar-container div[title='展开侧边栏']::after { + background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' fill='none' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8.293 4.293a1 1 0 0 0 0 1.414L14.586 12l-6.293 6.293a1 1 0 1 0 1.414 1.414l7-7a1 1 0 0 0 0-1.414l-7-7a1 1 0 0 0-1.414 0Z' fill='%23ffffff'/%3E%3C/svg%3E"); +} + +/* Hide the default SVG inside the expand div */ +.theme-doc-sidebar-container div[title='Expand sidebar'] svg, +.theme-doc-sidebar-container div[title='展开侧边栏'] svg { + display: none; +} + +/* ══════════════════════════════════════════════════ + Sidebar enhancements +══════════════════════════════════════════════════ */ +.menu__link { + border-radius: 4px 0 0 4px; + font-size: 14px; +} + +ul.menu__list > li > a.menu__link--active { + border-right: 1px solid var(--ifm-color-primary); +} + +/* ══════════════════════════════════════════════════ + Footer tweaks — dyte-style dark palette +══════════════════════════════════════════════════ */ +.footer, +.footer--dark { + background-color: #1c1c1c !important; + border-top: 1px solid #2e2e2e !important; + padding: 3rem 0 2rem; + color: #b4b4b4; +} + +.footer__title { + font-size: 14px; + font-weight: normal; + color: #b4b4b4; + margin-bottom: 0.5rem; +} + +.footer__item { + font-size: 14px; + font-weight: normal; +} + +.footer__link-item { + color: #b4b4b4; + transition: color 0.15s; +} + +.footer__link-item:hover { + text-decoration: none; + color: #ffffff; +} + +.footer__copyright { + margin-top: 32px; + font-size: 14px; + color: #b4b4b4; +} + +/* ══════════════════════════════════════════════════ + Code block tweaks — dyte-style +══════════════════════════════════════════════════ */ + +/* Reference variable (used by details/admonitions) — do NOT use as pre background */ +:root { + --docs-color-code-background: #f6f8fa; + --code-border-color: var(--docs-color-border); +} + +html[data-theme='dark'] { + --docs-color-code-background: #1e1e1e; +} + +/* Only add a border — let Prism theme control the background/colors */ +pre.prism-code { + border: 1px solid var(--code-border-color); +} + +/* Inline code */ +code:not(pre code) { + background-color: var(--docs-color-background-200); + border: 1px solid var(--docs-color-border); + border-radius: 4px; + font-size: 0.88em; + padding: 0.1em 0.35em; +} + +/* Code block title bar */ +.codeBlockTitle_node_modules-\@docusaurus-theme-classic-lib-theme-CodeBlock-Content-styles-module { + background-color: var(--docs-color-background-100) !important; + border-bottom: 1px solid var(--code-border-color) !important; + font-size: 13px; +} + +/* Details/Admonition code blocks */ +details code { + background-color: var(--docs-color-background); +} + diff --git a/src/pages/index.module.css b/src/pages/index.module.css index 5c0d4f6..429a45b 100644 --- a/src/pages/index.module.css +++ b/src/pages/index.module.css @@ -1,10 +1,414 @@ /* stylelint-disable docusaurus/copyright-header */ -/** - * CSS files with the .module.css suffix will be treated as CSS modules - * and scoped locally. - */ +/* ══════════════════════════════════════════════════════════ + Homepage Wrapper +══════════════════════════════════════════════════════════ */ +.homepageWrapper { + display: flex; + flex-direction: column; +} +/* ══════════════════════════════════════════════════════════ + Hero Background — dyte's noise-bg with grid pattern +══════════════════════════════════════════════════════════ */ +.heroBg { + padding-bottom: 4rem; + background-color: #fafafa; + background-image: + linear-gradient(rgba(33, 96, 253, 0.03) 1px, transparent 1px), + linear-gradient(90deg, rgba(33, 96, 253, 0.03) 1px, transparent 1px); + background-size: 40px 40px; + border-bottom: 1px solid var(--ifm-toc-border-color); +} + +[data-theme='dark'] .heroBg { + background-color: #111; + background-image: + linear-gradient(rgba(33, 96, 253, 0.06) 1px, transparent 1px), + linear-gradient(90deg, rgba(33, 96, 253, 0.06) 1px, transparent 1px); + background-size: 40px 40px; +} + +/* ══════════════════════════════════════════════════════════ + Hero Top Section (title + subtitle) +══════════════════════════════════════════════════════════ */ +.heroTop { + padding: 5rem 1.5rem 3rem; + text-align: center; + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; +} + +.heroBadge { + display: inline-block; + padding: 0.3rem 0.9rem; + border-radius: 9999px; + border: 1px solid rgba(33, 96, 253, 0.35); + background: rgba(33, 96, 253, 0.08); + color: #2160fd; + font-size: 0.8rem; + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; +} + +[data-theme='dark'] .heroBadge { + background: rgba(33, 96, 253, 0.15); + color: #7a9eff; + border-color: rgba(33, 96, 253, 0.4); +} + +.heroTitle { + font-size: 3.5rem; + font-weight: 800; + line-height: 1.1; + letter-spacing: -0.03em; + color: #0f172a; + margin: 0; +} + +[data-theme='dark'] .heroTitle { + color: #f1f5f9; +} + +.heroTitleAccent { + color: #2160fd; +} + +[data-theme='dark'] .heroTitleAccent { + color: #7a9eff; +} + +.heroSubtitle { + max-width: 560px; + font-size: 1.1rem; + line-height: 1.7; + color: #475569; + margin: 0; +} + +[data-theme='dark'] .heroSubtitle { + color: #94a3b8; +} + +.heroButtons { + display: flex; + gap: 0.75rem; + flex-wrap: wrap; + justify-content: center; + margin-top: 0.5rem; +} + +.btnPrimary { + display: inline-flex; + align-items: center; + padding: 0.65rem 1.5rem; + border-radius: 8px; + background: #2160fd; + color: #fff !important; + font-weight: 600; + font-size: 0.95rem; + text-decoration: none !important; + transition: background 0.2s, transform 0.15s, box-shadow 0.2s; + box-shadow: 0 2px 12px rgba(33, 96, 253, 0.35); +} + +.btnPrimary:hover { + background: #1442c4; + transform: translateY(-1px); + box-shadow: 0 4px 20px rgba(33, 96, 253, 0.45); + color: #fff !important; +} + +.btnOutline { + display: inline-flex; + align-items: center; + padding: 0.65rem 1.5rem; + border-radius: 8px; + border: 1.5px solid #cbd5e1; + background: transparent; + color: #334155 !important; + font-weight: 600; + font-size: 0.95rem; + text-decoration: none !important; + transition: border-color 0.2s, color 0.2s, background 0.2s; +} + +.btnOutline:hover { + border-color: #2160fd; + color: #2160fd !important; + background: rgba(33, 96, 253, 0.04); +} + +[data-theme='dark'] .btnOutline { + border-color: #334155; + color: #cbd5e1 !important; +} + +[data-theme='dark'] .btnOutline:hover { + border-color: #7a9eff; + color: #7a9eff !important; +} + +/* ══════════════════════════════════════════════════════════ + Hero Cards (dyte-style: dark bg + blue hover gradient) +══════════════════════════════════════════════════════════ */ +.heroCards { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 1.25rem; + max-width: 1200px; + margin: 0 auto; + padding: 0 1.5rem; +} + +/* The card itself is the */ +.heroCard { + position: relative; + display: flex; + flex-direction: column; + justify-content: space-between; + width: 360px; + border-radius: 1.5rem; /* rounded-3xl */ + border: 1px solid #e2e8f0; /* secondary-700 light */ + background: #f8fafc; /* secondary-900 light */ + overflow: hidden; + cursor: pointer; + text-decoration: none !important; + color: #0f172a !important; + transition: border-color 0.25s ease, + background 0.25s ease, + box-shadow 0.25s ease, + color 0.25s ease, + transform 0.2s ease; +} + +[data-theme='dark'] .heroCard { + border-color: #1e293b; /* secondary-700 dark */ + background: #0f172a; /* secondary-900 dark */ + color: #f1f5f9 !important; +} + +/* ── Hover State ───────────────────────────────────── */ +.heroCard:hover { + border-color: #2160fd; + background: linear-gradient( + 135deg, + rgba(33, 96, 253, 0.15) 0%, + transparent 60% + ); + box-shadow: 0 0 0 1px rgba(33, 96, 253, 0.25), + 0 8px 30px rgba(33, 96, 253, 0.12); + color: #2160fd !important; + transform: translateY(-3px); +} + +[data-theme='dark'] .heroCard:hover { + background: linear-gradient( + 135deg, + rgba(33, 96, 253, 0.25) 0%, + transparent 60% + ); +} + +.heroCardContent { + padding: 1.5rem; + display: flex; + flex-direction: column; + gap: 0.75rem; + flex: 1; +} + +.heroCardHeader { + display: flex; + align-items: center; + gap: 0.75rem; +} + +.heroCardEmoji { + font-size: 1.75rem; + line-height: 1; + width: 2.5rem; + height: 2.5rem; + display: flex; + align-items: center; + justify-content: center; + border-radius: 0.75rem; + background: rgba(33, 96, 253, 0.08); + flex-shrink: 0; + transition: background 0.25s, transform 0.2s; +} + +.heroCard:hover .heroCardEmoji { + background: rgba(33, 96, 253, 0.18); + transform: scale(1.1); +} + +.heroCardTitle { + font-size: 1.2rem; + font-weight: 700; + margin: 0; + color: #0f172a; + transition: color 0.25s; +} + +[data-theme='dark'] .heroCardTitle { + color: #f1f5f9; +} + +.heroCard:hover .heroCardTitle { + color: #2160fd; +} + +[data-theme='dark'] .heroCard:hover .heroCardTitle { + color: #7a9eff; +} + +.heroCardText { + font-size: 0.9rem; + line-height: 1.65; + color: #64748b; + margin: 0; + transition: color 0.25s; +} + +[data-theme='dark'] .heroCardText { + color: #94a3b8; +} + +.heroCard:hover .heroCardText { + color: #1e40af; +} + +[data-theme='dark'] .heroCard:hover .heroCardText { + color: #93c5fd; +} + +.heroCardTags { + display: flex; + flex-wrap: wrap; + gap: 0.4rem; + margin-top: 0.25rem; +} + +.heroCardTag { + display: inline-block; + padding: 0.15rem 0.55rem; + border-radius: 4px; + background: rgba(33, 96, 253, 0.07); + color: #2160fd; + font-size: 0.72rem; + font-weight: 600; + transition: background 0.2s; +} + +.heroCard:hover .heroCardTag { + background: rgba(33, 96, 253, 0.15); +} + +[data-theme='dark'] .heroCardTag { + background: rgba(33, 96, 253, 0.12); + color: #7a9eff; +} + +/* Arrow in top-right */ +.heroCardArrow { + position: absolute; + top: 1.1rem; + right: 1.2rem; + font-size: 1.25rem; + opacity: 0; + transform: translate(6px, -6px); + color: #2160fd; + transition: opacity 0.25s, transform 0.25s; +} + +.heroCard:hover .heroCardArrow { + opacity: 1; + transform: translate(0, 0); +} + +/* ══════════════════════════════════════════════════════════ + Feature Strip +══════════════════════════════════════════════════════════ */ +.featuresStrip { + background: #fff; + border-bottom: 1px solid var(--ifm-toc-border-color); + padding: 2.5rem 1.5rem; +} + +[data-theme='dark'] .featuresStrip { + background: #161616; +} + +.featuresInner { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 1.5rem; + max-width: 1100px; + margin: 0 auto; +} + +@media (max-width: 900px) { + .featuresInner { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 480px) { + .featuresInner { + grid-template-columns: 1fr; + } + .heroCards { + flex-direction: column; + align-items: center; + } + .heroCard { + width: 100%; + max-width: 380px; + } + .heroTitle { + font-size: 2.2rem; + } +} + +.featureItem { + display: flex; + align-items: flex-start; + gap: 0.8rem; +} + +.featureIcon { + font-size: 1.6rem; + flex-shrink: 0; + margin-top: 0.1rem; +} + +.featureTitle { + font-size: 0.9rem; + font-weight: 600; + color: #0f172a; + margin-bottom: 0.25rem; +} + +[data-theme='dark'] .featureTitle { + color: #f1f5f9; +} + +.featureDesc { + font-size: 0.8rem; + line-height: 1.5; + color: #64748b; +} + +[data-theme='dark'] .featureDesc { + color: #94a3b8; +} + +/* Legacy - kept for compatibility */ .heroBanner { padding: 4rem 0; text-align: center; @@ -12,12 +416,6 @@ overflow: hidden; } -@media screen and (max-width: 966px) { - .heroBanner { - padding: 2rem; - } -} - .buttons { display: flex; align-items: center; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index d72c3b1..66f3add 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,55 +1,119 @@ import React from 'react'; -import clsx from 'clsx'; import Layout from '@theme/Layout'; import Link from '@docusaurus/Link'; -import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import styles from './index.module.css'; -import HomepageFeatures from '../components/HomepageFeatures'; -function HomepageHeader(): JSX.Element { - const { siteConfig } = useDocusaurusContext(); +/* ── Hero Cards ────────────────────────────────────────────── */ +const HERO_CARDS = [ + { + id: 'backend', + emoji: '⚙️', + title: '后端技术', + link: '/docs/backend-doc/intro-docs', + text: '深入讲解 Spring Boot / Spring Cloud 核心概念,微服务架构、分布式缓存与性能调优,含真实项目案例', + tags: ['Spring Boot', 'Spring Cloud', 'MySQL', 'Redis'], + }, + { + id: 'frontend', + emoji: '⚛️', + title: '前端开发', + link: '/docs/frontend-doc/intro-docs', + text: '系统化学习 React / Vue 现代框架,工程化实践、状态管理与跨端开发,构建高质量前端应用', + tags: ['React', 'Vue 3', 'Vite', 'TypeScript'], + }, + { + id: 'algorithms', + emoji: '🧠', + title: '算法与面试', + link: '/docs/LeetCode/intro-docs', + text: '精选 LeetCode 题解与数据结构深析,系统设计面试指南,快速突破大厂技术面试关卡', + tags: ['LeetCode', '数据结构', '系统设计', '剑指Offer'], + }, +]; + +/* ── Feature List ───────────────────────────────────────────── */ +const FEATURES = [ + { icon: '🔍', title: '全文搜索', desc: '集成 Algolia DocSearch,毫秒级检索,快速定位任意知识点' }, + { icon: '🌙', title: '深色模式', desc: '完整支持深色/浅色主题切换,护眼阅读体验' }, + { icon: '📱', title: '响应式设计', desc: '适配桌面、平板、手机,随时随地查阅技术文档' }, + { icon: '⚡', title: '持续更新', desc: '技术团队持续维护,同步最新技术栈与面试题解' }, +]; + +function HeroCard({ emoji, title, link, text, tags }) { return ( -
-
-

🚀 {siteConfig.title}

-

{siteConfig.tagline}

-

- 为全栈、全端工程师精心打造的技术文档 + 算法面试 + 最佳实践一站式参考库 -

-
- - ⚙️ 后端技术 - - - ⚛️ 前端开发 - - - 🧠 算法面试 - + +
+
+ {emoji} +

{title}

+
+

{text}

+
+ {tags.map(tag => ( + {tag} + ))}
-
+
+ + ); +} + +function FeatureItem({ icon, title, desc }) { + return ( +
+ {icon} +
+
{title}
+
{desc}
+
+
); } export default function Home(): JSX.Element { - const { siteConfig } = useDocusaurusContext(); return ( - -
- -
+ title="CodeDocs — 全栈技术文档" + description="覆盖后端、前端、算法面试的一站式技术文档库,为全栈工程师打造" + wrapperClassName={styles.homepageWrapper} + > + {/* ── Hero ──────────────────────────────────────── */} +
+
+ 全栈工程师技术速查站 +

+ 一站式技术文档库 +

+

+ 覆盖 后端 · 前端 · 算法面试,为全栈工程师打造的权威参考手册 +

+
+ + 立即阅读 + + + 浏览全部文档 + +
+
+ + {/* ── Hero Cards ────────────────────────────── */} +
+ {HERO_CARDS.map(card => ( + + ))} +
+
+ + {/* ── Feature Strip ────────────────────────────── */} +
+
+ {FEATURES.map(f => ( + + ))} +
+
); } diff --git a/src/snippets/tech-docs.html b/src/snippets/tech-docs.html new file mode 100644 index 0000000..15fbad6 --- /dev/null +++ b/src/snippets/tech-docs.html @@ -0,0 +1,184 @@ +
+ + + + + +
diff --git a/tailwind.config.js b/tailwind.config.js deleted file mode 100644 index 759ccca..0000000 --- a/tailwind.config.js +++ /dev/null @@ -1,77 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -module.exports = { - corePlugins: { - preflight: false, - }, - darkMode: ['class', '[data-theme="dark"]'], - content: ['./src/**/*.{jsx,tsx,html}', './docs/**/*.{jsx,tsx,html}'], - theme: { - extend: { - colors: { - primary: { - 50: '#f0f5ff', - 100: '#e0ebff', - 200: '#c5d9ff', - 300: '#a3bdff', - 400: '#7a99ff', - 500: '#2160fd', - 600: '#1e4fd4', - 700: '#1939a8', - 800: '#15278a', - 900: '#121d70', - }, - slate: { - 50: '#f8fafc', - 100: '#f1f5f9', - 200: '#e2e8f0', - 300: '#cbd5e1', - 400: '#94a3b8', - 500: '#64748b', - 600: '#475569', - 700: '#334155', - 800: '#1e293b', - 900: '#0f172a', - }, - }, - fontFamily: { - sans: ['Inter', 'system-ui', 'sans-serif'], - }, - spacing: { - '1': '0.25rem', - '2': '0.5rem', - '3': '0.75rem', - '4': '1rem', - '6': '1.5rem', - '8': '2rem', - '12': '3rem', - '16': '4rem', - '20': '5rem', - '24': '6rem', - }, - borderRadius: { - 'sm': '0.375rem', - 'md': '0.5rem', - 'lg': '0.75rem', - 'xl': '1rem', - '2xl': '1.5rem', - '3xl': '2rem', - }, - boxShadow: { - 'sm': '0 1px 2px 0 rgb(0 0 0 / 0.05)', - 'md': '0 4px 6px -1px rgb(0 0 0 / 0.1)', - 'lg': '0 10px 15px -3px rgb(0 0 0 / 0.1)', - 'xl': '0 20px 25px -5px rgb(0 0 0 / 0.1)', - }, - transitionProperty: { - 'colors': 'color, background-color, border-color, text-decoration-color, fill, stroke', - 'all': 'all', - }, - transitionDuration: { - '200': '200ms', - '300': '300ms', - '500': '500ms', - }, - }, - }, - plugins: [], -};