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() { </div> } -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 <div className="pt-[1.25rem] pr-[2.25rem] pb-0 pl-[3.375rem]">{ @@ -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%"})`, }}> <div className={`transition duration-300 text-4xl font-oswaldMedium`}> {item.title} </div> <div className="h-full text-[1.75rem] relative flex items-center transition duration-300"> {item.subtitle} - <div className="w-full h-[.375rem] absolute right-0 bottom-[-.1875rem] bg-[currentColor]"></div> + <div className="w-full h-[.375rem] absolute right-0 bottom-[-.1875rem] bg-[currentColor]"/> </div> </a> }) }</div> } +function SubNavigation({items, setShowSubNavigation}: { + items: SubNavigationItem[] + setShowSubNavigation: React.Dispatch<React.SetStateAction<boolean>> +}) { + return <div className="text-4xl font-benderBold overflow-y-auto"> + <button className="w-full h-[4.5rem] text-left bg-[#5a5a5a] bg-opacity-80 block pl-[3.375rem]" + onClick={() => setShowSubNavigation(false)}> + <IconArrow className="h-[2.25rem] rotate-180 inline-block pl-9"/> + 回到主菜单 + </button> + <ul className="pt-[1.25rem] pr-[2.25rem] pb-0 pl-[3.375rem]"> + { + items.map(({title, href}, index) => <li key={index} className="h-[4.5rem]"> + <a target="_self" {...{href}}>{title}</a> + </li>) + } + </ul> + </div> +} + 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() { </div> } -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 <div className={"w-full h-full absolute top-0 left-0 z-[22] overflow-hidden bg-black bg-opacity-90" + " transition-[opacity,visibility] ease-in-out duration-[600ms]"} style={{opacity: $isNavMenuOpen ? 1 : 0, visibility: $isNavMenuOpen ? "visible" : "hidden"}}> - <div className="w-full h-px absolute left-0 top-[9.375rem] bg-[#4f4f4f]"></div> + <div className="w-full h-px absolute left-0 top-[9.375rem] bg-[#4f4f4f]"/> <div className="w-full h-full pt-[9.375rem] pr-[5.75rem] flex flex-col"> - <Navigation/> + { + showSubNavigation && subNavigationItems && subNavigationItems.length > 0 + ? <SubNavigation items={subNavigationItems} {...{setShowSubNavigation}}/> + : <Navigation {...{showSubNavigation}}/> + } <ToolBox/> </div> - <div className="w-px h-full absolute top-0 right-[5.75rem] bg-[#4f4f4f]"></div> + <div className="w-px h-full absolute top-0 right-[5.75rem] bg-[#4f4f4f]"/> </div> } 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 --- -<RootLayout title={tabTitle}> +<RootLayout title={tabTitle} {...{subNavigationItems}}> <!-- TODO: Canvas 动态背景 --> <div class="landscape:hidden"> <PageTracker client:only="react"/> 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 --- <!DOCTYPE html> @@ -38,7 +40,7 @@ const {lang, title, description} = Astro.props; <div class="relative w-full h-full m-auto max-w-[180rem]"> <Header/> <slot/> - <Menu client:only="react"/> + <Menu client:only="react" {...{subNavigationItems}}/> <ToolBox client:load/> <OwnerInfo client:load/> </div> 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("-"), + })) --- -<InfoLayout title="DOCS" subTitle="文档" tabTitle={tabTitle + " - 文档"}> - <nav slot="left-aside" class="h-full mix-blend-difference bg-list-texture bg-cover bg-center bg-opacity-30 flex flex-col"> +<InfoLayout title="DOCS" subTitle="文档" tabTitle={tabTitle + " - 文档"} {...{subNavigationItems}}> + <nav slot="left-aside" + class="h-full mix-blend-difference bg-list-texture bg-cover bg-center bg-opacity-30 flex flex-col"> <DocsLeftAside/> <DocsLeftAsideSwitch client:load/> </nav> @@ -34,9 +40,7 @@ const tabTitle = entry?.data?.title ?? "无标题" <summary class="text-black bg-white text-[24px] font-bold px-3 font-oswaldMedium"> Document Index - 文档索引 </summary> - <DocsLeftAside/> - <hr/> - <DocumentIndexUL {...{headings}} /> + <DocumentIndexUL {...{headings}}/> </details> <article> <Content/> @@ -47,7 +51,7 @@ const tabTitle = entry?.data?.title ?? "无标题" <h2 class="text-black bg-white text-[1.75rem] font-bold px-3 font-oswaldMedium"> Document Index - 文档索引 </h2> - <DocumentIndexUL {...{headings}} /> + <DocumentIndexUL {...{headings}}/> </nav> <DocsToolPanel slot="tool-panel" client:load/> 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("-"), + })) --- -<InfoLayout title="DOCS" subTitle="文档" tabTitle="文档"> + +<InfoLayout title="DOCS" subTitle="文档" tabTitle="文档" {...{subNavigationItems}}> <nav slot="left-aside" class="h-full mix-blend-difference bg-list-texture bg-cover bg-center bg-opacity-30 flex flex-col"> <DocsLeftAside/>