Compare commits

...

7 Commits

Author SHA1 Message Date
Callum Flack
1b6fc692aa example use of GroupWithSpace 2024-09-03 16:50:14 +10:00
Callum Flack
8e8abada48 add basic space system 2024-09-03 16:49:34 +10:00
Callum Flack
e83247407c example use of DS typography for 2 x Headers 2024-09-03 14:08:23 +10:00
Callum Flack
fd2e2b8d75 add basic typography system
* rename apply-color-theme > base-theme to account for typography inclusions
* using a theme file mean not having to add the design-system settings manually
2024-09-03 14:04:58 +10:00
Callum Flack
8c67734667 use color tokens in homepage project 2024-09-03 13:01:26 +10:00
Callum Flack
1047072edd revise color tokens for use 2024-09-03 13:01:26 +10:00
Callum Flack
3edb085272 add semantic colour tokens
requires use of the "selector" dark mode strategy: https://tailwindcss.com/docs/dark-mode
2024-09-03 09:35:20 +10:00
29 changed files with 1458 additions and 1038 deletions

View File

@@ -28,6 +28,7 @@
"eslint": "^8",
"eslint-config-next": "14.2.7",
"postcss": "^8",
"postcss-import": "^16.1.0",
"tailwindcss": "^3.4.1",
"typescript": "^5"
}

View File

@@ -1,6 +1,7 @@
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
"postcss-import": {},
tailwindcss: {},
},
};

View File

@@ -0,0 +1,57 @@
import { cva, cx, type VariantProps } from "class-variance-authority";
/*
Space helps you group related elements by whitespace, both vertically and horizontally. Use it to create layouts with whitespace.
*/
export const spaceVariants = cva([""], {
variants: {
vertical: {
minor: "space-y-d8",
major: "space-y-d16",
super: "space-y-d24",
},
container: {
true: "container",
},
},
compoundVariants: [
// EXAMPLE:
// {
// intent: "display",
// size: ["super", "title", "subtitle"],
// class: "text-super tracking-super",
// },
],
defaultVariants: {
// vertical: "default",
container: true,
},
});
export interface SpaceProps
extends React.HTMLAttributes<HTMLElement>,
VariantProps<typeof spaceVariants> {
as?: React.ElementType;
}
export function GroupWithSpace({
as: Component = "div",
vertical,
className,
...props
}: SpaceProps) {
return (
<Component
{...props}
className={cx(
spaceVariants({
vertical,
className,
})
)}
>
{props.children}
</Component>
);
}

View File

@@ -0,0 +1,103 @@
import { cva, cx, type VariantProps } from "class-variance-authority";
const displayStyle = "font-display font-semibold";
const headingStyle = "font-sans font-medium";
const paragraphStyle = "font-sans font-normal";
// const monoStyle = "font-mono font-medium";
export const textVariants = cva([], {
variants: {
intent: {
default: "",
link: "link",
markdown: "prose", // TBC
fine: [paragraphStyle, "text-fine subpixel-antialiased"],
// TODO: metaHeading: [monoStyle]
body: [paragraphStyle, "text-base"],
lead: [headingStyle, "text-lead"],
subheading: [displayStyle, "text-subheading"],
heading: [displayStyle, "text-heading"],
subtitle: [displayStyle, "text-subtitle"],
title: [displayStyle, "text-title"],
super: [displayStyle, "text-super"],
},
color: {
feint: "text-line",
dim: "text-solid",
default: "text-fill",
destructive: "text-destructive",
},
align: {
left: "text-left",
center: "text-center",
right: "text-right",
},
inline: {
true: "leading-none",
},
balance: {
true: "text-balance",
},
bullet: {
true: ["list-disc"],
},
},
// Compound variants apply classes when multiple other variant conditions are met: https://cva.style/docs/getting-started/variants#compound-variants
compoundVariants: [
// EXAMPLE:
// {
// intent: "display",
// size: ["super", "title", "subtitle"],
// class: "text-super tracking-super",
// },
],
// I find the less that is defaulted and the more inherited from the body element's typographic settings, the less property assignment is required. Let's wait & see what are needs are.
defaultVariants: {
// intent: "body",
// color: "default",
// align: "left",
},
});
export interface TextProps
extends Omit<React.HTMLAttributes<HTMLElement>, "color">,
VariantProps<typeof textVariants> {
as?: React.ElementType;
}
export const Text = ({
as: Component = "p",
className,
intent,
color,
align,
inline,
balance,
bullet,
...props
}: TextProps) => {
if (Component === "li") {
bullet = true;
}
return (
<Component
{...props}
className={cx(
textVariants({
intent,
color,
align,
inline,
balance,
bullet,
className,
}),
Component === "ul" ? "pl-[2em]" : ""
)}
>
{/* {format ? formatText(children) : children} */}
{props.children}
</Component>
);
};

View File

@@ -0,0 +1,2 @@
export * from "./Text";
export * from "./Space";

View File

@@ -1,23 +1,25 @@
import clsx from "clsx";
export function HairlineBleedGrid({ children }: { children: React.ReactNode }) {
return (
<div
className={clsx(
"grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6",
"mb-10",
"items-stretch",
"gap-[1px]",
"-mx-4 md:-mx-6",
"rounded-xl",
"overflow-hidden",
"bg-stone-50 dark:bg-stone-950",
"[&>*]:rounded-none",
"[&>*]:border-none",
"[&>*]:bg-stone-100 [&>*]:dark:bg-stone-900"
)}
>
{children}
</div>
);
return (
<div
className={clsx(
"grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6",
"mb-10",
"items-stretch",
"gap-[1px]",
"-mx-4 md:-mx-6",
"rounded-xl",
"overflow-hidden",
// "bg-stone-50 dark:bg-stone-950",
"bg-canvas",
"[&>*]:rounded-none",
"[&>*]:border-none",
// "[&>*]:bg-stone-100 [&>*]:dark:bg-stone-900"
"[&>*]:bg-background"
)}
>
{children}
</div>
);
}

View File

@@ -1,35 +1,23 @@
import { ReactNode } from "react";
import { H1 } from "../atoms/Headings";
import clsx from "clsx";
function H1Sub({ children }: { children: React.ReactNode }) {
return (
<p
className={clsx(
"text-3xl lg:text-4xl",
"leading-snug",
"tracking-tight",
"mb-5",
"max-w-4xl",
"text-stone-700 dark:text-stone-500"
)}
>
{children}
</p>
);
}
import { Text } from "../atoms";
export function HeroHeader({
title,
slogan,
title,
slogan,
}: {
title: ReactNode;
slogan: ReactNode;
title: ReactNode;
slogan: ReactNode;
}) {
return (
<hgroup className="md:pt-20 mb-10">
<H1>{title}</H1>
<H1Sub>{slogan}</H1Sub>
</hgroup>
);
return (
// prefer header over hgroup? I prefer to avoid semantic HTML as it has not made much difference to web apps or SEO or anything for the last decade. I do like header, footer, main, section, article, aside, etc. as they make sense in the context of a document. Naming this header or section would be premature, hgroup is actually better but folks reading it may assume they need to be pedantic here. So IMHO, div would suffice.
// no "mb-10 md:pt-20", always hoist whitespace styles to the parent.
<hgroup className="space-y-1.5">
<Text as="h1" intent="super">
{title}
</Text>
<Text as="h2" intent="subtitle" color="dim">
{slogan}
</Text>
</hgroup>
);
}

View File

@@ -1,34 +1,23 @@
import { ReactNode } from "react";
import { H2 } from "../atoms/Headings";
import clsx from "clsx";
function H2Sub({ children }: { children: React.ReactNode }) {
return (
<p
className={clsx(
"text-lg lg:text-xl",
"leading-snug",
"tracking-tight",
"max-w-4xl",
"text-stone-700 dark:text-stone-500"
)}
>
{children}
</p>
);
}
import { Text } from "../atoms";
export function SectionHeader({
title,
slogan,
title,
slogan,
}: {
title: ReactNode;
slogan: ReactNode;
title: ReactNode;
slogan: ReactNode;
}) {
return (
<hgroup className="mb-5">
<H2>{title}</H2>
<H2Sub>{slogan}</H2Sub>
</hgroup>
);
return (
// no mb-*, always hoist whitespace styles to the parent
<hgroup className="space-y-0.5">
<Text as="h2" intent="subheading">
{title}
</Text>
{/* remove "max-w-4xl", hoist width styles to the parent */}
<Text as="p" intent="lead" color="dim">
{slogan}
</Text>
</hgroup>
);
}

View File

@@ -0,0 +1,2 @@
export * from "./HeroHeader";
export * from "./SectionHeader";

View File

