diff --git a/src/client/components/Article.module.css b/src/client/components/Article.module.css index 06272ed..a9ef2b5 100644 --- a/src/client/components/Article.module.css +++ b/src/client/components/Article.module.css @@ -13,6 +13,7 @@ position: sticky; top: calc(var(--header-height) + 2rem - var(--header-offset)); max-height: calc(100dvh - var(--header-height) - 4rem + var(--header-offset)); + width: 12rem; right: 0; transition: transform 0.3s ease-in-out; overflow-y: auto; @@ -23,14 +24,6 @@ .article { margin: 2rem 1.25rem; } - - .aside { - position: fixed; - top: 0; - right: 0; - height: 100dvh; - transform: translateX(100%); - } } .info { @@ -75,3 +68,40 @@ .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%); + } +} diff --git a/src/client/components/Article.tsx b/src/client/components/Article.tsx index e526f05..efef801 100644 --- a/src/client/components/Article.tsx +++ b/src/client/components/Article.tsx @@ -1,16 +1,21 @@ -import { solidBaseConfig } from "virtual:solidbase"; +import { Dialog } from "@kobalte/core/dialog"; import { WindowEventListener } from "@solid-primitives/event-listener"; import { createShortcut } from "@solid-primitives/keyboard"; import { isAppleDevice } from "@solid-primitives/platform"; import { type ParentProps, Show, createSignal } from "solid-js"; import { useSolidBaseContext } from "../context"; +import { mobileLayout } from "../globals"; import { useCurrentPageData } from "../page-data"; -import { usePrevNext, useSidebar } from "../sidebar"; +import { usePrevNext } from "../sidebar"; import styles from "./Article.module.css"; +import layoutStyles from "./Layout.module.css"; export default function Article(props: ParentProps) { - const { TableOfContents, Link, LastUpdated, Footer } = - useSolidBaseContext().components; + const { + components: { TableOfContents, Link, LastUpdated, Footer }, + tocOpen, + setTocOpen, + } = useSolidBaseContext(); const [contentRef, setContentRef] = createSignal(); @@ -110,9 +115,23 @@ export default function Article(props: ParentProps) { - + + + + } + > + + + + + + + + + ); diff --git a/src/client/components/Header.module.css b/src/client/components/Header.module.css index 47129ff..b80163f 100644 --- a/src/client/components/Header.module.css +++ b/src/client/components/Header.module.css @@ -31,13 +31,13 @@ } html { - --header-height: 5.5rem !important; + --header-height: 6.5rem !important; } } @media screen and (min-width: 1100px) { - .mobile-menu { - display: none; + .mobile-bar { + display: none !important; } } @@ -55,12 +55,26 @@ background: transparent; border-radius: var(--border-radius); color: var(--text-color); - padding: 0.25rem; + font-size: .8rem; + padding: 0.5rem; cursor: var(--button-cursor); + display: flex; + align-items: center; + gap: .5rem; + margin: 0 -.5rem; + text-decoration: none; + transition-property: background-color, color; + transition-timing-function: var(--transition-timing); + transition-duration: .15s; &:hover, - &:focus { - background: color-mix(in hsl, var(--text-color) 10%, transparent); + &:focus-visible { + color: var(--heading-color); + background: color-mix(in hsl, var(--link-underline-color) 20%, transparent); + } + + &.active { + color: var(--active-link-color); } & svg { @@ -105,3 +119,11 @@ } } } + +.mobile-bar { + flex: none !important; + border-top: 1px solid + color-mix(in hsl, var(--decoration-color) 15%, transparent); + margin: 0 -4rem; + padding: .25rem 4rem; +} diff --git a/src/client/components/Header.tsx b/src/client/components/Header.tsx index f307d34..38b03d9 100644 --- a/src/client/components/Header.tsx +++ b/src/client/components/Header.tsx @@ -15,20 +15,22 @@ import { useSolidBaseContext } from "../context"; import { mobileLayout } from "../globals"; import { getLocaleLink } from "../locale"; import styles from "./Header.module.css"; -import { MenuIcon } from "./icons"; +import { MenuLeftIcon, MenuRightIcon } from "./icons"; const DocSearch = lazy(() => import("./DocSearch")); const BUFFER_MULT = 3; -interface HeaderProps { - setSidebarOpen: Setter; -} +interface HeaderProps {} export default function Header(props: HeaderProps) { const [ref, setRef] = createSignal(); - const { ThemeSelector, LocaleSelector } = useSolidBaseContext().components; + const { + components: { ThemeSelector, LocaleSelector }, + setSidebarOpen, + setTocOpen, + } = useSolidBaseContext(); const scroll = useWindowScrollPosition(); const [offset, setOffset] = createSignal(0); @@ -128,18 +130,18 @@ export default function Header(props: HeaderProps) { diff --git a/src/client/components/Layout.module.css b/src/client/components/Layout.module.css index 843923a..9648a7a 100644 --- a/src/client/components/Layout.module.css +++ b/src/client/components/Layout.module.css @@ -46,7 +46,7 @@ top: 0; height: 100dvh; z-index: 51; - min-width: 80%; + width: 70dvw; background: var(--background-color); animation: contentHide 300ms ease-out forwards; @@ -163,27 +163,6 @@ } } -.sidenav-close-btn { - appearance: none; - outline: none; - border: none; - background: transparent; - border-radius: var(--border-radius); - color: var(--text-color); - padding: 0.5rem; - cursor: var(--button-cursor); - - &:hover, - &:focus { - background: color-mix(in hsl, var(--text-color) 10%, transparent); - } - - & svg { - width: 1.25rem; - height: 1.25rem; - } -} - @keyframes overlayShow { from { opacity: 0; @@ -214,10 +193,10 @@ @keyframes contentHide { from { opacity: 1; - transform: translateX(-100%); + transform: translateX(0); } to { opacity: 0; - transform: translateX(0); + transform: translateX(-100%); } } diff --git a/src/client/components/Layout.tsx b/src/client/components/Layout.tsx index 65f6489..4b36579 100644 --- a/src/client/components/Layout.tsx +++ b/src/client/components/Layout.tsx @@ -29,12 +29,12 @@ export default function Layout(props: ParentProps) { const { config, components: { Header, Article }, + sidebarOpen, + setSidebarOpen, } = useSolidBaseContext(); const pageData = useCurrentPageData(); - const [sidebarOpen, setSidebarOpen] = createSignal(false); - const sidebar = useSidebar(); createEffect(() => @@ -78,7 +78,7 @@ export default function Layout(props: ParentProps) {
-
+
0} @@ -108,9 +108,6 @@ export default function Layout(props: ParentProps) { {config().title} - - -
diff --git a/src/client/components/TableOfContents.tsx b/src/client/components/TableOfContents.tsx index f8f9023..1dfa96d 100644 --- a/src/client/components/TableOfContents.tsx +++ b/src/client/components/TableOfContents.tsx @@ -10,7 +10,7 @@ import { import { type TableOfContentData, useCurrentPageData } from "../page-data"; import styles from "./TableOfContents.module.css"; -export default function TableOfContents(props: {}) { +export default function TableOfContents(props: { scrollspy?: boolean }) { const toc = () => useCurrentPageData()().toc; const [currentSection, setCurrentSection] = createSignal( @@ -24,7 +24,7 @@ export default function TableOfContents(props: {}) { >([]); createEffect(() => { - if (!toc()) return []; + if (!toc() || !props.scrollspy) return []; setHeadingPositions( flattenData(toc()!).map((url) => { const el = document.getElementById(url.slice(1)); @@ -51,6 +51,8 @@ export default function TableOfContents(props: {}) { }); createEffect(() => { + if (!props.scrollspy) return; + const top = scroll.y; let current = headingPositions()[0]?.url; @@ -72,7 +74,11 @@ export default function TableOfContents(props: {}) { @@ -82,6 +88,7 @@ export default function TableOfContents(props: {}) { function TableOfContentsItem(props: { data: TableOfContentData; current: string | undefined; + scrollspy: boolean; }) { const [ref, setRef] = createSignal(); @@ -120,7 +127,11 @@ function TableOfContentsItem(props: {
    {(nested) => ( - + )}
diff --git a/src/client/components/icons.tsx b/src/client/components/icons.tsx index 14d93fd..5450f93 100644 --- a/src/client/components/icons.tsx +++ b/src/client/components/icons.tsx @@ -41,6 +41,23 @@ export function MenuIcon(props: ComponentProps<"svg">) { ); } +export function MenuLeftIcon(props: ComponentProps<"svg">) { + return ( + + + + ); +} + +export function MenuRightIcon(props: ComponentProps<"svg">) { + return ; +} + export function CrossIcon(props: ComponentProps<"svg">) { return ( ; locale: ReturnType; + sidebarOpen: Accessor; + setSidebarOpen: Setter; + tocOpen: Accessor; + setTocOpen: Setter; } const SolidBaseContext = createContext(); @@ -67,6 +73,9 @@ export function SolidBaseProvider(props: ParentProps) { const locale = useLocale(); const config = useRouteConfig(); + const [sidebarOpen, setSidebarOpen] = createSignal(false); + const [tocOpen, setTocOpen] = createSignal(false); + return ( {props.children} diff --git a/src/client/globals.ts b/src/client/globals.ts index 084c63e..f61d244 100644 --- a/src/client/globals.ts +++ b/src/client/globals.ts @@ -4,7 +4,7 @@ import { createEffect, createSignal, on } from "solid-js"; const [_mobileLayout, setMobileLayout] = createSignal(false); const query = createMediaQuery("(max-width: 1100px)"); -createEffect(on(query, setMobileLayout, { defer: true })); +createEffect(on(query, (q) => setMobileLayout(q), { defer: true })); setTimeout(() => setMobileLayout(query()));