Skip to content

Commit

Permalink
chore: change mobile toc
Browse files Browse the repository at this point in the history
  • Loading branch information
jer3m01 committed Oct 23, 2024
1 parent 728e87f commit 0097502
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 167 deletions.
37 changes: 0 additions & 37 deletions src/client/components/Article.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -68,40 +68,3 @@
.next {
align-items: flex-end;
}

.sidenav {
position: fixed;
right: 0;
top: 0;
height: 100dvh;
z-index: 51;
width: 70dvw;
background: var(--background-color);
animation: contentHide 300ms ease-out forwards;
padding: 1rem;

&[data-expanded] {
animation: contentShow 300ms ease-out;
}
}

@keyframes contentShow {
from {
opacity: 0;
transform: translateX(100%);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes contentHide {
from {
opacity: 1;
transform: translateX(0);
}
to {
opacity: 0;
transform: translateX(100%);
}
}
21 changes: 4 additions & 17 deletions src/client/components/Article.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { mobileLayout } from "../globals";
import { useCurrentPageData } from "../page-data";
import { usePrevNext } from "../sidebar";
import styles from "./Article.module.css";
import layoutStyles from "./Layout.module.css";

export default function Article(props: ParentProps) {
const {
Expand Down Expand Up @@ -115,22 +114,10 @@ export default function Article(props: ParentProps) {
</Show>
</div>

<Show
when={mobileLayout()}
fallback={
<aside class={styles.aside}>
<TableOfContents />
</aside>
}
>
<Dialog open={tocOpen()} onOpenChange={setTocOpen}>
<Dialog.Portal>
<Dialog.Overlay class={layoutStyles["sidenav-overlay"]} />
<Dialog.Content class={styles.sidenav}>
<TableOfContents />
</Dialog.Content>
</Dialog.Portal>
</Dialog>
<Show when={!mobileLayout()}>
<aside class={styles.aside}>
<TableOfContents />
</aside>
</Show>
</article>
</>
Expand Down
65 changes: 65 additions & 0 deletions src/client/components/Header.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@
width: 1rem;
height: 1rem;
}

& > svg {
transition-property: transform;
transition-timing-function: var(--transition-timing);
transition-duration: .15s;
}

&[data-expanded] > svg {
transform: rotateX(180deg);
}
}

.selectors {
Expand Down Expand Up @@ -127,3 +137,58 @@
margin: 0 -4rem;
padding: .25rem 4rem;
}

.toc-container {
height: 0;
width: 100dvw;
left: -1rem;
top: 1px;
position: relative;
overflow: visible;
flex: 0 !important;
}

.toc-popup {
position: sticky;
top: calc(var(--header-height) + var(--header-offset));
left: 0;
z-index: 51;
width: 100dvw;
max-height: calc(100dvh - var(--header-height));
background: var(--background-color);
overflow-y: auto;
animation: contentHide 50ms ease-out forwards;
transform-origin: top;
padding: 1rem;
border-bottom: 1px solid
color-mix(in hsl, var(--decoration-color) 15%, transparent);

&[data-expanded] {
animation: contentShow 50ms ease-out forwards;
}

& * {
opacity: 1 !important;
}
}

@keyframes contentShow {
from {
opacity: 0;
transform: scale(0.99) translateY(-1rem);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes contentHide {
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: 0;
transform: scale(0.99) translateY(-1rem);
}
}
142 changes: 73 additions & 69 deletions src/client/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
import { createEventListener } from "@solid-primitives/event-listener";
import { useWindowScrollPosition } from "@solid-primitives/scroll";
import { useMatch } from "@solidjs/router";
import {
For,
type Setter,
Show,
createEffect,
createSignal,
lazy,
onMount,
} from "solid-js";
import { For, Show, createEffect, createSignal, lazy, onMount } from "solid-js";

import { Dialog } from "@kobalte/core/dialog";
import { useSolidBaseContext } from "../context";
import { mobileLayout } from "../globals";
import { getLocaleLink } from "../locale";
import styles from "./Header.module.css";
import { MenuLeftIcon, MenuRightIcon } from "./icons";
import { ArrowDownIcon, MenuLeftIcon } from "./icons";

const DocSearch = lazy(() => import("./DocSearch"));

Expand All @@ -25,11 +18,13 @@ interface HeaderProps {}

export default function Header(props: HeaderProps) {
const [ref, setRef] = createSignal<HTMLElement>();
const [tocRef, setTocRef] = createSignal<HTMLElement>();

const {
components: { ThemeSelector, LocaleSelector },
components: { ThemeSelector, LocaleSelector, TableOfContents },
setSidebarOpen,
setTocOpen,
tocOpen,
} = useSolidBaseContext();

const scroll = useWindowScrollPosition();
Expand All @@ -55,7 +50,7 @@ export default function Header(props: HeaderProps) {
const delta = scroll.y - prev;

const newVal = Math.max(
Math.min(Math.round(prefOffset + delta), headerHeight * BUFFER_MULT),
Math.min(prefOffset + delta, headerHeight * BUFFER_MULT),
0,
);

Expand Down Expand Up @@ -87,63 +82,72 @@ export default function Header(props: HeaderProps) {
const { config, locale } = useSolidBaseContext();

return (
<header class={styles.header} ref={setRef}>
<div>
<a
href={getLocaleLink(locale.currentLocale())}
class={styles["logo-link"]}
>
<Show when={config().logo} fallback={<span>{config().title}</span>}>
<img src={config().logo} alt={config().title} />
</Show>
</a>
<div class={styles.selectors}>
{config().search?.provider === "algolia" && <DocSearch />}
<Show when={config().nav}>
{(nav) => (
<For each={nav()}>
{(item) => {
const match = useMatch(() =>
locale.applyPathPrefix(
`${item.activeMatch ?? item.link}/*rest`,
),
);

return (
<a
class={styles.navLink}
href={locale.applyPathPrefix(item.link)}
data-matched={match() !== undefined ? true : undefined}
>
{item.text}
</a>
);
}}
</For>
)}
</Show>
<LocaleSelector />
<ThemeSelector />
<Dialog open={tocOpen()} onOpenChange={setTocOpen} modal={false}>
<header class={styles.header} ref={setRef}>
<div>
<a
href={getLocaleLink(locale.currentLocale())}
class={styles["logo-link"]}
>
<Show when={config().logo} fallback={<span>{config().title}</span>}>
<img src={config().logo} alt={config().title} />
</Show>
</a>
<div class={styles.selectors}>
{config().search?.provider === "algolia" && <DocSearch />}
<Show when={config().nav}>
{(nav) => (
<For each={nav()}>
{(item) => {
const match = useMatch(() =>
locale.applyPathPrefix(
`${item.activeMatch ?? item.link}/*rest`,
),
);

return (
<a
class={styles.navLink}
href={locale.applyPathPrefix(item.link)}
data-matched={match() !== undefined ? true : undefined}
>
{item.text}
</a>
);
}}
</For>
)}
</Show>
<LocaleSelector />
<ThemeSelector />
</div>
</div>
</div>
<div class={styles["mobile-bar"]}>
<button
type="button"
class={styles["mobile-menu"]}
onClick={() => setSidebarOpen((p) => !p)}
aria-label="Open navigation"
>
<MenuLeftIcon /> Menu
</button>
<button
type="button"
class={styles["mobile-menu"]}
onClick={() => setTocOpen((p) => !p)}
aria-label="Open table of contents"
>
On this page <MenuRightIcon />
</button>
</div>
</header>
<div class={styles["mobile-bar"]}>
<button
type="button"
class={styles["mobile-menu"]}
onClick={() => setSidebarOpen((p) => !p)}
aria-label="Open navigation"
>
<MenuLeftIcon /> Menu
</button>
<Dialog.Trigger
type="button"
class={styles["mobile-menu"]}
aria-label="Open table of contents"
>
On this page <ArrowDownIcon />
</Dialog.Trigger>
</div>

<div ref={setTocRef} class={styles["toc-container"]} />
</header>

<Dialog.Portal mount={tocRef()}>
<Dialog.Content class={styles["toc-popup"]}>
<TableOfContents />
</Dialog.Content>
</Dialog.Portal>
</Dialog>
);
}
Loading

0 comments on commit 0097502

Please sign in to comment.