rewrite nav
This commit is contained in:
parent
6249a0aba7
commit
5341fe58d0
18 changed files with 254 additions and 415 deletions
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
import "@styles/components/accordion.css"
|
||||
import "@styles/components/accordion.css";
|
||||
---
|
||||
<details class=`accordion ${Astro.props.class ?? ""}` {...Astro.props}>
|
||||
<summary>
|
||||
|
@ -19,12 +19,13 @@ import "@styles/components/accordion.css"
|
|||
const body = accordion.querySelector(".accordion-container") as HTMLDivElement;
|
||||
|
||||
summary.addEventListener("click", event => {
|
||||
if ((event.target as Element).tagName === "A") return;
|
||||
event.preventDefault();
|
||||
body.classList.toggle("animate", true);
|
||||
|
||||
if (!accordion.open || accordion.classList.contains("closing")) {
|
||||
accordion.classList.toggle("closing", false);
|
||||
body.style.setProperty("--height", "0px");
|
||||
body.classList.toggle("animate", true);
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
accordion.open = true;
|
||||
|
@ -34,8 +35,12 @@ import "@styles/components/accordion.css"
|
|||
body.style.setProperty("--height", body.scrollHeight + "px");
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
accordion.classList.toggle("closing", true);
|
||||
body.style.setProperty("--height", "0px");
|
||||
body.classList.toggle("animate", true);
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
accordion.classList.toggle("closing", true);
|
||||
body.style.setProperty("--height", "0px");
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
import Accordion from "./Accordion.astro"
|
||||
import collapsibleMarker from "@icons/collapsible-marker.svg?raw"
|
||||
import Accordion from "./Accordion.astro";
|
||||
import collapsibleMarker from "@icons/collapsible-marker.svg?raw";
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
title: string;
|
||||
}
|
||||
const { title } = Astro.props;
|
||||
---
|
||||
|
|
20
src/components/NavCollapsible.astro
Normal file
20
src/components/NavCollapsible.astro
Normal file
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
import Accordion from "./Accordion.astro";
|
||||
import navMarker from "@icons/nav-marker.svg?raw";
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
link: string;
|
||||
current?: boolean;
|
||||
}
|
||||
const { title, link, current } = Astro.props;
|
||||
---
|
||||
<Accordion class=`nav-component nav-collapsible ${current ? "nav-current" : ""}` {...(current ? { open: "" } : {})}>
|
||||
<div slot="header">
|
||||
<a class=`nav-link ${current ? "nav-current" : ""}` href={link}>{title}</a>
|
||||
<div class="nav-collapse-marker">
|
||||
<Fragment set:html={navMarker}/>
|
||||
</div>
|
||||
</div>
|
||||
<slot>
|
||||
</Accordion>
|
|
@ -1,31 +1,24 @@
|
|||
---
|
||||
import { generateTypeData } from "@config/io/generateTypeData";
|
||||
import { groupRoutes } from "@config/io/helpers";
|
||||
import NavComponent from "./nav";
|
||||
|
||||
const routes = await generateTypeData();
|
||||
const groupedRoutes = groupRoutes(routes);
|
||||
import SidebarWrapper from "./nav/SidebarWrapper.tsx";
|
||||
import RootNav from "./nav/RootNav.astro";
|
||||
|
||||
const url = Astro.url.pathname.split("/");
|
||||
const currentRoute = url[2];
|
||||
const currentModule = url[3];
|
||||
const currentClass = url[4];
|
||||
|
||||
const treeProps = {
|
||||
items: groupedRoutes,
|
||||
currentRoute: currentRoute,
|
||||
currentModule: currentModule,
|
||||
currentClass: currentClass,
|
||||
};
|
||||
export interface Props {
|
||||
mobile: boolean;
|
||||
}
|
||||
|
||||
const { mobile } = Astro.props;
|
||||
---
|
||||
|
||||
<aside class=`nav-wrapper${mobile ? "-mobile" : ""}`>
|
||||
<NavComponent
|
||||
routes={groupedRoutes}
|
||||
tree={treeProps}
|
||||
mobile={mobile}
|
||||
client:idle
|
||||
/>
|
||||
{ mobile ? (
|
||||
<SidebarWrapper client:load>
|
||||
<RootNav currentRoute={currentRoute} currentModule={currentModule} currentClass={currentClass}/>
|
||||
</SidebarWrapper>
|
||||
) : (
|
||||
<RootNav currentRoute={currentRoute} currentModule={currentModule} currentClass={currentClass}/>
|
||||
)}
|
||||
</aside>
|
||||
|
|
10
src/components/navigation/sidebars/nav/Link.astro
Normal file
10
src/components/navigation/sidebars/nav/Link.astro
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
interface Props {
|
||||
title: string;
|
||||
link: string;
|
||||
current?: boolean;
|
||||
}
|
||||
|
||||
const { title, link, current } = Astro.props;
|
||||
---
|
||||
<a class=`nav-component nav-item nav-link ${current ? "nav-current" : ""}` href={link}>{title}</a>
|
51
src/components/navigation/sidebars/nav/RootNav.astro
Normal file
51
src/components/navigation/sidebars/nav/RootNav.astro
Normal file
|
@ -0,0 +1,51 @@
|
|||
---
|
||||
export interface Props {
|
||||
currentRoute: string;
|
||||
currentModule: string;
|
||||
currentClass: string;
|
||||
}
|
||||
|
||||
const { currentRoute, currentModule, currentClass } = Astro.props;
|
||||
|
||||
import { generateTypeData } from "@config/io/generateTypeData";
|
||||
import { groupRoutes } from "@config/io/helpers";
|
||||
import Tree from "./Tree.astro";
|
||||
|
||||
const routes = await generateTypeData();
|
||||
const groupedRoutes = groupRoutes(routes);
|
||||
|
||||
const configuration = {
|
||||
title: "Configuration",
|
||||
link: "/docs/configuration",
|
||||
current: currentRoute.startsWith("configuration"),
|
||||
entries: groupedRoutes.tutorials.configuration.map(
|
||||
({ name, type }) => ({
|
||||
title: name,
|
||||
link: `/docs/configuration/${type}`,
|
||||
current: currentModule === type,
|
||||
})
|
||||
),
|
||||
};
|
||||
|
||||
const types = {
|
||||
title: "Quickshell Types",
|
||||
link: "/docs/types",
|
||||
current: currentRoute.startsWith("types"),
|
||||
entries: Object.entries(groupedRoutes.types).map(
|
||||
([module, items]) => ({
|
||||
title: module,
|
||||
link: `/docs/types/${module}`,
|
||||
current: currentModule === module,
|
||||
entries: items.map(type => ({
|
||||
title: type.name,
|
||||
link: `/docs/types/${module}/${type.name}`,
|
||||
current: currentClass === type.name,
|
||||
})),
|
||||
})
|
||||
),
|
||||
};
|
||||
---
|
||||
<nav class="navtree">
|
||||
<Tree {...configuration}/>
|
||||
<Tree {...types}/>
|
||||
</nav>
|
|
@ -4,37 +4,25 @@ import {
|
|||
onMount,
|
||||
onCleanup,
|
||||
type Component,
|
||||
type JSXElement,
|
||||
} from "solid-js";
|
||||
|
||||
import { LoadingSpinner, MenuToX, XToMenu } from "@icons";
|
||||
import { Tree } from "./Tree";
|
||||
import type { NavProps } from "../types";
|
||||
import { MenuToX, XToMenu } from "@icons";
|
||||
|
||||
const NavComponent: Component<NavProps> = props => {
|
||||
export interface SidebarContent {
|
||||
children: JSXElement;
|
||||
}
|
||||
|
||||
const NavComponent: Component<SidebarContent> = props => {
|
||||
const [open, setOpen] = createSignal<boolean>(false);
|
||||
const { tree, mobile, routes } = props;
|
||||
const { children } = props;
|
||||
let navRef: HTMLDivElement;
|
||||
|
||||
if (!tree) {
|
||||
return <LoadingSpinner />;
|
||||
}
|
||||
|
||||
function toggle(e: MouseEvent) {
|
||||
e.preventDefault();
|
||||
setOpen(!open());
|
||||
}
|
||||
|
||||
if (!mobile) {
|
||||
return (
|
||||
<Tree
|
||||
currentRoute={tree.currentRoute}
|
||||
currentModule={tree.currentModule || null}
|
||||
currentClass={tree.currentClass || null}
|
||||
items={routes}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
const isLink = "href" in (event.target || {});
|
||||
const isInBody = document.body.contains(event.target as Node);
|
||||
|
@ -78,12 +66,7 @@ const NavComponent: Component<NavProps> = props => {
|
|||
id={open() ? "#qs_search" : ""}
|
||||
class={`nav-items ${open() ? "shown" : ""}`}
|
||||
>
|
||||
<Tree
|
||||
currentRoute={tree.currentRoute}
|
||||
currentModule={tree.currentModule}
|
||||
currentClass={tree.currentClass}
|
||||
items={routes}
|
||||
/>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
23
src/components/navigation/sidebars/nav/Tree.astro
Normal file
23
src/components/navigation/sidebars/nav/Tree.astro
Normal file
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
import NavCollapsible from "@components/NavCollapsible.astro";
|
||||
import Self from "./Tree.astro";
|
||||
import Link from "./Link.astro";
|
||||
|
||||
interface TreeEntry {
|
||||
title: string;
|
||||
link: string;
|
||||
current?: boolean;
|
||||
entries?: TreeEntry[];
|
||||
}
|
||||
|
||||
interface Props extends TreeEntry {}
|
||||
|
||||
const { title, link, entries, current } = Astro.props;
|
||||
---
|
||||
<NavCollapsible title={title} link={link} current={current ?? false}>
|
||||
{entries?.map(entry => entry.entries ? (
|
||||
<Self {...entry}/>
|
||||
) : (
|
||||
<Link title={entry.title} link={entry.link} current={entry.current}/>
|
||||
))}
|
||||
</NavCollapsible>
|
|
@ -1,176 +0,0 @@
|
|||
import { type Component, Index, For } from "solid-js";
|
||||
import { Accordion } from "@ark-ui/solid";
|
||||
|
||||
import { LinkSimple, ShevronSmallDown } from "@icons";
|
||||
import type { TreeProps } from "../types";
|
||||
|
||||
export const Tree: Component<TreeProps> = props => {
|
||||
const { currentRoute, currentModule, currentClass, items } =
|
||||
props;
|
||||
|
||||
const typeKeys = items!.types && Object.keys(items!.types);
|
||||
|
||||
const tutorials =
|
||||
items!.tutorials && items!.tutorials
|
||||
? items!.tutorials.configuration
|
||||
: null;
|
||||
|
||||
return (
|
||||
<nav class="navtree">
|
||||
<Accordion.Root
|
||||
defaultValue={
|
||||
currentRoute === "types" ? ["Types"] : ["Configuration"]
|
||||
}
|
||||
collapsible
|
||||
multiple
|
||||
>
|
||||
<Accordion.Item value={"Configuration"}>
|
||||
<Accordion.ItemTrigger>
|
||||
<Accordion.ItemIndicator>
|
||||
<ShevronSmallDown class={"nav-shevron"} />
|
||||
</Accordion.ItemIndicator>
|
||||
<p>
|
||||
<a href={"/docs/configuration"}>Configuration</a>
|
||||
</p>
|
||||
</Accordion.ItemTrigger>
|
||||
<Accordion.ItemContent>
|
||||
<For each={tutorials}>
|
||||
{item => (
|
||||
<div
|
||||
class={`arktree-item ${currentModule === item.type ? "__current-type-doc" : ""}`}
|
||||
>
|
||||
<a href={`/docs/configuration/${item.type}`}>
|
||||
{item.name}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</For>
|
||||
</Accordion.ItemContent>
|
||||
</Accordion.Item>
|
||||
<Accordion.Item value={"Types"}>
|
||||
<Accordion.ItemTrigger>
|
||||
<Accordion.ItemIndicator>
|
||||
<ShevronSmallDown class={"nav-shevron"} />
|
||||
</Accordion.ItemIndicator>
|
||||
<p>
|
||||
<a href={"/docs/types"}>Type Definitions</a>
|
||||
</p>
|
||||
</Accordion.ItemTrigger>
|
||||
<Accordion.ItemContent>
|
||||
<Index each={typeKeys}>
|
||||
{typeKey => {
|
||||
return (
|
||||
<Accordion.Root
|
||||
defaultValue={
|
||||
currentModule === typeKey()
|
||||
? [typeKey()]
|
||||
: [""]
|
||||
}
|
||||
multiple
|
||||
collapsible
|
||||
>
|
||||
<Accordion.Item
|
||||
value={typeKey()}
|
||||
id={typeKey()}
|
||||
class={
|
||||
typeKey() === currentModule
|
||||
? "__current-type-doc"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
<Accordion.ItemTrigger
|
||||
id={`${typeKey()}:button`}
|
||||
>
|
||||
<Accordion.ItemIndicator>
|
||||
<ShevronSmallDown
|
||||
class={"nav-shevron"}
|
||||
/>
|
||||
</Accordion.ItemIndicator>
|
||||
<p>
|
||||
<a href={`/docs/types/${typeKey()}`}>
|
||||
{typeKey()}
|
||||
</a>
|
||||
</p>
|
||||
</Accordion.ItemTrigger>
|
||||
<Accordion.ItemContent>
|
||||
<For each={items!.types[typeKey()]}>
|
||||
{submodule => (
|
||||
<div
|
||||
class={
|
||||
currentClass === submodule.name
|
||||
? "__current-type-doc"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
<a
|
||||
href={`/docs/types/${submodule.type}/${submodule.name}`}
|
||||
>
|
||||
{submodule.name}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</For>
|
||||
</Accordion.ItemContent>
|
||||
</Accordion.Item>
|
||||
</Accordion.Root>
|
||||
);
|
||||
}}
|
||||
</Index>
|
||||
</Accordion.ItemContent>
|
||||
</Accordion.Item>
|
||||
<Accordion.Item
|
||||
value="QtQuick Type Reference"
|
||||
id="qtquick-reference"
|
||||
>
|
||||
<Accordion.ItemTrigger>
|
||||
<Accordion.ItemIndicator>
|
||||
<LinkSimple />
|
||||
</Accordion.ItemIndicator>
|
||||
<span
|
||||
class="link-outside"
|
||||
onMouseDown={() =>
|
||||
window.open(
|
||||
"https://doc.qt.io/qt-6/qtquick-qmlmodule.html"
|
||||
)
|
||||
}
|
||||
>
|
||||
<a
|
||||
href="https://doc.qt.io/qt-6/qtquick-qmlmodule.html"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
QtQuick Types
|
||||
</a>
|
||||
</span>
|
||||
</Accordion.ItemTrigger>
|
||||
</Accordion.Item>
|
||||
<Accordion.Item
|
||||
value="Quickshell Examples"
|
||||
id="quickshell-examples"
|
||||
>
|
||||
<Accordion.ItemTrigger>
|
||||
<Accordion.ItemIndicator>
|
||||
<LinkSimple />
|
||||
</Accordion.ItemIndicator>
|
||||
<span
|
||||
class="link-outside"
|
||||
onMouseDown={() =>
|
||||
window.open(
|
||||
"https://git.outfoxxed.me/outfoxxed/quickshell-examples"
|
||||
)
|
||||
}
|
||||
>
|
||||
<a
|
||||
href="https://git.outfoxxed.me/outfoxxed/quickshell-examples"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Quickshell Examples
|
||||
</a>
|
||||
</span>
|
||||
</Accordion.ItemTrigger>
|
||||
</Accordion.Item>
|
||||
</Accordion.Root>
|
||||
</nav>
|
||||
);
|
||||
};
|
|
@ -16,12 +16,6 @@ export interface TreeProps {
|
|||
currentClass: string | null;
|
||||
}
|
||||
|
||||
export interface NavProps {
|
||||
routes: GroupedRoutes;
|
||||
tree: TreeProps;
|
||||
mobile: boolean;
|
||||
}
|
||||
|
||||
// Right
|
||||
export interface TOCProps {
|
||||
config?: ConfigHeading[];
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
import { processMarkdown } from "@config/io/markdown"
|
||||
import { processMarkdown } from "@config/io/markdown";
|
||||
|
||||
export interface Props {
|
||||
markdown?: string,
|
||||
markdown?: string;
|
||||
}
|
||||
|
||||
const { markdown } = Astro.props;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue