From c1e28224aa2e1450031669d9a7e359b63e04687d Mon Sep 17 00:00:00 2001 From: Volpeon Date: Wed, 22 Jul 2026 19:40:59 +0200 Subject: Init --- src/ui/components/Logo.tsx | 34 +++++++++++ src/ui/components/ReleaseCard.tsx | 47 +++++++++++++++ src/ui/components/SiteFooter.tsx | 39 ++++++++++++ src/ui/components/SiteHeader.tsx | 121 ++++++++++++++++++++++++++++++++++++++ src/ui/components/SiteNav.tsx | 38 ++++++++++++ 5 files changed, 279 insertions(+) create mode 100644 src/ui/components/Logo.tsx create mode 100644 src/ui/components/ReleaseCard.tsx create mode 100644 src/ui/components/SiteFooter.tsx create mode 100644 src/ui/components/SiteHeader.tsx create mode 100644 src/ui/components/SiteNav.tsx (limited to 'src/ui/components') diff --git a/src/ui/components/Logo.tsx b/src/ui/components/Logo.tsx new file mode 100644 index 0000000..a9ec9be --- /dev/null +++ b/src/ui/components/Logo.tsx @@ -0,0 +1,34 @@ +import type { HTMLAttributes } from "corvos/plugins/jsx.ts"; + +import site from "@/corvos.config.ts"; + +export type Props = HTMLAttributes<"a"> & { + size?: "sm" | "lg"; + variant?: "static-black" | "static-white"; +}; + +export const Logo = async ({ size, variant, class: cls, ...props }: Props) => { + const symbols = await site.load("assets/symbols.svg"); + + return ( + + + Logo + + + + ); +}; diff --git a/src/ui/components/ReleaseCard.tsx b/src/ui/components/ReleaseCard.tsx new file mode 100644 index 0000000..bffe256 --- /dev/null +++ b/src/ui/components/ReleaseCard.tsx @@ -0,0 +1,47 @@ +import type { Select } from "corvos"; + +import type site from "@/corvos.config.ts"; + +import { CardBody } from "$/ui/objects/CardBody.tsx"; +import { Heading } from "$/ui/objects/Heading.tsx"; + +import { Card, type Props as CardProps } from "../objects/Card.tsx"; + +export type Props = CardProps<"a"> & { + "heading-level": "h1" | "h2" | "h3" | "h4" | "h5" | "h6"; + "page": Select; +}; + +export const ReleaseCard = ({ "heading-level": headingLevel, page, ...props }: Props) => { + return ( + + + + + + {page.data.title} + + + + +
    +
  • + +
  • +
+
+
+ ); +}; diff --git a/src/ui/components/SiteFooter.tsx b/src/ui/components/SiteFooter.tsx new file mode 100644 index 0000000..8bada2e --- /dev/null +++ b/src/ui/components/SiteFooter.tsx @@ -0,0 +1,39 @@ +import site from "@/corvos.config.ts"; + +import { Container } from "../layouts/Container.tsx"; +import { Divider } from "../objects/Divider.tsx"; +import { Logo } from "./Logo.tsx"; + +export const SiteFooter = async () => { + const symbols = await site.load("assets/symbols.svg"); + + return ( +
+ + + +
+ ); +}; diff --git a/src/ui/components/SiteHeader.tsx b/src/ui/components/SiteHeader.tsx new file mode 100644 index 0000000..17831a1 --- /dev/null +++ b/src/ui/components/SiteHeader.tsx @@ -0,0 +1,121 @@ +import type { HTMLAttributes } from "corvos/plugins/jsx.ts"; + +import { Icon } from "$/ui/objects/Icon.tsx"; + +import { nav } from "../../data/nav.ts"; +import { ActionButton } from "../objects/ActionButton.tsx"; +import { Navbar } from "../objects/Navbar.tsx"; +import { NavbarItem } from "../objects/NavbarItem.tsx"; +import { Logo } from "./Logo.tsx"; + +export type Props = HTMLAttributes<"header"> & { + "url": string; + "mode"?: "compact" | "none"; + "at-end"?: boolean; + "hidden"?: boolean; + "sm"?: JSX.Element; + "end"?: JSX.Element; + "children"?: JSX.Element; +}; + +export const SiteHeader = ({ + children, + sm, + url, + mode, + "at-end": atEnd, + hidden, + end, + class: cls, + ...props +}: Props) => { + const navItems = nav.map((item) => ({ + ...item, + selected: new RegExp(`^${item.url.replace("/#", "/")}`).test(url), + })); + + const parent = navItems + .filter((item) => item.url !== url) + .reduce( + (parent: (typeof navItems)[number] | undefined, item) => + item.selected && item.url.length > (parent?.url.length ?? 0) ? item : parent, + undefined, + ); + const selected = navItems.reduce( + (sel, item) => (item.selected && item.url.length > sel.url.length ? item : sel), + { + icon: "", + label: "Back", + selected: true, + url: "/", + }, + ); + + const variant = atEnd ? "static-white" : undefined; + + return ( + + ); +}; diff --git a/src/ui/components/SiteNav.tsx b/src/ui/components/SiteNav.tsx new file mode 100644 index 0000000..7518e3c --- /dev/null +++ b/src/ui/components/SiteNav.tsx @@ -0,0 +1,38 @@ +import { Icon } from "$/ui/objects/Icon.tsx"; + +import { nav } from "../../data/nav.ts"; +import { Navbar } from "../objects/Navbar.tsx"; +import { NavbarItem } from "../objects/NavbarItem.tsx"; + +export interface Props { + url: string; +} + +export const SiteNav = ({ url }: Props) => { + const navItems = nav + .filter((item) => !item.hidden) + .map((item) => ({ + ...item, + selected: item.url === "/" ? item.url === url : new RegExp(`^${item.url}`).test(url), + })); + + return ( + <> +
+ + + + ); +}; -- cgit v1.3.1