UNPKG

@kobalte/solidbase

Version:

Fully featured, fully customisable static site generation for SolidStart

153 lines (147 loc) 5.58 kB
// @refresh reload import { Dialog } from "@kobalte/core/dialog"; import { Title } from "@solidjs/meta"; import { A } from "@solidjs/router"; import { For, Match, Show, Switch } from "solid-js"; import { useLocale, useThemeListener } from "../client"; import { SidebarProvider, useSidebar, } from "../client/sidebar"; import { DefaultThemeComponentsProvider, DefaultThemeStateProvider, useDefaultThemeComponents, useDefaultThemeState, } from "./context"; import { mobileLayout } from "./globals"; import { usePace } from "./pace"; import { useRouteConfig } from "./utils"; import "virtual:solidbase/default-theme/fonts.css"; import styles from "./Layout.module.css"; import "./index.css"; import { Collapsible } from "@kobalte/core/collapsible"; import { Dynamic } from "solid-js/web"; import IconArrowDownLine from "~icons/ri/arrow-down-s-line"; export default (props) => { const config = useRouteConfig(); return (<DefaultThemeStateProvider> <DefaultThemeComponentsProvider> <SidebarProvider config={config().themeConfig?.sidebar}> <Layout>{props.children}</Layout> </SidebarProvider> </DefaultThemeComponentsProvider> </DefaultThemeStateProvider>); }; function Layout(props) { const { Header, Article, Link } = useDefaultThemeComponents(); const { sidebarOpen, setSidebarOpen, frontmatter } = useDefaultThemeState(); const config = useRouteConfig(); const sidebar = useSidebar(); useThemeListener(); usePace(); return (<> <Title>{config().title}</Title> <div class={styles.skipnav}> <Link href="#main-content" onClick={() => { document .getElementById("main-content") ?.querySelector("button, [href], input, select, textarea, [tabindex]:not([tabindex='-1'])")?.focus(); }}> Skip to main content </Link> </div> <div class={styles.layout}> <Header /> <Show when={(() => { const s = sidebar(); if (!s || s.items.length <= 0 || frontmatter()?.sidebar === false) return; return s; })()} fallback={<div class="_e"/>}> {(sidebar) => (<Show when={mobileLayout()} fallback={<aside class={styles.sidenav}> <div class={styles["sidenav-content"]}> <Navigation sidebar={sidebar()}/> </div> </aside>}> <Dialog open={sidebarOpen()} onOpenChange={setSidebarOpen}> <Dialog.Portal> <Dialog.Overlay class={styles["sidenav-overlay"]}/> <Dialog.Content class={styles.sidenav}> <div class={styles["sidenav-content"]}> <div class={styles["sidenav-header"]}> <a href="/" class={styles["logo-link"]}> <Show when={config().logo} fallback={<span>{config().title}</span>}> <img src={config().logo} alt={config().title}/> </Show> </a> </div> <Navigation sidebar={sidebar()}/> </div> </Dialog.Content> </Dialog.Portal> </Dialog> </Show>)} </Show> <main id="main-content"> <Article>{props.children}</Article> </main> </div> </>); } function Navigation(props) { return (<nav class={styles["sidenav-links"]}> <ul> <For each={props.sidebar.items}> {(item) => (<NavigationItem prefix={props.sidebar.prefix} item={item}/>)} </For> </ul> </nav>); } function NavigationItem(props) { const locale = useLocale(); const { setSidebarOpen } = useDefaultThemeState(); return (<Switch> <Match when={"link" in props.item && props.item}> {(item) => { const link = () => item().link; const prefix = () => props.prefix; return (<li> <A class={`${styles["sidenav-link"]}`} activeClass={styles.active} href={locale.applyPathPrefix(`${prefix() === "/" ? "" : prefix()}${link() === "/" ? "" : link()}`)} end onClick={() => setSidebarOpen(false)}> <span>{item().title}</span> <Switch> <Match when={item().status === "new"}> <span class={styles["status-new"]}>New</span> </Match> <Match when={item().status === "updated"}> <span class={styles["status-updated"]}>Updated</span> </Match> <Match when={item().status === "next"}> <span class={styles["status-next"]}>Next</span> </Match> <Match when={typeof item().status === "object" && item() .status}> {(status) => (<span class={styles["status-custom"]} style={`---fg: ${status().textColor ?? "white"}; ---bg: ${status().color}`}> {status().text} </span>)} </Match> </Switch> </A> </li>); }} </Match> <Match when={"items" in props.item && props.item}> {(section) => { return (<Collapsible as="li" defaultOpen={!section().collapsed}> <Collapsible.Trigger class={styles["section-trigger"]} aria-label="Toggle list view"> <Dynamic component={`h${(props.depth ?? 0) + 2}`}> {section().title} </Dynamic> <IconArrowDownLine /> </Collapsible.Trigger> <Collapsible.Content as="ul" class={styles["section-content"]}> <For each={section().items}> {(item) => (<NavigationItem prefix={props.prefix + (section().base ?? "")} item={item} depth={(props.depth ?? 0) + 1}/>)} </For> </Collapsible.Content> </Collapsible>); }} </Match> </Switch>); } //# sourceMappingURL=Layout.jsx.map