From 6a1d21f3aadcfa077aacc29d858d63548741d2cd Mon Sep 17 00:00:00 2001 From: Yue-plus Date: Thu, 29 Aug 2024 02:46:15 +0800 Subject: [PATCH] feat(RootLayout): SubNavigation --- package.json | 4 +- pnpm-lock.yaml | 70 +++++++++++++++---------------- src/_types/SubNavigationItem.ts | 4 ++ src/components/header/NavMenu.tsx | 62 +++++++++++++++++++++------ src/layouts/InfoLayout.astro | 5 ++- src/layouts/RootLayout.astro | 6 ++- src/pages/docs/[...slug].astro | 26 +++++++----- src/pages/docs/index.astro | 15 +++++-- 8 files changed, 123 insertions(+), 69 deletions(-) create mode 100644 src/_types/SubNavigationItem.ts diff --git a/package.json b/package.json index b7100d5..9b27824 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,8 @@ "@nanostores/react": "^0.7.3", "@types/react": "^18.3.4", "@types/react-dom": "^18.3.0", - "astro": "^4.14.5", - "nanostores": "^0.11.2", + "astro": "^4.14.6", + "nanostores": "^0.11.3", "react": "^18.3.1", "react-dom": "^18.3.1", "sass": "^1.77.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4ab71c0..ca0230c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,10 +16,10 @@ importers: version: 3.6.2(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(vite@5.4.2(sass@1.77.8)) '@astrojs/tailwind': specifier: ^5.1.0 - version: 5.1.0(astro@4.14.5(rollup@4.21.1)(sass@1.77.8)(typescript@5.5.4))(tailwindcss@3.4.10) + version: 5.1.0(astro@4.14.6(rollup@4.21.1)(sass@1.77.8)(typescript@5.5.4))(tailwindcss@3.4.10) '@nanostores/react': specifier: ^0.7.3 - version: 0.7.3(nanostores@0.11.2)(react@18.3.1) + version: 0.7.3(nanostores@0.11.3)(react@18.3.1) '@types/react': specifier: ^18.3.4 version: 18.3.4 @@ -27,11 +27,11 @@ importers: specifier: ^18.3.0 version: 18.3.0 astro: - specifier: ^4.14.5 - version: 4.14.5(rollup@4.21.1)(sass@1.77.8)(typescript@5.5.4) + specifier: ^4.14.6 + version: 4.14.6(rollup@4.21.1)(sass@1.77.8)(typescript@5.5.4) nanostores: - specifier: ^0.11.2 - version: 0.11.2 + specifier: ^0.11.3 + version: 0.11.3 react: specifier: ^18.3.1 version: 18.3.1 @@ -778,8 +778,8 @@ packages: array-iterate@2.0.1: resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==} - astro@4.14.5: - resolution: {integrity: sha512-sv47kPE6FnvyxxHHcCePNwTKpOMKBq0r1m6WZYg6ag9j3yF9m72ov64NFB7c+hAMDUKgsHfVdLKjOOqDC/c+fA==} + astro@4.14.6: + resolution: {integrity: sha512-MIDyNhtu3L4uakHvlTprh21eQPehYOtZSuSLtd+r6xZcl3lB+mlBz/hs1W3iHEQAORyJnKArWSY/aVOBKUyflA==} engines: {node: ^18.17.1 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'} hasBin: true @@ -1154,8 +1154,8 @@ packages: hast-util-raw@9.0.4: resolution: {integrity: sha512-LHE65TD2YiNsHD3YuXcKPHXPLuYh/gjp12mOfU8jxSrm1f/yJpsb0F/KKljS6U9LJoP0Ux+tCe8iJ2AsPzTdgA==} - hast-util-to-html@9.0.1: - resolution: {integrity: sha512-hZOofyZANbyWo+9RP75xIDV/gq+OUKx+T46IlwERnKmfpwp81XBFbT9mi26ws+SJchA4RVUQwIBJpqEOBhMzEQ==} + hast-util-to-html@9.0.2: + resolution: {integrity: sha512-RP5wNpj5nm1Z8cloDv4Sl4RS8jH5HYa0v93YB6Wb4poEzgMo/dAAL0KcT4974dCjcNG5pkLqTImeFHHCwwfY3g==} hast-util-to-parse5@8.0.0: resolution: {integrity: sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==} @@ -1518,8 +1518,8 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - nanostores@0.11.2: - resolution: {integrity: sha512-6bucNxMJA5rNV554WQl+MWGng0QVMzlRgpKTHHfIbVLrhQ+yRXBychV9ECGVuuUfCMQPjfIG9bj8oJFZ9hYP/Q==} + nanostores@0.11.3: + resolution: {integrity: sha512-TUes3xKIX33re4QzdxwZ6tdbodjmn3tWXCEc1uokiEmo14sI1EaGYNs2k3bU2pyyGNmBqFGAVl6jAGWd06AVIg==} engines: {node: ^18.0.0 || >=20.0.0} neotraverse@0.6.18: @@ -2020,8 +2020,8 @@ packages: vfile-message@4.0.2: resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} - vfile@6.0.2: - resolution: {integrity: sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg==} + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} vite@5.4.2: resolution: {integrity: sha512-dDrQTRHp5C1fTFzcSaMxjk6vdpKvT+2/mIdE07Gw2ykehT49O0z/VHS3zZ8iV/Gh8BJJKHWOe5RjaNrW5xf/GA==} @@ -2319,7 +2319,7 @@ snapshots: unist-util-remove-position: 5.0.0 unist-util-visit: 5.0.0 unist-util-visit-parents: 6.0.1 - vfile: 6.0.2 + vfile: 6.0.3 transitivePeerDependencies: - supports-color @@ -2339,9 +2339,9 @@ snapshots: - supports-color - vite - '@astrojs/tailwind@5.1.0(astro@4.14.5(rollup@4.21.1)(sass@1.77.8)(typescript@5.5.4))(tailwindcss@3.4.10)': + '@astrojs/tailwind@5.1.0(astro@4.14.6(rollup@4.21.1)(sass@1.77.8)(typescript@5.5.4))(tailwindcss@3.4.10)': dependencies: - astro: 4.14.5(rollup@4.21.1)(sass@1.77.8)(typescript@5.5.4) + astro: 4.14.6(rollup@4.21.1)(sass@1.77.8)(typescript@5.5.4) autoprefixer: 10.4.20(postcss@8.4.41) postcss: 8.4.41 postcss-load-config: 4.0.2(postcss@8.4.41) @@ -2707,9 +2707,9 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 - '@nanostores/react@0.7.3(nanostores@0.11.2)(react@18.3.1)': + '@nanostores/react@0.7.3(nanostores@0.11.3)(react@18.3.1)': dependencies: - nanostores: 0.11.2 + nanostores: 0.11.3 react: 18.3.1 '@nodelib/fs.scandir@2.1.5': @@ -2956,7 +2956,7 @@ snapshots: array-iterate@2.0.1: {} - astro@4.14.5(rollup@4.21.1)(sass@1.77.8)(typescript@5.5.4): + astro@4.14.6(rollup@4.21.1)(sass@1.77.8)(typescript@5.5.4): dependencies: '@astrojs/compiler': 2.10.3 '@astrojs/internal-helpers': 0.4.1 @@ -3016,7 +3016,7 @@ snapshots: strip-ansi: 7.1.0 tsconfck: 3.1.1(typescript@5.5.4) unist-util-visit: 5.0.0 - vfile: 6.0.2 + vfile: 6.0.3 vite: 5.4.2(sass@1.77.8) vitefu: 0.2.5(vite@5.4.2(sass@1.77.8)) which-pm: 3.0.0 @@ -3388,7 +3388,7 @@ snapshots: devlop: 1.1.0 hast-util-from-parse5: 8.0.1 parse5: 7.1.2 - vfile: 6.0.2 + vfile: 6.0.3 vfile-message: 4.0.2 hast-util-from-parse5@8.0.1: @@ -3398,7 +3398,7 @@ snapshots: devlop: 1.1.0 hastscript: 8.0.0 property-information: 6.5.0 - vfile: 6.0.2 + vfile: 6.0.3 vfile-location: 5.0.3 web-namespaces: 2.0.1 @@ -3422,17 +3422,16 @@ snapshots: parse5: 7.1.2 unist-util-position: 5.0.0 unist-util-visit: 5.0.0 - vfile: 6.0.2 + vfile: 6.0.3 web-namespaces: 2.0.1 zwitch: 2.0.4 - hast-util-to-html@9.0.1: + hast-util-to-html@9.0.2: dependencies: '@types/hast': 3.0.4 '@types/unist': 3.0.3 ccount: 2.0.1 comma-separated-tokens: 2.0.3 - hast-util-raw: 9.0.4 hast-util-whitespace: 3.0.0 html-void-elements: 3.0.0 mdast-util-to-hast: 13.2.0 @@ -3706,7 +3705,7 @@ snapshots: trim-lines: 3.0.1 unist-util-position: 5.0.0 unist-util-visit: 5.0.0 - vfile: 6.0.2 + vfile: 6.0.3 mdast-util-to-markdown@2.1.0: dependencies: @@ -3947,7 +3946,7 @@ snapshots: nanoid@3.3.7: {} - nanostores@0.11.2: {} + nanostores@0.11.3: {} neotraverse@0.6.18: {} @@ -4019,7 +4018,7 @@ snapshots: nlcst-to-string: 4.0.0 unist-util-modify-children: 4.0.0 unist-util-visit-children: 3.0.0 - vfile: 6.0.2 + vfile: 6.0.3 parse5@7.1.2: dependencies: @@ -4143,12 +4142,12 @@ snapshots: dependencies: '@types/hast': 3.0.4 hast-util-raw: 9.0.4 - vfile: 6.0.2 + vfile: 6.0.3 rehype-stringify@10.0.0: dependencies: '@types/hast': 3.0.4 - hast-util-to-html: 9.0.1 + hast-util-to-html: 9.0.2 unified: 11.0.5 rehype@13.0.1: @@ -4184,7 +4183,7 @@ snapshots: '@types/mdast': 4.0.4 mdast-util-to-hast: 13.2.0 unified: 11.0.5 - vfile: 6.0.2 + vfile: 6.0.3 remark-smartypants@3.0.2: dependencies: @@ -4474,7 +4473,7 @@ snapshots: extend: 3.0.2 is-plain-obj: 4.1.0 trough: 2.2.0 - vfile: 6.0.2 + vfile: 6.0.3 unist-util-find-after@5.0.0: dependencies: @@ -4529,17 +4528,16 @@ snapshots: vfile-location@5.0.3: dependencies: '@types/unist': 3.0.3 - vfile: 6.0.2 + vfile: 6.0.3 vfile-message@4.0.2: dependencies: '@types/unist': 3.0.3 unist-util-stringify-position: 4.0.0 - vfile@6.0.2: + vfile@6.0.3: dependencies: '@types/unist': 3.0.3 - unist-util-stringify-position: 4.0.0 vfile-message: 4.0.2 vite@5.4.2(sass@1.77.8): diff --git a/src/_types/SubNavigationItem.ts b/src/_types/SubNavigationItem.ts new file mode 100644 index 0000000..1eaffff --- /dev/null +++ b/src/_types/SubNavigationItem.ts @@ -0,0 +1,4 @@ +export type SubNavigationItem = { + title: string + href: string +} diff --git a/src/components/header/NavMenu.tsx b/src/components/header/NavMenu.tsx index f898d6f..d65b591 100644 --- a/src/components/header/NavMenu.tsx +++ b/src/components/header/NavMenu.tsx @@ -1,8 +1,9 @@ -import React from "react"; -import {IconBiliBili, IconGitHub, IconSkland, IconTapTap, IconWechat, IconWeibo} from "../SvgIcons"; -import {useStore} from "@nanostores/react"; -import {isNavMenuOpen, viewIndex} from "../store/rootLayoutStore.ts"; -import arknightsConfig from "../../../arknights.config.tsx"; +import React, {useEffect, useState} from "react" +import {useStore} from "@nanostores/react" +import type {SubNavigationItem} from "../../_types/SubNavigationItem.ts" +import {IconArrow, IconBiliBili, IconGitHub, IconSkland, IconTapTap, IconWechat, IconWeibo} from "../SvgIcons" +import {isNavMenuOpen, viewIndex} from "../store/rootLayoutStore.ts" +import arknightsConfig from "../../../arknights.config.tsx" export default function NavMenu() { const LineClassName: React.ComponentProps<"div">["className"] = @@ -27,9 +28,14 @@ export default function NavMenu() { } -function Navigation() { +function Navigation({showSubNavigation}: { showSubNavigation: boolean }) { const $viewIndex = useStore(viewIndex) const $isNavMenuOpen = useStore(isNavMenuOpen) + const [showItems, setShowItems] = useState(false) + + useEffect(() => { + setShowItems($isNavMenuOpen && !showSubNavigation) + }, [$isNavMenuOpen, showSubNavigation]) let delay = -70 return
{ @@ -44,21 +50,41 @@ function Navigation() { color: $viewIndex === index ? "#19d1ff" : "inherit", borderBottom: "1px solid hsla(0, 0%, 100%, .3)", transitionDelay: delay + "ms", - opacity: $isNavMenuOpen ? 1 : 0, - transform: `translateX(${$isNavMenuOpen ? "0" : "20%"})`, + opacity: showItems ? 1 : 0, + transform: `translateX(${showItems ? "0" : "20%"})`, }}>
{item.title}
{item.subtitle} -
+
}) }
} +function SubNavigation({items, setShowSubNavigation}: { + items: SubNavigationItem[] + setShowSubNavigation: React.Dispatch> +}) { + return
+ +
    + { + items.map(({title, href}, index) =>
  • + {title} +
  • ) + } +
+
+} + function ToolBox() { const {Skland, Bilibili, WeChat, Weibo, TapTap, GitHub} = arknightsConfig.navbar.toolbox const aClassName: string = "text-inherit flex-none cursor-pointer" @@ -104,16 +130,26 @@ function ToolBox() {
} -export function Menu() { +export function Menu({subNavigationItems}: { subNavigationItems?: SubNavigationItem[] }) { const $isNavMenuOpen = useStore(isNavMenuOpen) + const [showSubNavigation, setShowSubNavigation] = useState(false) + + useEffect(() => { + subNavigationItems && subNavigationItems.length > 0 && $isNavMenuOpen && setShowSubNavigation(true) + }, [$isNavMenuOpen]); + return
-
+
- + { + showSubNavigation && subNavigationItems && subNavigationItems.length > 0 + ? + : + }
-
+
} diff --git a/src/layouts/InfoLayout.astro b/src/layouts/InfoLayout.astro index 2ed7fa1..94756f9 100644 --- a/src/layouts/InfoLayout.astro +++ b/src/layouts/InfoLayout.astro @@ -1,4 +1,5 @@ --- +import type {SubNavigationItem} from "../_types/SubNavigationItem"; import RootLayout from "./RootLayout.astro" import {IconArrow} from "../components/SvgIcons" import LineDecorator from "../components/LineDecorator" @@ -9,6 +10,7 @@ interface Props { subTitle?: string tabTitle?: string goBackHref?: string + subNavigationItems?: SubNavigationItem[] } const base = import.meta.env.BASE_URL @@ -16,9 +18,10 @@ const title = Astro.props.title ?? "INFO" const subTitle = Astro.props.subTitle ?? "情报中心" const tabTitle = Astro.props.tabTitle ?? "情报中心" const goBackHref = Astro.props.goBackHref +const subNavigationItems = Astro.props.subNavigationItems --- - +
diff --git a/src/layouts/RootLayout.astro b/src/layouts/RootLayout.astro index 4a3ec7d..dd98735 100644 --- a/src/layouts/RootLayout.astro +++ b/src/layouts/RootLayout.astro @@ -1,4 +1,5 @@ --- +import type {SubNavigationItem} from "../_types/SubNavigationItem"; import "../_styles/base.css" import FontFace from "../_styles/FontFace.astro" import Scrollbar from "../_styles/Scrollbar.astro" @@ -13,10 +14,11 @@ interface Props { lang?: string title?: string description?: string + subNavigationItems?: SubNavigationItem[] } const base = import.meta.env.BASE_URL -const {lang, title, description} = Astro.props; +const {lang, title, description, subNavigationItems} = Astro.props --- @@ -38,7 +40,7 @@ const {lang, title, description} = Astro.props;
- +
diff --git a/src/pages/docs/[...slug].astro b/src/pages/docs/[...slug].astro index 85e40ed..1f35222 100644 --- a/src/pages/docs/[...slug].astro +++ b/src/pages/docs/[...slug].astro @@ -1,28 +1,34 @@ --- -import {getCollection, getEntry} from 'astro:content' +import {getCollection} from 'astro:content' // import {Debug} from 'astro:components' +import type {SubNavigationItem} from "../../_types/SubNavigationItem" import InfoLayout from "../../layouts/InfoLayout.astro" import DocsLeftAside from "../../components/DocsLeftAside.astro" import DocsToolPanel from "../../components/DocsToolPanel" import DocumentIndexUL from "../../components/DocumentIndexUL.astro" -import DocsLeftAsideSwitch from "../../components/DocsLeftAsideSwitch"; +import DocsLeftAsideSwitch from "../../components/DocsLeftAsideSwitch" export async function getStaticPaths() { - const allDocs = await getCollection("docs"); - - return allDocs.map(entry => ({ + return (await getCollection("docs")).map(entry => ({ params: {slug: entry.slug.split("-").slice(1).join("-")}, props: {entry}, })) } +const base = import.meta.env.BASE_URL const {entry} = Astro.props const {Content, headings} = await entry.render() const tabTitle = entry?.data?.title ?? "无标题" +const subNavigationItems: SubNavigationItem[] = (await getCollection("docs")) + .map(({id, slug, body, collection, data}, index) => ({ + title: data.title ?? id, + href: base + "docs/" + slug.split("-").slice(1).join("-"), + })) --- - - diff --git a/src/pages/docs/index.astro b/src/pages/docs/index.astro index 57d19ef..3b66cae 100644 --- a/src/pages/docs/index.astro +++ b/src/pages/docs/index.astro @@ -1,14 +1,21 @@ --- -import {getCollection, getEntry} from 'astro:content' +import {getCollection} from 'astro:content' // import {Debug} from 'astro:components' +import type {SubNavigationItem} from "../../_types/SubNavigationItem" import InfoLayout from "../../layouts/InfoLayout.astro" import DocsLeftAside from "../../components/DocsLeftAside.astro" -import DocsLeftAsideSwitch from "../../components/DocsLeftAsideSwitch"; -import {IconArrow} from "../../components/SvgIcons"; +import DocsLeftAsideSwitch from "../../components/DocsLeftAsideSwitch" +import {IconArrow} from "../../components/SvgIcons" const base = import.meta.env.BASE_URL +const subNavigationItems: SubNavigationItem[] = (await getCollection("docs")) + .map(({id, slug, body, collection, data}, index) => ({ + title: data.title ?? id, + href: base + "docs/" + slug.split("-").slice(1).join("-"), + })) --- - + +