@@ -6,176 +6,166 @@ import { ReactNode, useLayoutEffect, useRef, useState } from "react";
import { BreadCrumb } from "../molecules/Breadcrumb";
import clsx from "clsx";
import Link from "next/link";
import { cva, cx, type VariantProps } from "class-variance-authority";
export function Nav({
mainLogo,
items,
docNav,
mainLogo,
items,
docNav,
}: {
mainLogo: ReactNode;
items: {
href: string;
icon?: ReactNode;
title: string;
firstOnRight?: boolean;
newTab?: boolean;
}[];
docNav: ReactNode;
mainLogo: ReactNode;
items: {
href: string;
icon?: ReactNode;
title: string;
firstOnRight?: boolean;
newTab?: boolean;
}[];
docNav: ReactNode;
}) {
const [menuOpen, setMenuOpen] = useState(false);
const [searchOpen, setSearchOpen] = useState(false);
const searchRef = useRef<HTMLInputElement>(null);
const [menuOpen, setMenuOpen] = useState(false);
const [searchOpen, setSearchOpen] = useState(false);
const searchRef = useRef<HTMLInputElement>(null);
useLayoutEffect(() => {
searchOpen && searchRef.current?.focus();
}, [searchOpen]);
useLayoutEffect(() => {
searchOpen && searchRef.current?.focus();
}, [searchOpen]);
const pathname = usePathname();
const pathname = usePathname();
return (
<>
<nav
className={[
clsx(
"hidden md:flex sticky left-0 right-0 top-0 max-sm:bottom-0 w-full justify-center",
"bg-stone-50 dark:bg-stone-950 border-b max-sm:border-t border-stone-50 dark:border-b-stone-950",
"max-h-none overflow-hidden transition[max-height] duration-300 ease-in-out",
"z-50",
menuOpen ? "h-[100dvh]" : "h-16"
)
].join(" ")}
return (
<>
<nav
className={cx(
"hidden sticky inset-x-0 top-0 max-sm:bottom-0 w-full",
"md:flex justify-center z-50",
// "bg-stone-50 dark:bg-stone-950 border-b max-sm:border-t border-stone-50 dark:border-b-stone-950",
"bg-canvas border-canvas max-sm:border-t",
"max-h-none overflow-hidden transition-[max-height] duration-300 ease-in-out",
menuOpen ? "h-[100dvh]" : "h-16"
)}
>
<div className="flex flex-wrap px-8 items-center max-sm:justify-between lg:gap-2 max-w-[80rem] w-full">
<div className="flex items-center flex-shrink">
<NavLinkLogo prominent href="/" className="-ml-2">
{mainLogo}
</NavLinkLogo>
</div>
{items.map((item, i) =>
"icon" in item ? (
<NavLinkLogo key={i} href={item.href} newTab={item.newTab}>
{item.icon}
</NavLinkLogo>
) : (
<NavLink
key={i}
href={item.href}
newTab={item.newTab}
className={clsx(
"max-sm:w-full",
item.firstOnRight ? "md:ml-auto" : ""
)}
>
{item.title}
</NavLink>
)
)}
</div>
</nav>
<div className="flex items-center self-stretch px-4 md:hidden dark:text-white">
<NavLinkLogo prominent href="/" className="mr-auto">
{mainLogo}
</NavLinkLogo>
<button
className="flex items-center p-3 rounded-xl"
onMouseDown={() => {
setMenuOpen((o) => !o);
setSearchOpen(false);
}}
>
<MenuIcon className="mr-2" />
<BreadCrumb items={items} />
</button>
</div>
<div
onClick={() => {
setMenuOpen(false);
setSearchOpen(false);
}}
className={clsx(
menuOpen || searchOpen ? "block" : "hidden",
"fixed top-0 bottom-0 left-0 right-0 bg-stone-200/80 dark:bg-black/80 w-full h-full z-20"
)}
></div>
<nav
className={clsx(
"md:hidden fixed flex flex-col bottom-4 right-4 z-50",
"bg-stone-50 dark:bg-stone-925 dark:text-white border border-stone-100 dark:border-stone-900 dark:outline dark:outline-1 dark:outline-black/60 rounded-lg shadow-lg",
menuOpen || searchOpen ? "left-4" : ""
)}
>
<div className={clsx(menuOpen ? "block" : "hidden", " px-2 pb-2")}>
<div className="flex items-center w-full border-b border-stone-100 dark:border-stone-900">
<NavLinkLogo
prominent
href="/"
className="mr-auto"
onClick={() => setMenuOpen(false)}
>
<div className="flex flex-wrap px-8 items-center max-sm:justify-between lg:gap-2 max-w-[80rem] w-full">
<div className="flex items-center flex-shrink">
<NavLinkLogo prominent href="/" className="-ml-2">
{mainLogo}
</NavLinkLogo>
</div>
{items.map((item, i) =>
"icon" in item ? (
<NavLinkLogo
key={i}
href={item.href}
newTab={item.newTab}
>
{item.icon}
</NavLinkLogo>
) : (
<NavLink
key={i}
href={item.href}
newTab={item.newTab}
className={clsx(
"max-sm:w-full",
item.firstOnRight ? "md:ml-auto" : "",
)}
>
{item.title}
</NavLink>
),
)}
</div>
</nav>
<div className="md:hidden px-4 flex items-center self-stretch dark:text-white">
<NavLinkLogo prominent href="/" className="mr-auto">
{mainLogo}
{mainLogo}
</NavLinkLogo>
{items
.filter((item) => "icon" in item)
.map((item, i) => (
<NavLinkLogo key={i} href={item.href} newTab={item.newTab}>
{item.icon}
</NavLinkLogo>
<button
className="flex p-3 rounded-xl items-center"
onMouseDown={() => {
setMenuOpen((o) => !o);
setSearchOpen(false);
}}
>
<MenuIcon className="mr-2" />
<BreadCrumb items={items} />
</button>
))}
</div>
{pathname === "/docs" && (
<div className="max-h-[calc(100dvh-15rem)] p-4 border-b border-stone-100 dark:border-stone-900 overflow-x-auto prose-sm prose-ul:pl-1 prose-ul:ml-1 prose-li:my-2 prose-li:leading-tight prose-ul:list-['-']">
{docNav}
</div>
<div
onClick={() => {
setMenuOpen(false);
setSearchOpen(false);
}}
className={clsx(
menuOpen || searchOpen ? "block" : "hidden",
"fixed top-0 bottom-0 left-0 right-0 bg-stone-200/80 dark:bg-black/80 w-full h-full z-20",
)}
></div>
<nav
className={clsx(
"md:hidden fixed flex flex-col bottom-4 right-4 z-50",
"bg-stone-50 dark:bg-stone-925 dark:text-white border border-stone-100 dark:border-stone-900 dark:outline dark:outline-1 dark:outline-black/60 rounded-lg shadow-lg",
menuOpen || searchOpen ? "left-4" : "",
)}
>
<div
className={clsx(menuOpen ? "block" : "hidden", " px-2 pb-2")}
)}
<div className="flex justify-end gap-4 -mb-2">
{items
.filter((item) => !("icon" in item))
.slice(0, 3)
.map((item, i) => (
<>
<NavLink
key={i}
href={item.href}
onClick={() => setMenuOpen(false)}
newTab={item.newTab}
>
{item.title}
</NavLink>
</>
))}
</div>
<div className="flex justify-end gap-4 border-b border-stone-100 dark:border-stone-900">
{items
.filter((item) => !("icon" in item))
.slice(3)
.map((item, i) => (
<NavLink
key={i}
href={item.href}
onClick={() => setMenuOpen(false)}
newTab={item.newTab}
className={clsx("")}
>
<div className="flex items-center w-full border-b border-stone-100 dark:border-stone-900">
<NavLinkLogo
prominent
href="/"
className="mr-auto"
onClick={() => setMenuOpen(false)}
>
{mainLogo}
</NavLinkLogo>
{items
.filter((item) => "icon" in item)
.map((item, i) => (
<NavLinkLogo
key={i}
href={item.href}
newTab={item.newTab}
>
{item.icon}
</NavLinkLogo>
))}
</div>
{pathname === "/docs" && (
<div className="max-h-[calc(100dvh-15rem)] p-4 border-b border-stone-100 dark:border-stone-900 overflow-x-auto prose-sm prose-ul:pl-1 prose-ul:ml-1 prose-li:my-2 prose-li:leading-tight prose-ul:list-['-']">
{docNav}
</div>
)}
<div className="flex gap-4 justify-end -mb-2">
{items
.filter((item) => !("icon" in item))
.slice(0, 3)
.map((item, i) => (
<>
<NavLink
key={i}
href={item.href}
onClick={() => setMenuOpen(false)}
newTab={item.newTab}
>
{item.title}
</NavLink>
</>
))}
</div>
<div className="flex gap-4 justify-end border-b border-stone-100 dark:border-stone-900">
{items
.filter((item) => !("icon" in item))
.slice(3)
.map((item, i) => (
<NavLink
key={i}
href={item.href}
onClick={() => setMenuOpen(false)}
newTab={item.newTab}
className={clsx("")}
>
{item.title}
</NavLink>
))}
</div>
</div>
<div className="flex items-center self-stretch justify-end">
{/* <input
{item.title}
</NavLink>
))}
</div>
</div>
<div className="flex items-center self-stretch justify-end">
{/* <input
type="text"
className={clsx(
menuOpen || searchOpen ? "" : "hidden",
@@ -184,7 +174,7 @@ export function Nav({
placeholder="Search docs..."
ref={searchRef}
/> */}
{/* <button
{/* <button
className="flex p-3 rounded-xl"
onClick={() => {
setSearchOpen(true);
@@ -197,102 +187,102 @@ export function Nav({
>
<SearchIcon className="" />
</button> */}
<button
className="flex p-3 rounded-xl items-center"
onMouseDown={() => {
setMenuOpen((o) => !o);
setSearchOpen(false);
}}
>
{menuOpen || searchOpen ? (
<XIcon />
) : (
<>
<MenuIcon className="mr-2" />
<BreadCrumb items={items} />
</>
)}
</button>
</div>
</nav>
</>
);
<button
className="flex items-center p-3 rounded-xl"
onMouseDown={() => {
setMenuOpen((o) => !o);
setSearchOpen(false);
}}
>
{menuOpen || searchOpen ? (
<XIcon />
) : (
<>
<MenuIcon className="mr-2" />
<BreadCrumb items={items} />
</>
)}
</button>
</div>
</nav>
</>
);
}
function NavLink({
href,
className,
children,
onClick,
newTab,
href,
className,
children,
onClick,
newTab,
}: {
href: string;
className?: string;
children: ReactNode;
onClick?: () => void;
newTab?: boolean;
href: string;
className?: string;
children: ReactNode;
onClick?: () => void;
newTab?: boolean;
}) {
const path = usePathname();
const path = usePathname();
return (
<Link
href={href}
className={clsx(
"px-2 lg:px-4 py-3 text-sm",
className,
path === href
? "font-medium text-black dark:text-white cursor-default"
: "text-stone-600 dark:text-stone-400 hover:text-black dark:hover:text-white transition-colors hover:transition-none",
)}
onClick={onClick}
target={newTab ? "_blank" : undefined}
>
{children}
{newTab ? (
<span className="inline-block text-stone-300 dark:text-stone-700 relative -top-0.5 -left-0.5 -mr-2">
</span>
) : (
""
)}
</Link>
);
return (
<Link
href={href}
className={clsx(
"px-2 lg:px-4 py-3 text-sm",
className,
path === href
? "font-medium text-black dark:text-white cursor-default"
: "text-stone-600 dark:text-stone-400 hover:text-black dark:hover:text-white transition-colors hover:transition-none"
)}
onClick={onClick}
target={newTab ? "_blank" : undefined}
>
{children}
{newTab ? (
<span className="inline-block text-stone-300 dark:text-stone-700 relative -top-0.5 -left-0.5 -mr-2">
</span>
) : (
""
)}
</Link>
);
}
function NavLinkLogo({
href,
className,
children,
prominent,
onClick,
newTab,
href,
className,
children,
prominent,
onClick,
newTab,
}: {
href: string;
className?: string;
children: ReactNode;
prominent?: boolean;
onClick?: () => void;
newTab?: boolean;
href: string;
className?: string;
children: ReactNode;
prominent?: boolean;
onClick?: () => void;
newTab?: boolean;
}) {
const path = usePathname();
const path = usePathname();
return (
<Link
href={href}
className={clsx(
"max-sm:px-4 px-2 lg:px-3 py-3 transition-opacity hover:transition-none",
path === href
? "cursor-default"
: prominent
? "hover:opacity-50"
: "opacity-60 hover:opacity-100",
"text-black dark:text-white",
className,
)}
onClick={onClick}
target={newTab ? "_blank" : undefined}
>
{children}
</Link>
);
}
return (
<Link
href={href}
className={clsx(
"max-sm:px-4 px-2 lg:px-3 py-3 transition-opacity hover:transition-none",
path === href
? "cursor-default"
: prominent
? "hover:opacity-50"
: "opacity-60 hover:opacity-100",
"text-black dark:text-white",
className
)}
onClick={onClick}
target={newTab ? "_blank" : undefined}
>
{children}
</Link>
);
}

View File

@@ -1,45 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
/* .manrope-bold {
font-family: "Manrope", sans-serif;
font-optical-sizing: auto;
font-weight: 500;
font-style: normal;
} */
:root {
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 214, 219, 220;
--background-end-rgb: 255, 255, 255;
font-family: "Manrope", sans-serif;
font-optical-sizing: auto;
font-weight: 300;
font-style: normal;
}
@media (prefers-color-scheme: dark) {
:root {
--foreground-rgb: 255, 255, 255;
--background-start-rgb: 0, 0, 0;
--background-end-rgb: 0, 0, 0;
}
}
body {
color: rgb(var(--foreground-rgb));
background: linear-gradient(
to bottom,
transparent,
rgb(var(--background-end-rgb))
)
rgb(var(--background-start-rgb));
}
@layer utilities {
.text-balance {
text-wrap: balance;
}
}

View File

@@ -1,5 +1,5 @@
import type { Metadata } from 'next';
import './globals.css';
import type { Metadata } from "next";
import "../styles/globals.css";
import { Manrope } from "next/font/google";
import { Inter } from "next/font/google";
@@ -21,8 +21,8 @@ const pragmata = localFont({
});
export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
title: "Jazz Design System",
description: "The Jazz Design System",
};
export default function RootLayout({
@@ -32,11 +32,13 @@ export default function RootLayout({
}>) {
return (
<html lang="en">
<body className={[
manrope.variable,
pragmata.variable,
inter.className,
].join(" ")}>{children}</body>
<body
className={[manrope.variable, pragmata.variable, inter.className].join(
" "
)}
>
{children}
</body>
</html>
);
}

View File

@@ -0,0 +1,27 @@
// const result = generateClampFontSize(500, 1200, 11.5, 14);
// console.log(result); // clamp(11.5px, 9.7143px + 0.3571vw, 14px)
// prev used: https://clamp.font-size.app/
// alt method from klim.co.nz:
// w1: "calc(8 / var(--viewport-basis) * 100vw)"
export function generateClampSize(
minViewportWidth: number,
maxViewportWidth: number,
minFontSize: number,
maxFontSize: number
): string {
const minClampValue = `${minFontSize}px`;
const maxClampValue = `${maxFontSize}px`;
const fontSizeDiff = maxFontSize - minFontSize;
const viewportWidthDiff = maxViewportWidth - minViewportWidth;
const slope = fontSizeDiff / viewportWidthDiff;
const yIntercept = minFontSize - slope * minViewportWidth;
const clampExpression = `${yIntercept.toFixed(4)}px + ${(slope * 100).toFixed(
4
)}vw`;
return `clamp(${minClampValue}, ${clampExpression}, ${maxClampValue})`;
}

View File

@@ -0,0 +1,19 @@
@layer base {
* {
@apply border-border;
}
html {
@apply bg-canvas;
}
::selection {
@apply bg-fill text-canvas;
}
body {
@apply font-sans font-normal antialiased;
@apply text-base;
@apply bg-canvas text-fill;
/* transition color everywhere: do NOT use tailwind here as the variables are inherited across every transition across the codebase */
transition: color 50ms ease 0s;
}
}

View File

@@ -0,0 +1,38 @@
.dark,
.dark-theme {
--stone-950: #fefbf5;
--stone-925: #fcf9f2;
--stone-900: #f7f3ee;
--stone-800: #e7e3de;
--stone-700: #d2cec9;
--stone-600: #bdbab5;
--stone-500: #aaa6a1;
--stone-400: #87837f;
--stone-300: #6d6965;
--stone-200: #4e4a46;
--stone-100: #312e2a;
--stone-75: #252320;
--stone-50: #171411;
}
@supports (color: oklch(0% 0 0)) {
@media (color-gamut: p3) {
.dark,
.dark-theme {
--stone-950: oklch(0.988281 0.002 75);
--stone-925: oklch(0.980563 0.002 75);
--stone-900: oklch(0.964844 0.002 75);
--stone-800: oklch(0.917969 0.002 75);
--stone-700: oklch(0.853516 0.002 75);
/* --stone-700: oklch(0.523438 0.002 75); */
--stone-600: oklch(0.789063 0.002 75);
--stone-500: oklch(0.726563 0.002 75);
--stone-400: oklch(0.613281 0.002 75);
--stone-300: oklch(0.523438 0.002 75);
--stone-200: oklch(0.412109 0.002 75);
--stone-100: oklch(0.302734 0.002 75);
--stone-75: oklch(0.22 0.002 75);
--stone-50: oklch(0.193359 0.002 75);
}
}
}

View File

@@ -0,0 +1,35 @@
:root {
--stone-50: #fefbf5;
--stone-75: #fcf9f2;
--stone-100: #f7f3ee;
--stone-200: #e7e3de;
--stone-300: #d2cec9;
--stone-400: #bdbab5;
--stone-500: #aaa6a1;
--stone-600: #87837f;
--stone-700: #6d6965;
--stone-800: #4e4a46;
--stone-900: #312e2a;
--stone-925: #252320;
--stone-950: #171411;
}
@supports (color: oklch(0% 0 0)) {
@media (color-gamut: p3) {
:root {
--stone-50: oklch(0.988281 0.002 75);
--stone-75: oklch(0.980563 0.002 75);
--stone-100: oklch(0.964844 0.002 75);
--stone-200: oklch(0.917969 0.002 75);
--stone-300: oklch(0.853516 0.002 75);
--stone-400: oklch(0.789063 0.002 75);
--stone-500: oklch(0.726563 0.002 75);
--stone-600: oklch(0.613281 0.002 75);
--stone-700: oklch(0.523438 0.002 75);
--stone-800: oklch(0.412109 0.002 75);
--stone-900: oklch(0.302734 0.002 75);
--stone-925: oklch(0.22 0.002 75);
--stone-950: oklch(0.193359 0.002 75);
}
}
}

View File

@@ -0,0 +1,42 @@
@import "./color-custom-stone.css";
@import "./color-custom-stone-dark.css";
@layer base {
:root {
/* GRAY */
/* backgrounds & panels */
--color-gray-base: var(--stone-50);
--color-gray-bg-subtle: var(--stone-75);
--color-gray-bg: var(--stone-100);
--color-gray-bg-hover: var(--stone-200);
--color-gray-bg-active: var(--stone-300);
/* borders, lines & focus rings */
--color-gray-border-light: var(--stone-200);
--color-gray-border: var(--stone-300);
--color-gray-border-hover: var(--stone-400);
--color-gray-line: var(--stone-500);
/* solids */
--color-gray-light: var(--stone-600);
--color-gray-solid: var(--stone-700);
--color-gray-solid-hover: var(--stone-800);
/* fills */
--color-gray-fill: var(--stone-900);
--color-gray-fill-contrast: var(--stone-950);
/* ACCENT */
/* TODO: We'll populate this schema as we need… */
--color-accent-fill: #3313f7;
}
}
/*
Dark theme variations.
Because `.dark` only exists when next-themes renders it,
we don't wrap it in `base` b/c we don't want Tailwind to omit it.
*/
.dark {
--color-gray-solid: var(--stone-500);
}

View File

@@ -0,0 +1,13 @@
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
@import "./color-theme.css";
@import "./space-theme.css";
@import "./base-theme.css";
:root {
font-family: "Manrope", sans-serif;
font-optical-sizing: auto;
font-weight: 300;
font-style: normal;
}

View File

@@ -0,0 +1,23 @@
/* @import "@radix-ui/colors/black-alpha.css"; */
/* @import "@evilmartians/harmony/css/stone.css"; */
@import "./color-custom-stone.css";
@import "./color-custom-stone-dark.css";
@layer base {
:root {
--radius: 8px;
--height-nav: 80px;
--height-tab: 54px;
--space-inset: 20px;
--space-inset-2x: calc(var(--space-inset) * 2);
--container-text-px: 660px;
--container-text: calc(var(--container-text-px) - (var(--space-inset) * 2));
--container-hero-px: 1000px;
--container-hero: calc(var(--container-hero-px) - (var(--space-inset) * 2));
--inset-full: calc((100vw - (var(--space-inset) * 2)));
--inset-text: calc((100vw - var(--container-text)) / 2);
--inset-hero: calc((100vw - var(--container-hero)) / 2);
}
}

View File

@@ -1,95 +1,221 @@
import harmonyPalette from "@evilmartians/harmony/tailwind";
import typography from "@tailwindcss/typography";
import tailwindCSSAnimate from "tailwindcss-animate";
import { generateClampSize } from "./src/lib/generate-clamp-size";
const lineHeight = {
body: `${24 / 17}`,
heading: "1.333",
title: "1.2",
super: "0.98",
};
const letterSpacing = {
meta: "0.02em",
body: "0",
heading: "-0.01em",
super: "-0.03em",
};
/** @type {import('tailwindcss').Config} */
const config = {
content: [
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
colors: {
...harmonyPalette,
stone: {
"50": "oklch(0.988281 0.002 75 / <alpha-value>)",
"75": "oklch(0.980563 0.002 75 / <alpha-value>)",
"100": "oklch(0.964844 0.002 75 / <alpha-value>)",
"200": "oklch(0.917969 0.002 75 / <alpha-value>)",
"300": "oklch(0.853516 0.002 75 / <alpha-value>)",
"400": "oklch(0.789063 0.002 75 / <alpha-value>)",
"500": "oklch(0.726563 0.002 75 / <alpha-value>)",
"600": "oklch(0.613281 0.002 75 / <alpha-value>)",
"700": "oklch(0.523438 0.002 75 / <alpha-value>)",
"800": "oklch(0.412109 0.002 75 / <alpha-value>)",
"900": "oklch(0.302734 0.002 75 / <alpha-value>)",
"925": "oklch(0.220000 0.002 75 / <alpha-value>)",
"950": "oklch(0.193359 0.002 75 / <alpha-value>)",
},
},
extend: {
fontFamily: {
display: ["var(--font-manrope)"],
mono: ["var(--font-ppr)"],
},
// shadcn-ui
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
},
content: [
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
],
darkMode: "selector",
theme: {
colors: {
// DARK SPECTRUM
canvas: "var(--color-gray-base)", // avoids name clash with text-base
"background-subtle": "var(--color-gray-bg-subtle)",
background: "var(--color-gray-bg)",
"background-hover": "var(--color-gray-bg-hover)",
"background-active": "var(--color-gray-bg-active)",
"border-light": "var(--color-gray-border-light)",
border: "var(--color-gray-border)",
"border-hover": "var(--color-gray-border-hover)",
line: "var(--color-gray-line)",
"solid-light": "var(--color-gray-light)",
solid: "var(--color-gray-solid)",
"solid-hover": "var(--color-gray-solid-hover)",
"fill-tint": "var(--color-gray-fill)",
fill: "var(--color-gray-fill-contrast)",
// ACCENT SPECTRUM
accent: "var(--color-accent-fill)",
},
plugins: [tailwindCSSAnimate, typography()],
fontSize: {
xs: [
generateClampSize(500, 1200, 9, 11),
{ lineHeight: lineHeight.body, letterSpacing: letterSpacing.body },
],
fine: [
generateClampSize(500, 1200, 9, 11),
{ lineHeight: lineHeight.body, letterSpacing: letterSpacing.body },
],
meta: [
generateClampSize(500, 1200, 11, 13),
{ lineHeight: lineHeight.body, letterSpacing: letterSpacing.body },
],
small: [
generateClampSize(500, 1200, 12, 14),
{ lineHeight: lineHeight.body, letterSpacing: letterSpacing.body },
],
base: [
generateClampSize(500, 1200, 14, 16),
{ lineHeight: lineHeight.body, letterSpacing: letterSpacing.body },
],
large: [
generateClampSize(500, 1200, 15, 17),
{ lineHeight: lineHeight.body, letterSpacing: letterSpacing.body },
],
lead: [
generateClampSize(500, 1200, 17, 20),
{
lineHeight: lineHeight.body,
letterSpacing: letterSpacing.heading,
},
],
subheading: [
generateClampSize(500, 1200, 18, 24),
{
lineHeight: lineHeight.heading,
letterSpacing: letterSpacing.heading,
},
],
heading: [
generateClampSize(500, 1200, 20, 27),
{ lineHeight: lineHeight.title, letterSpacing: letterSpacing.heading },
],
subtitle: [
generateClampSize(500, 1200, 22, 36),
{ lineHeight: lineHeight.title, letterSpacing: letterSpacing.heading },
],
title: [
generateClampSize(500, 1200, 27, 42),
{ lineHeight: lineHeight.title, letterSpacing: letterSpacing.heading },
],
subsuper: [
generateClampSize(500, 1200, 32, 48),
{ lineHeight: lineHeight.super, letterSpacing: letterSpacing.super },
],
super: [
generateClampSize(500, 1200, 39, 60),
{ lineHeight: lineHeight.super, letterSpacing: letterSpacing.super },
],
display: [
generateClampSize(500, 1200, 39, 60),
{ lineHeight: lineHeight.super, letterSpacing: letterSpacing.super },
],
},
container: {
center: true,
padding: "var(--space-inset)",
screens: {
// lg: "var(--container-text)", doesn't take vars WTF?
xl: "1280px",
},
},
spacing: {
// new default used to mtach icons to font-size
em: "1em",
// insets & heights
navH: "var(--height-nav)",
tabH: "var(--height-tab)",
inset: "var(--space-inset)",
"inset-2x": "var(--space-inset-2x)",
// horizontal containers
"text-px": "var(--container-text-px)",
text: "var(--container-text)",
"hero-px": "var(--container-hero-px)",
hero: "var(--container-hero)",
mobile: "639px",
"inset-full": "var(--inset-full)",
"inset-hero": "var(--inset-hero)",
"inset-text": "var(--inset-text)",
// lower value is 2/3 of upper value
d4: generateClampSize(500, 1200, 10.5, 16),
d6: generateClampSize(500, 1200, 16, 24),
d8: generateClampSize(500, 1200, 21, 32),
d12: generateClampSize(500, 1200, 32, 48),
d16: generateClampSize(500, 1200, 43, 64),
d20: generateClampSize(500, 1200, 54, 80),
d24: generateClampSize(500, 1200, 64, 96),
d28: generateClampSize(500, 1200, 75, 112),
d32: generateClampSize(500, 1200, 85, 128),
d36: generateClampSize(500, 1200, 96, 144),
d42: generateClampSize(500, 1200, 112, 168),
d48: generateClampSize(500, 1200, 128, 192),
d64: generateClampSize(500, 1200, 171, 256),
d72: generateClampSize(500, 1200, 192, 288),
d96: generateClampSize(500, 1200, 256, 384),
// Tailwind defaults: we need to import these here because we're creating a new theme, not extending it
px: "1px",
0: "0px",
0.5: "0.125rem",
1: "0.25rem",
1.5: "0.375rem",
2: "0.5rem",
2.5: "0.625rem",
3: "0.75rem",
3.5: "0.875rem",
4: "1rem",
5: "1.25rem",
6: "1.5rem",
7: "1.75rem",
8: "2rem",
9: "2.25rem",
10: "2.5rem",
11: "2.75rem",
12: "3rem",
14: "3.5rem",
16: "4rem",
20: "5rem",
24: "6rem",
28: "7rem",
32: "8rem",
36: "9rem",
40: "10rem",
44: "11rem",
48: "12rem",
52: "13rem",
56: "14rem",
60: "15rem",
64: "16rem",
72: "18rem",
80: "20rem",
96: "24rem",
},
extend: {
fontFamily: {
display: ["var(--font-manrope)"],
mono: ["var(--font-ppr)"],
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
},
},
plugins: [tailwindCSSAnimate, typography()],
};
export default config;

View File

@@ -15,6 +15,7 @@ import { UL } from "gcmp-design-system/src/app/components/molecules/List";
import { LI } from "gcmp-design-system/src/app/components/atoms/ListItem";
import { P } from "gcmp-design-system/src/app/components/atoms/Paragraph";
import { TextLink } from "gcmp-design-system/src/app/components/atoms/TextLink";
import { GroupWithSpace } from "gcmp-design-system/src/app/components/atoms";
import {
UploadCloudIcon,
@@ -54,63 +55,64 @@ import { H3 } from "gcmp-design-system/src/app/components/atoms/Headings";
export default function Home() {
return (
<>
<HeroHeader
title="Instant sync."
slogan="A new way to build apps with distributed state."
/>
<GroupWithSpace as="section" vertical="minor">
<HeroHeader
title="Instant sync."
slogan="A new way to build apps with distributed state."
/>
<HairlineBleedGrid>
<LabelledFeatureIcon
label="Cross-device sync"
icon={MonitorSmartphoneIcon}
/>
<LabelledFeatureIcon
label="Real-time multiplayer"
icon={SquareMousePointerIcon}
/>
<LabelledFeatureIcon
label="Team/social features"
icon={UsersIcon}
/>
<LabelledFeatureIcon
label="Built-in permissions"
icon={FileLock2Icon}
/>
<LabelledFeatureIcon
label="Cloud sync & storage"
icon={UploadCloudIcon}
/>
<LabelledFeatureIcon
label="On-device storage"
icon={HardDriveDownloadIcon}
/>
<LabelledFeatureIcon
label="Instant UI updates"
icon={GaugeIcon}
/>
<LabelledFeatureIcon
label="E2EE & signatures"
icon={KeyRoundIcon}
/>
<HairlineBleedGrid>
<LabelledFeatureIcon
label="Cross-device sync"
icon={MonitorSmartphoneIcon}
/>
<LabelledFeatureIcon
label="Real-time multiplayer"
icon={SquareMousePointerIcon}
/>
<LabelledFeatureIcon
label="Team/social features"
icon={UsersIcon}
/>
<LabelledFeatureIcon
label="Built-in permissions"
icon={FileLock2Icon}
/>
<LabelledFeatureIcon
label="Cloud sync & storage"
icon={UploadCloudIcon}
/>
<LabelledFeatureIcon
label="On-device storage"
icon={HardDriveDownloadIcon}
/>
<LabelledFeatureIcon
label="Instant UI updates"
icon={GaugeIcon}
/>
<LabelledFeatureIcon
label="E2EE & signatures"
icon={KeyRoundIcon}
/>
<div className="col-span-2 col-start-1 row-span-2 row-start-1 px-4 pb-4 text-base md:px-6">
<Prose>
<Intro />
</Prose>
</div>
</HairlineBleedGrid>
</GroupWithSpace>
<div className="col-start-1 row-start-1 row-span-2 col-span-2 px-4 md:px-6 pb-4 text-base">
<Prose>
<Intro />
</Prose>
</div>
</HairlineBleedGrid>
<div className="-mx-[calc(min(0,(100vw-95rem)/2))]">
<GroupWithSpace as="section" vertical="minor">
<SectionHeader
title="First impressions..."
slogan="A chat app in 84 lines of code."
/>
<GappedGrid className="mt-0 -mx-4 md:-mx-6">
<div className="md:col-start-1 col-span-2">
<div className="col-span-2 md:col-start-1">
<App_tsx />
</div>
<div className="md:col-start-3 col-span-2">
<div className="col-span-2 md:col-start-3">
<ChatScreen_tsx />
</div>
<ResponsiveIframe
@@ -119,102 +121,108 @@ export default function Home() {
className="lg:col-start-5 col-span-2 rounded-xl overflow-hidden min-h-[50vh]"
/>
</GappedGrid>
</div>
</GroupWithSpace>
<SectionHeader
title="Collaborative Values"
slogan="Your new building blocks."
/>
<Prose>
<CoValuesIntro />
</Prose>
<GroupWithSpace as="section" vertical="minor">
<SectionHeader
title="Collaborative Values"
slogan="Your new building blocks."
/>
<Prose>
<CoValuesIntro />
</Prose>
<GappedGrid
title="Bread-and-butter datastructures"
className="grid-cols-2 lg:grid-cols-4"
>
<GridCard>
<H3>
<CodeRef>CoMap</CodeRef>
</H3>
<SmallProse>
<CoMapDescription />
</SmallProse>
</GridCard>
<GappedGrid
title="Bread-and-butter datastructures"
className="grid-cols-2 lg:grid-cols-4"
>
<GridCard>
<H3>
<CodeRef>CoMap</CodeRef>
</H3>
<SmallProse>
<CoMapDescription />
</SmallProse>
</GridCard>
<GridCard>
<H3>
<CodeRef>CoList</CodeRef>
</H3>
<SmallProse>
<CoListDescription />
</SmallProse>
</GridCard>
<GridCard>
<H3>
<CodeRef>CoList</CodeRef>
</H3>
<SmallProse>
<CoListDescription />
</SmallProse>
</GridCard>
<GridCard>
<H3>
<CodeRef>CoPlainText</CodeRef> &{" "}
<CodeRef>CoRichText</CodeRef> <ComingSoonBadge />
</H3>
<SmallProse>
<CoPlainTextDescription />
</SmallProse>
</GridCard>
<GridCard>
<H3>
<CodeRef>CoPlainText</CodeRef> &{" "}
<CodeRef>CoRichText</CodeRef> <ComingSoonBadge />
</H3>
<SmallProse>
<CoPlainTextDescription />
</SmallProse>
</GridCard>
<GridCard>
<H3>
<CodeRef>CoStream</CodeRef>
</H3>
<SmallProse>
<CoStreamDescription />
</SmallProse>
</GridCard>
</GappedGrid>
<GridCard>
<H3>
<CodeRef>CoStream</CodeRef>
</H3>
<SmallProse>
<CoStreamDescription />
</SmallProse>
</GridCard>
</GappedGrid>
</GroupWithSpace>
<GappedGrid
title="First-class files & binary data"
className="grid-cols-2 lg:grid-cols-4"
>
<GridCard>
<H3>
<CodeRef>BinaryCoStream</CodeRef>
</H3>
<SmallProse>
<BinaryCoStreamDescription />
</SmallProse>
</GridCard>
<GroupWithSpace as="section" vertical="minor">
<GappedGrid
title="First-class files & binary data"
className="grid-cols-2 lg:grid-cols-4"
>
<GridCard>
<H3>
<CodeRef>BinaryCoStream</CodeRef>
</H3>
<SmallProse>
<BinaryCoStreamDescription />
</SmallProse>
</GridCard>
<GridCard>
<H3>
<CodeRef>ImageDefinition</CodeRef>
</H3>
<SmallProse>
<ImageDefinitionDescription />
</SmallProse>
</GridCard>
</GappedGrid>
<GridCard>
<H3>
<CodeRef>ImageDefinition</CodeRef>
</H3>
<SmallProse>
<ImageDefinitionDescription />
</SmallProse>
</GridCard>
</GappedGrid>
</GroupWithSpace>
<GappedGrid
title="Secure permissions, authorship & teams"
className="grid-cols-2 lg:grid-cols-4"
>
<GridCard>
<H3>
<CodeRef>Group</CodeRef>
</H3>
<SmallProse>
<GroupDescription />
</SmallProse>
</GridCard>
<GridCard>
<H3>
<CodeRef>Account</CodeRef>
</H3>
<SmallProse>
<AccountDescription />
</SmallProse>
</GridCard>
</GappedGrid>
<GroupWithSpace as="section" vertical="minor">
<GappedGrid
title="Secure permissions, authorship & teams"
className="grid-cols-2 lg:grid-cols-4"
>
<GridCard>
<H3>
<CodeRef>Group</CodeRef>
</H3>
<SmallProse>
<GroupDescription />
</SmallProse>
</GridCard>
<GridCard>
<H3>
<CodeRef>Account</CodeRef>
</H3>
<SmallProse>
<AccountDescription />
</SmallProse>
</GridCard>
</GappedGrid>
</GroupWithSpace>
<SectionHeader
title="The Jazz Toolkit"
@@ -293,32 +301,42 @@ export default function Home() {
</GridCard>
</GappedGrid>
<SectionHeader
title="Jazz Mesh"
slogan="Serverless sync & storage for Jazz apps"
/>
<GroupWithSpace as="section" vertical="minor">
<SectionHeader
title="Jazz Mesh"
slogan="Serverless sync & storage for Jazz apps"
/>
<Prose>
<MeshIntro />
</Prose>
<Prose>
<MeshIntro />
</Prose>
<P>{'->'} <TextLink href="/mesh" target="_blank">
Learn more about Jazz Mesh
</TextLink></P>
<H3>Get Started</H3>
<UL>
<LI>
<TextLink href="/docs" target="_blank">
Read the docs
<P>
{"->"}{" "}
<TextLink href="/mesh" target="_blank">
Learn more about Jazz Mesh
</TextLink>
</LI>
<LI>
<TextLink href="https://discord.gg/utDMjHYg42" target="_blank">
Join our Discord
</TextLink>
</LI>
</UL>
</P>
</GroupWithSpace>
<GroupWithSpace as="section" vertical="minor">
<H3>Get Started</H3>
<UL>
<LI>
<TextLink href="/docs" target="_blank">
Read the docs
</TextLink>
</LI>
<LI>
<TextLink
href="https://discord.gg/utDMjHYg42"
target="_blank"
>
Join our Discord
</TextLink>
</LI>
</UL>
</GroupWithSpace>
</>
);
}

View File

@@ -1,418 +1,21 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
@import "gcmp-design-system/src/styles/color-theme.css";
@import "gcmp-design-system/src/styles/space-theme.css";
@import "gcmp-design-system/src/styles/base-theme.css";
@import "../styles/code-theme.css";
@layer base, shiki;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 20 14.3% 4.1%;
--card: 0 0% 100%;
--card-foreground: 20 14.3% 4.1%;
--popover: 0 0% 100%;
--popover-foreground: 20 14.3% 4.1%;
--primary: 24 9.8% 10%;
--primary-foreground: 60 9.1% 97.8%;
--secondary: 60 4.8% 95.9%;
--secondary-foreground: 24 9.8% 10%;
--muted: 60 4.8% 95.9%;
--muted-foreground: 25 5.3% 44.7%;
--accent: 60 4.8% 95.9%;
--accent-foreground: 24 9.8% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 60 9.1% 97.8%;
--border: 20 5.9% 90%;
--input: 20 5.9% 90%;
--ring: 20 14.3% 4.1%;
--radius: 0.5rem;
}
.dark {
--background: 20 14.3% 4.1%;
--foreground: 60 9.1% 97.8%;
--card: 20 14.3% 4.1%;
--card-foreground: 60 9.1% 97.8%;
--popover: 20 14.3% 4.1%;
--popover-foreground: 60 9.1% 97.8%;
--primary: 60 9.1% 97.8%;
--primary-foreground: 24 9.8% 10%;
--secondary: 12 6.5% 15.1%;
--secondary-foreground: 60 9.1% 97.8%;
--muted: 12 6.5% 15.1%;
--muted-foreground: 24 5.4% 63.9%;
--accent: 12 6.5% 15.1%;
--accent-foreground: 60 9.1% 97.8%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 60 9.1% 97.8%;
--border: 12 6.5% 15.1%;
--input: 12 6.5% 15.1%;
--ring: 24 5.7% 82.9%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
.overlay-close {
background-color: "black";
@apply bg-fill-contrast;
}
}
pre.shiki {
overflow: hidden;
}
pre.shiki:hover .dim {
opacity: 1;
}
pre.shiki div.dim {
opacity: 0.5;
}
pre.shiki div.dim,
pre.shiki div.highlight {
margin: 0;
padding: 0;
}
pre.shiki div.highlight {
opacity: 1;
background-color: #f1f8ff;
}
pre.shiki div.line {
/* min-height: 1rem; */
counter-increment: lineNumber 1;
}
pre.shiki div.line::before {
content: counter(lineNumber);
display: inline-block;
vertical-align: middle;
width: 1.3rem;
padding-right: 0.3rem;
text-align: right;
transition: color 0.3s;
@apply text-stone-200/50 dark:text-stone-900 text-[0.65rem];
}
pre.shiki div.line:hover::before {
@apply text-stone-400 dark:text-stone-600;
}
/** Don't show the language identifiers */
pre.shiki .language-id {
display: none;
}
/** When you mouse over the pre, show the underlines */
pre.twoslash:hover data-lsp {
@apply border-dotted border-b border-stone-300 dark:border-stone-700;
}
/** The tooltip-like which provides the LSP response */
pre.twoslash data-lsp::before {
content: attr(lsp);
position: absolute;
transform: translate(0, 1.2rem);
max-width: 30rem;
@apply text-xs px-1.5 py-1 rounded border border-stone-200 dark:border-stone-800 shadow-lg overflow-hidden whitespace-pre-wrap text-stone-700 bg-stone-50 dark:text-stone-200 dark:bg-stone-950;
text-align: left;
z-index: 100;
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
display: none;
}
pre.twoslash data-lsp:hover::before {
display: block;
opacity: 1;
pointer-events: visible;
width: auto;
height: auto;
}
.shiki-outer {
@apply shadow-sm rounded-xl;
}
.shiki-filename {
@apply px-3 py-2 bg-stone-100 text-stone-700 dark:bg-stone-900 dark:text-stone-300 rounded-t-xl text-xs;
}
pre .code-container {
overflow: scroll;
@apply p-2 pl-0 bg-stone-75 dark:bg-stone-925 rounded-b-xl text-[0.8rem] leading-tight border border-stone-100 dark:border-stone-900;
}
/* The try button */
pre .code-container > a {
position: absolute;
right: 8px;
bottom: 8px;
border-radius: 4px;
border: 1px solid #719af4;
padding: 0 8px;
color: #719af4;
text-decoration: none;
opacity: 0;
transition-timing-function: ease;
transition: opacity 0.3s;
}
/* Respect no animations */
@media (prefers-reduced-motion: reduce) {
pre .code-container > a {
transition: none;
}
}
pre .code-container > a:hover {
color: white;
background-color: #719af4;
}
pre .code-container:hover a {
opacity: 1;
}
pre code {
white-space: pre;
}
pre code a {
text-decoration: none;
}
pre data-err {
/* Extracted from VS Code */
background: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23c94824'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E")
repeat-x bottom left;
padding-bottom: 3px;
}
pre .query {
margin-bottom: 10px;
color: #137998;
display: inline-block;
}
/* In order to have the 'popped out' style design and to not break the layout
/* we need to place a fake and un-selectable copy of the error which _isn't_ broken out
/* behind the actual error message.
/* This sections keeps both of those two in in sync */
pre .error,
pre .error-behind {
margin-left: -14px;
margin-top: 8px;
margin-bottom: 4px;
padding: 6px;
padding-left: 14px;
width: calc(100% - 20px);
white-space: pre-wrap;
display: block;
}
pre .error {
position: absolute;
background-color: #fee;
border-left: 2px solid #bf1818;
/* Give the space to the error code */
display: flex;
align-items: center;
color: black;
}
pre .error .code {
display: none;
}
pre .error-behind {
user-select: none;
visibility: transparent;
color: #fee;
}
/* Queries */
pre .arrow {
/* Transparent background */
background-color: #eee;
position: relative;
top: -7px;
margin-left: 0.1rem;
/* Edges */
border-left: 1px solid #eee;
border-top: 1px solid #eee;
transform: translateY(25%) rotate(45deg);
/* Size */
height: 8px;
width: 8px;
}
pre .popover {
margin-bottom: 10px;
background-color: #eee;
display: inline-block;
padding: 0 0.5rem 0.3rem;
margin-top: 10px;
border-radius: 3px;
}
/* Completion */
pre .inline-completions ul.dropdown {
display: inline-block;
position: absolute;
width: 240px;
background-color: gainsboro;
color: grey;
padding-top: 4px;
font-family: var(--code-font);
font-size: 0.8rem;
margin: 0;
padding: 0;
border-left: 4px solid #4b9edd;
}
pre .inline-completions ul.dropdown::before {
background-color: #4b9edd;
width: 2px;
position: absolute;
top: -1.2rem;
left: -3px;
content: " ";
}
pre .inline-completions ul.dropdown li {
overflow-x: hidden;
padding-left: 4px;
margin-bottom: 4px;
}
pre .inline-completions ul.dropdown li.deprecated {
text-decoration: line-through;
}
pre .inline-completions ul.dropdown li span.result-found {
color: #4b9edd;
}
pre .inline-completions ul.dropdown li span.result {
width: 100px;
color: black;
display: inline-block;
}
.dark-theme .markdown pre {
background-color: #d8d8d8;
border-color: #ddd;
filter: invert(98%) hue-rotate(180deg);
}
data-lsp {
/* Ensures there's no 1px jump when the hover happens */
border-bottom: 1px dotted transparent;
/* Fades in unobtrusively */
transition-timing-function: ease;
transition: border-color 0.3s;
}
/* Respect people's wishes to not have animations */
@media (prefers-reduced-motion: reduce) {
data-lsp {
transition: none;
}
}
/** Annotations support, providing a tool for meta commentary */
.tag-container {
position: relative;
}
.tag-container .twoslash-annotation {
position: absolute;
font-family:
"JetBrains Mono",
Menlo,
Monaco,
Consolas,
Courier New,
monospace;
right: -10px;
/** Default annotation text to 200px */
width: 200px;
color: #187abf;
background-color: #fcf3d9 bb;
}
.tag-container .twoslash-annotation p {
text-align: left;
font-size: 0.8rem;
line-height: 0.9rem;
}
.tag-container .twoslash-annotation svg {
float: left;
margin-left: -44px;
}
.tag-container .twoslash-annotation.left {
right: auto;
left: -200px;
}
.tag-container .twoslash-annotation.left svg {
float: right;
margin-right: -5px;
}
/** Support for showing console log/warn/errors inline */
pre .logger {
display: flex;
align-items: center;
color: black;
padding: 6px;
padding-left: 8px;
width: calc(100% - 19px);
white-space: pre-wrap;
}
pre .logger svg {
margin-right: 9px;
}
pre .logger.error-log {
background-color: #fee;
border-left: 2px solid #bf1818;
}
pre .logger.warn-log {
background-color: #ffe;
border-left: 2px solid #eae662;
}
pre .logger.log-log {
background-color: #e9e9e9;
border-left: 2px solid #ababab;
}
pre .logger.log-log svg {
margin-left: 6px;
margin-right: 9px;
}
body {
--shiki-color-text: #606060;
--shiki-color-background: transparent;
--shiki-token-constant: #00a5a5;
--shiki-token-string: #4e3a2c;
--shiki-token-comment: #aaa;
--shiki-token-keyword: #7b8bff;
--shiki-token-parameter: #ff9800;
--shiki-token-function: #445dd7;
--shiki-token-string-expression: #38a35f;
--shiki-token-punctuation: #969696;
--shiki-token-link: #1aa245;
}
.dark body {
--shiki-color-text: #d1d1d1;
--shiki-token-constant: #2dc9c9;
--shiki-token-string: #feb179;
--shiki-token-comment: #6b737c;
--shiki-token-keyword: #7b8bff;
--shiki-token-parameter: #ff9800;
--shiki-token-function: #9babff;
--shiki-token-string-expression: #42bb69;
--shiki-token-punctuation: #bbb;
--shiki-token-link: #ffab70;
}

View File

@@ -10,6 +10,8 @@ import { SpeedInsights } from "@vercel/speed-insights/next";
import { Analytics } from "@vercel/analytics/react";
import { JazzNav } from "@/components/docs/nav";
import { JazzFooter } from "@/components/docs/footer";
import { spaceVariants } from "gcmp-design-system/src/app/components/atoms";
import { cx } from "class-variance-authority";
// If loading a variable font, you don't need to specify the font weight
const manrope = Manrope({
@@ -44,7 +46,7 @@ export default function RootLayout({
manrope.variable,
pragmata.variable,
inter.className,
"flex flex-col items-center bg-stone-50 dark:bg-stone-950 overflow-x-hidden",
"flex flex-col items-center overflow-x-hidden",
].join(" ")}
>
<SpeedInsights />
@@ -56,7 +58,14 @@ export default function RootLayout({
disableTransitionOnChange
>
<JazzNav />
<main className="flex min-h-screen flex-col p-8 max-w-[80rem] w-full [&_*]:scroll-mt-[6rem]">
<main
className={cx(
spaceVariants({
vertical: "major",
}),
"py-d16",
)}
>
{children}
</main>
<JazzFooter />

View File

@@ -136,7 +136,7 @@ export function DocNav() {
</li>
</ul>
<p className="font-medium border-t -mx-4 px-4 pt-4 border-stone-200 dark:border-stone-800">
<p className="px-4 pt-4 -mx-4 font-medium border-t border-stone-200 dark:border-stone-800">
<DocNavLink href="#faq">FAQ</DocNavLink>
</p>
@@ -158,7 +158,7 @@ export async function NavPackage({
return (
<>
<h2 className="text-sm mt-4 flex gap-1 items-center -mx-4 px-4 pt-4 border-t border-stone-200 dark:border-stone-800 ">
<h2 className="flex items-center gap-1 px-4 pt-4 mt-4 -mx-4 text-sm border-t border-background-hover">
<code className="font-bold">{packageName}</code>{" "}
<PackageIcon size={15} strokeWidth={1.5} />
</h2>
@@ -169,7 +169,7 @@ export async function NavPackage({
open={category.title !== "Other"}
className="[&:not([open])_summary]:after:content-['...']"
>
<summary className="block text-xs mt-2 cursor-pointer">
<summary className="block mt-2 text-xs cursor-pointer">
{category.title}
</summary>
<div className="text-sm -ml-0.5 max-w-full text-balance">

View File

@@ -16,7 +16,6 @@
},
"packageManager": "pnpm@9.1.4",
"dependencies": {
"gcmp-design-system": "workspace:*",
"@icons-pack/react-simple-icons": "^9.1.0",
"@mdx-js/loader": "^2.3.0",
"@mdx-js/react": "^2.3.0",
@@ -24,6 +23,8 @@
"@types/mdx": "^2.0.8",
"@vercel/analytics": "^1.3.1",
"@vercel/speed-insights": "^1.0.12",
"class-variance-authority": "^0.7.0",
"gcmp-design-system": "workspace:*",
"lucide-react": "^0.436.0",
"mdast-util-from-markdown": "^2.0.0",
"mdast-util-mdx": "^3.0.0",
@@ -44,6 +45,7 @@
"eslint": "^8",
"eslint-config-next": "13.5.4",
"postcss": "^8",
"postcss-import": "^16.1.0",
"prettier": "^3.2.5",
"tailwindcss": "^3",
"typedoc": "^0.25.13",

View File

@@ -1,5 +1,6 @@
module.exports = {
plugins: {
"postcss-import": {},
tailwindcss: {},
"@csstools/postcss-oklab-function": { preserve: true },
autoprefixer: {},

View File

@@ -0,0 +1,344 @@
pre.shiki {
overflow: hidden;
}
pre.shiki:hover .dim {
opacity: 1;
}
pre.shiki div.dim {
opacity: 0.5;
}
pre.shiki div.dim,
pre.shiki div.highlight {
margin: 0;
padding: 0;
}
pre.shiki div.highlight {
opacity: 1;
background-color: #f1f8ff;
}
pre.shiki div.line {
/* min-height: 1rem; */
counter-increment: lineNumber 1;
}
pre.shiki div.line::before {
content: counter(lineNumber);
display: inline-block;
vertical-align: middle;
width: 1.3rem;
padding-right: 0.3rem;
text-align: right;
transition: color 0.3s;
@apply text-border-light text-[0.65rem];
}
pre.shiki div.line:hover::before {
@apply text-border;
}
/** Don't show the language identifiers */
pre.shiki .language-id {
display: none;
}
/** When you mouse over the pre, show the underlines */
pre.twoslash:hover data-lsp {
@apply border-dotted border-b border-border;
}
/** The tooltip-like which provides the LSP response */
pre.twoslash data-lsp::before {
content: attr(lsp);
position: absolute;
transform: translate(0, 1.2rem);
max-width: 30rem;
@apply text-xs px-1.5 py-1 rounded shadow-lg overflow-hidden whitespace-pre-wrap;
@apply border border-border-light;
@apply text-solid bg-canvas;
text-align: left;
z-index: 100;
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
display: none;
}
pre.twoslash data-lsp:hover::before {
display: block;
opacity: 1;
pointer-events: visible;
width: auto;
height: auto;
}
.shiki-outer {
@apply shadow-sm rounded-xl;
}
.shiki-filename {
@apply px-3 py-2 rounded-t-xl text-xs;
/* @apply bg-background-subtle text-stone-700 dark:text-stone-300; */
@apply bg-background text-solid;
}
pre .code-container {
overflow: scroll;
@apply p-2 pl-0 rounded-b-xl text-[0.8rem] leading-tight;
/* @apply bg-stone-75 dark:bg-stone-925; */
@apply bg-background-subtle;
/* @apply border border-stone-100 dark:border-stone-900; */
@apply border border-background;
}
/* The try button */
pre .code-container > a {
position: absolute;
right: 8px;
bottom: 8px;
border-radius: 4px;
border: 1px solid #719af4;
padding: 0 8px;
color: #719af4;
text-decoration: none;
opacity: 0;
transition-timing-function: ease;
transition: opacity 0.3s;
}
/* Respect no animations */
@media (prefers-reduced-motion: reduce) {
pre .code-container > a {
transition: none;
}
}
pre .code-container > a:hover {
color: white;
background-color: #719af4;
}
pre .code-container:hover a {
opacity: 1;
}
pre code {
white-space: pre;
}
pre code a {
text-decoration: none;
}
pre data-err {
/* Extracted from VS Code */
background: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23c94824'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E")
repeat-x bottom left;
padding-bottom: 3px;
}
pre .query {
margin-bottom: 10px;
color: #137998;
display: inline-block;
}
/* In order to have the 'popped out' style design and to not break the layout
/* we need to place a fake and un-selectable copy of the error which _isn't_ broken out
/* behind the actual error message.
/* This sections keeps both of those two in in sync */
pre .error,
pre .error-behind {
margin-left: -14px;
margin-top: 8px;
margin-bottom: 4px;
padding: 6px;
padding-left: 14px;
width: calc(100% - 20px);
white-space: pre-wrap;
display: block;
}
pre .error {
position: absolute;
background-color: #fee;
border-left: 2px solid #bf1818;
/* Give the space to the error code */
display: flex;
align-items: center;
color: black;
}
pre .error .code {
display: none;
}
pre .error-behind {
user-select: none;
visibility: transparent;
color: #fee;
}
/* Queries */
pre .arrow {
/* Transparent background */
background-color: #eee;
position: relative;
top: -7px;
margin-left: 0.1rem;
/* Edges */
border-left: 1px solid #eee;
border-top: 1px solid #eee;
transform: translateY(25%) rotate(45deg);
/* Size */
height: 8px;
width: 8px;
}
pre .popover {
margin-bottom: 10px;
background-color: #eee;
display: inline-block;
padding: 0 0.5rem 0.3rem;
margin-top: 10px;
border-radius: 3px;
}
/* Completion */
pre .inline-completions ul.dropdown {
display: inline-block;
position: absolute;
width: 240px;
background-color: gainsboro;
color: grey;
padding-top: 4px;
font-family: var(--code-font);
font-size: 0.8rem;
margin: 0;
padding: 0;
border-left: 4px solid #4b9edd;
}
pre .inline-completions ul.dropdown::before {
background-color: #4b9edd;
width: 2px;
position: absolute;
top: -1.2rem;
left: -3px;
content: " ";
}
pre .inline-completions ul.dropdown li {
overflow-x: hidden;
padding-left: 4px;
margin-bottom: 4px;
}
pre .inline-completions ul.dropdown li.deprecated {
text-decoration: line-through;
}
pre .inline-completions ul.dropdown li span.result-found {
color: #4b9edd;
}
pre .inline-completions ul.dropdown li span.result {
width: 100px;
color: black;
display: inline-block;
}
.dark-theme .markdown pre {
background-color: #d8d8d8;
border-color: #ddd;
filter: invert(98%) hue-rotate(180deg);
}
data-lsp {
/* Ensures there's no 1px jump when the hover happens */
border-bottom: 1px dotted transparent;
/* Fades in unobtrusively */
transition-timing-function: ease;
transition: border-color 0.3s;
}
/* Respect people's wishes to not have animations */
@media (prefers-reduced-motion: reduce) {
data-lsp {
transition: none;
}
}
/** Annotations support, providing a tool for meta commentary */
.tag-container {
position: relative;
}
.tag-container .twoslash-annotation {
position: absolute;
font-family:
"JetBrains Mono",
Menlo,
Monaco,
Consolas,
Courier New,
monospace;
right: -10px;
/** Default annotation text to 200px */
width: 200px;
color: #187abf;
background-color: #fcf3d9 bb;
}
.tag-container .twoslash-annotation p {
text-align: left;
font-size: 0.8rem;
line-height: 0.9rem;
}
.tag-container .twoslash-annotation svg {
float: left;
margin-left: -44px;
}
.tag-container .twoslash-annotation.left {
right: auto;
left: -200px;
}
.tag-container .twoslash-annotation.left svg {
float: right;
margin-right: -5px;
}
/** Support for showing console log/warn/errors inline */
pre .logger {
display: flex;
align-items: center;
color: black;
padding: 6px;
padding-left: 8px;
width: calc(100% - 19px);
white-space: pre-wrap;
}
pre .logger svg {
margin-right: 9px;
}
pre .logger.error-log {
background-color: #fee;
border-left: 2px solid #bf1818;
}
pre .logger.warn-log {
background-color: #ffe;
border-left: 2px solid #eae662;
}
pre .logger.log-log {
background-color: #e9e9e9;
border-left: 2px solid #ababab;
}
pre .logger.log-log svg {
margin-left: 6px;
margin-right: 9px;
}
body {
--shiki-color-text: #606060;
--shiki-color-background: transparent;
--shiki-token-constant: #00a5a5;
--shiki-token-string: #4e3a2c;
--shiki-token-comment: #aaa;
--shiki-token-keyword: #7b8bff;
--shiki-token-parameter: #ff9800;
--shiki-token-function: #445dd7;
--shiki-token-string-expression: #38a35f;
--shiki-token-punctuation: #969696;
--shiki-token-link: #1aa245;
}
.dark body {
--shiki-color-text: #d1d1d1;
--shiki-token-constant: #2dc9c9;
--shiki-token-string: #feb179;
--shiki-token-comment: #6b737c;
--shiki-token-keyword: #7b8bff;
--shiki-token-parameter: #ff9800;
--shiki-token-function: #9babff;
--shiki-token-string-expression: #42bb69;
--shiki-token-punctuation: #bbb;
--shiki-token-link: #ffab70;
}

View File

@@ -10,5 +10,8 @@ const config: Config = {
"./app/**/*.{js,ts,jsx,tsx,mdx}",
"./node_modules/gcmp-design-system/src/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {},
},
};
export default config;

View File

@@ -60,6 +60,9 @@ importers:
postcss:
specifier: ^8
version: 8.4.38
postcss-import:
specifier: ^16.1.0
version: 16.1.0(postcss@8.4.38)
tailwindcss:
specifier: ^3.4.1
version: 3.4.3
@@ -148,6 +151,9 @@ importers:
postcss:
specifier: ^8
version: 8.4.38
postcss-import:
specifier: ^16.1.0
version: 16.1.0(postcss@8.4.38)
prettier:
specifier: ^3.2.5
version: 3.2.5
@@ -241,6 +247,7 @@ packages:
'@humanwhocodes/config-array@0.11.14':
resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
engines: {node: '>=10.10.0'}
deprecated: Use @eslint/config-array instead
'@humanwhocodes/module-importer@1.0.1':
resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
@@ -248,6 +255,7 @@ packages:
'@humanwhocodes/object-schema@2.0.3':
resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
deprecated: Use @eslint/object-schema instead
'@icons-pack/react-simple-icons@9.4.1':
resolution: {integrity: sha512-oDX8iE/AOyRIY0ys56+eybKSsyZODHQIPZ5mAGVxx3TszkA5l8lIxKl8HI9F801Y1CJxcySBjIk1XibrnFF0Hw==}
@@ -871,7 +879,7 @@ packages:
engines: {node: '>= 6'}
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
cross-spawn@7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
@@ -1268,9 +1276,11 @@ packages:
glob@7.1.7:
resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==}
deprecated: Glob versions prior to v9 are no longer supported
glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported
globals@13.24.0:
resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
@@ -1339,6 +1349,7 @@ packages:
inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
@@ -2056,6 +2067,12 @@ packages:
peerDependencies:
postcss: ^8.0.0
postcss-import@16.1.0:
resolution: {integrity: sha512-7hsAZ4xGXl4MW+OKEWCnF6T5jqBw80/EE9aXg1r2yyn1RsVEU8EtKXbijEODa+rg7iih4bKf7vlvTGYR4CnPNg==}
engines: {node: '>=18.0.0'}
peerDependencies:
postcss: ^8.0.0
postcss-js@4.0.1:
resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
engines: {node: ^12 || ^14 || >= 16}
@@ -2184,6 +2201,7 @@ packages:
rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true
run-parallel@1.2.0:
@@ -3554,7 +3572,7 @@ snapshots:
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0)
eslint-plugin-react: 7.34.1(eslint@8.57.0)
eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0)
@@ -3572,7 +3590,7 @@ snapshots:
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0)
eslint-plugin-react: 7.34.1(eslint@8.57.0)
eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0)
@@ -3596,7 +3614,7 @@ snapshots:
enhanced-resolve: 5.16.1
eslint: 8.57.0
eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
fast-glob: 3.3.2
get-tsconfig: 4.7.4
is-core-module: 2.13.1
@@ -3618,7 +3636,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0):
eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0):
dependencies:
array-includes: 3.1.8
array.prototype.findlastindex: 1.2.5
@@ -5082,6 +5100,13 @@ snapshots:
read-cache: 1.0.0
resolve: 1.22.8
postcss-import@16.1.0(postcss@8.4.38):
dependencies:
postcss: 8.4.38
postcss-value-parser: 4.2.0
read-cache: 1.0.0
resolve: 1.22.8
postcss-js@4.0.1(postcss@8.4.38):
dependencies:
camelcase-css: 2.0.1