@hraness/design-kit 0.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARTICLE_COPY.md +208 -0
- package/HERO_FIELDS.md +55 -0
- package/ICONS.md +56 -0
- package/LANTERN_MATERIAL.md +60 -0
- package/LICENSE +21 -0
- package/MARKETING_COPY.md +49 -0
- package/MARKETING_PRESET.md +108 -0
- package/PALETTES.md +90 -0
- package/PAPER_THEME.md +128 -0
- package/README.md +745 -0
- package/STATUS_PAGES.md +67 -0
- package/STYLE.md +245 -0
- package/WRITING.md +72 -0
- package/dist/browser/index.js +2345 -0
- package/dist/chunk-44djxk16.js +6872 -0
- package/dist/chunk-5gtx3pza.js +9 -0
- package/dist/chunk-77391vmq.js +454 -0
- package/dist/chunk-7b1586eb.js +1209 -0
- package/dist/chunk-8834fh4n.js +6 -0
- package/dist/chunk-9t8xyqte.js +870 -0
- package/dist/chunk-cejpzyfh.js +446 -0
- package/dist/chunk-eh71jz57.js +429 -0
- package/dist/chunk-evb02bc1.js +516 -0
- package/dist/chunk-h4k7yv6x.js +368 -0
- package/dist/chunk-he8eznb1.js +760 -0
- package/dist/chunk-mr1vdcjq.js +404 -0
- package/dist/chunk-wzvdn8ey.js +116 -0
- package/dist/fonts/nebula-sans/social-fonts.generated.js +53 -0
- package/dist/icons.js +48 -0
- package/dist/index.js +237 -0
- package/dist/launch.js +41 -0
- package/dist/mockups/client.js +422 -0
- package/dist/mockups/index.js +1850 -0
- package/dist/portfolio.js +1549 -0
- package/dist/provider-marks.js +19 -0
- package/dist/react/charts.js +11 -0
- package/dist/react/hero-backdrop.js +8 -0
- package/dist/react/index.js +7252 -0
- package/dist/react/platform-install.js +10 -0
- package/dist/react/server.js +137 -0
- package/dist/stylex-manifest.json +1 -0
- package/dist/stylex.css +5392 -0
- package/dist/syntax-highlighting.js +15 -0
- package/dist/testing.js +250 -0
- package/package.json +377 -0
- package/portfolio-inventory.json +31 -0
- package/scripts/check-lantern-material-snapshot.d.mts +26 -0
- package/scripts/check-lantern-material-snapshot.mjs +126 -0
- package/scripts/check-marketing-snapshot.d.mts +12 -0
- package/scripts/check-marketing-snapshot.mjs +58 -0
- package/scripts/lantern-material-snapshot.ts +101 -0
- package/scripts/marketing-textures.ts +48 -0
- package/scripts/paper-theme-snapshot.ts +97 -0
- package/scripts/product-marketing-snapshot.ts +149 -0
- package/src/appearance-menu.css +266 -0
- package/src/appearance.ts +32 -0
- package/src/article-html.ts +269 -0
- package/src/article.ts +686 -0
- package/src/browser/appearance-menu.ts +604 -0
- package/src/browser/artifact-share.ts +164 -0
- package/src/browser/design-palette.ts +197 -0
- package/src/browser/foil.ts +124 -0
- package/src/browser/hero-light.ts +11 -0
- package/src/browser/index.ts +29 -0
- package/src/browser/status-field.ts +432 -0
- package/src/browser/status-page.ts +100 -0
- package/src/browser/sticky-offset.ts +82 -0
- package/src/browser/theme-color-sync.ts +213 -0
- package/src/charts.css +7 -0
- package/src/compiler-components.css +34 -0
- package/src/compiler-foundation.css +18 -0
- package/src/compiler-palettes.css +7 -0
- package/src/compiler-tokens.css +342 -0
- package/src/components.css +3 -0
- package/src/design-gallery.css +431 -0
- package/src/effects.css +14 -0
- package/src/fonts/geist-mono/GeistMono[wght].woff2 +0 -0
- package/src/fonts/geist-mono/OFL.txt +93 -0
- package/src/fonts/geist-mono/PROVENANCE.md +12 -0
- package/src/fonts/instrument-serif/OFL.txt +93 -0
- package/src/fonts/instrument-serif/UPSTREAM.md +14 -0
- package/src/fonts/instrument-serif/instrument-serif-latin-400.woff2 +0 -0
- package/src/fonts/nebula-sans/LICENSE.txt +96 -0
- package/src/fonts/nebula-sans/NebulaSans-Black.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-BlackItalic.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-Bold.otf +0 -0
- package/src/fonts/nebula-sans/NebulaSans-Bold.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-BoldItalic.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-Book.otf +0 -0
- package/src/fonts/nebula-sans/NebulaSans-Book.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-BookItalic.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-Light.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-LightItalic.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-Medium.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-MediumItalic.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-Semibold.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-SemiboldItalic.woff2 +0 -0
- package/src/fonts/nebula-sans/PROVENANCE.md +14 -0
- package/src/fonts/nebula-sans/social-fonts.generated.ts +3873 -0
- package/src/fonts.css +106 -0
- package/src/icons/act60/act60.svg +5 -0
- package/src/icons/act60/application.svg +9 -0
- package/src/icons/act60/chapter-compare.svg +3 -0
- package/src/icons/act60/decree-residence.svg +6 -0
- package/src/icons/act60/estimate.svg +7 -0
- package/src/icons/act60/export-services.svg +4 -0
- package/src/icons/act60/investor.svg +13 -0
- package/src/icons/act60/presence.svg +7 -0
- package/src/icons/aicharts/aicharts.svg +6 -0
- package/src/icons/aicharts/cost-compare.svg +4 -0
- package/src/icons/aicharts/task-audio.svg +7 -0
- package/src/icons/aicharts/task-coding.svg +6 -0
- package/src/icons/aicharts/task-images.svg +3 -0
- package/src/icons/aicharts/task-reasoning.svg +9 -0
- package/src/icons/aicharts/task-research.svg +5 -0
- package/src/icons/aicharts/task-video.svg +4 -0
- package/src/icons/manifest.json +1371 -0
- package/src/icons/platonik/conversation.svg +3 -0
- package/src/icons/platonik/creature.svg +7 -0
- package/src/icons/platonik/economy.svg +4 -0
- package/src/icons/platonik/keep-light.svg +6 -0
- package/src/icons/platonik/platonik.svg +7 -0
- package/src/icons/platonik/spark-route.svg +15 -0
- package/src/icons/receipts/act60-retry.receipt.json +888 -0
- package/src/icons/receipts/act60.receipt.json +1366 -0
- package/src/icons/receipts/aicharts.receipt.json +1546 -0
- package/src/icons/receipts/platonik.receipt.json +1011 -0
- package/src/icons/receipts/roughday.receipt.json +770 -0
- package/src/icons/receipts/shared.receipt.json +1296 -0
- package/src/icons/receipts/slopcamera.receipt.json +1495 -0
- package/src/icons/receipts/soundfish-retry.receipt.json +460 -0
- package/src/icons/receipts/soundfish.receipt.json +1709 -0
- package/src/icons/receipts/sponge.receipt.json +1743 -0
- package/src/icons/receipts/stripe-history-retry.receipt.json +145 -0
- package/src/icons/receipts/stripe-history.receipt.json +1202 -0
- package/src/icons/receipts/wordcell.receipt.json +1924 -0
- package/src/icons/roughday/finance.svg +7 -0
- package/src/icons/roughday/roughday.svg +6 -0
- package/src/icons/roughday/technology.svg +4 -0
- package/src/icons/roughday/world.svg +4 -0
- package/src/icons/sets/act60.json +63 -0
- package/src/icons/sets/aicharts.json +63 -0
- package/src/icons/sets/platonik.json +39 -0
- package/src/icons/sets/roughday.json +25 -0
- package/src/icons/sets/shared.json +12 -0
- package/src/icons/sets/slopcamera.json +47 -0
- package/src/icons/sets/soundfish.json +43 -0
- package/src/icons/sets/sponge.json +51 -0
- package/src/icons/sets/stripe-history.json +39 -0
- package/src/icons/sets/wordcell.json +51 -0
- package/src/icons/shared/agent-skill.svg +4 -0
- package/src/icons/shared/cli.svg +5 -0
- package/src/icons/shared/privacy.svg +3 -0
- package/src/icons/shared/research.svg +7 -0
- package/src/icons/shared/sdk.svg +3 -0
- package/src/icons/slopcamera/diagram.svg +3 -0
- package/src/icons/slopcamera/direct-scene.svg +5 -0
- package/src/icons/slopcamera/edit-video.svg +17 -0
- package/src/icons/slopcamera/mcp.svg +3 -0
- package/src/icons/slopcamera/native-world.svg +3 -0
- package/src/icons/slopcamera/slopcamera.svg +11 -0
- package/src/icons/soundfish/agent-ui.svg +7 -0
- package/src/icons/soundfish/collaborate.svg +5 -0
- package/src/icons/soundfish/compose.svg +3 -0
- package/src/icons/soundfish/hear.svg +6 -0
- package/src/icons/soundfish/human-ui.svg +6 -0
- package/src/icons/soundfish/share.svg +3 -0
- package/src/icons/soundfish/soundfish.svg +6 -0
- package/src/icons/sponge/api.svg +3 -0
- package/src/icons/sponge/documents.svg +3 -0
- package/src/icons/sponge/library.svg +3 -0
- package/src/icons/sponge/one-question.svg +5 -0
- package/src/icons/sponge/people-direct.svg +5 -0
- package/src/icons/sponge/read.svg +3 -0
- package/src/icons/sponge/save.svg +4 -0
- package/src/icons/sponge/sponge.svg +7 -0
- package/src/icons/stripe-history/company-history.svg +3 -0
- package/src/icons/stripe-history/evidence.svg +4 -0
- package/src/icons/stripe-history/independence.svg +7 -0
- package/src/icons/stripe-history/publications.svg +11 -0
- package/src/icons/stripe-history/sources.svg +6 -0
- package/src/icons/stripe-history/stripe-history.svg +3 -0
- package/src/icons/wordcell/backlinks.svg +6 -0
- package/src/icons/wordcell/capture.svg +6 -0
- package/src/icons/wordcell/git-provenance.svg +4 -0
- package/src/icons/wordcell/kb.svg +4 -0
- package/src/icons/wordcell/markdown.svg +4 -0
- package/src/icons/wordcell/scopes.svg +3 -0
- package/src/icons/wordcell/search.svg +7 -0
- package/src/icons.generated.ts +734 -0
- package/src/icons.ts +51 -0
- package/src/index.ts +275 -0
- package/src/lantern-material.css +213 -0
- package/src/launch.ts +624 -0
- package/src/marketing-assets/UPSTREAM.md +18 -0
- package/src/marketing-assets/cells.svg +1 -0
- package/src/marketing-assets/grain.svg +1 -0
- package/src/marketing-forced-colors.css +12 -0
- package/src/mockups/client.tsx +415 -0
- package/src/mockups/core.tsx +318 -0
- package/src/mockups/frames.tsx +368 -0
- package/src/mockups/index.ts +14 -0
- package/src/mockups/surfaces.tsx +681 -0
- package/src/mockups.css +2607 -0
- package/src/palette-appearance.ts +45 -0
- package/src/palette-bridge.css +124 -0
- package/src/palette-color.ts +41 -0
- package/src/palette-system.css +721 -0
- package/src/palette-themes.ts +23 -0
- package/src/palette-tokens.stylex.ts +519 -0
- package/src/palettes.css +3 -0
- package/src/palettes.ts +161 -0
- package/src/paper-theme.css +244 -0
- package/src/plain-publication.css +1241 -0
- package/src/plain-site.css +397 -0
- package/src/platforms.ts +151 -0
- package/src/portfolio.generated.json +1595 -0
- package/src/portfolio.generated.ts +1596 -0
- package/src/portfolio.ts +226 -0
- package/src/product-marketing-foundation.css +433 -0
- package/src/product-marketing-preset.css +261 -0
- package/src/product-marketing.css +2186 -0
- package/src/provider-marks.generated.ts +112 -0
- package/src/provider-marks.ts +143 -0
- package/src/react/animated-rail-stage.stylex.ts +15 -0
- package/src/react/animated-rail-stage.tsx +51 -0
- package/src/react/app-shell.stylex.ts +104 -0
- package/src/react/app-shell.tsx +121 -0
- package/src/react/article.tsx +602 -0
- package/src/react/aurora-dots-background.tsx +34 -0
- package/src/react/charts.stylex.ts +563 -0
- package/src/react/charts.tsx +610 -0
- package/src/react/chat.stylex.ts +34 -0
- package/src/react/chat.tsx +155 -0
- package/src/react/design-gallery.tsx +943 -0
- package/src/react/design-palette.stylex.ts +124 -0
- package/src/react/design-palette.tsx +196 -0
- package/src/react/design-theme-context.tsx +41 -0
- package/src/react/effects.stylex.ts +325 -0
- package/src/react/fader.stylex.ts +71 -0
- package/src/react/fader.tsx +151 -0
- package/src/react/foil-card-math.ts +100 -0
- package/src/react/foil-card-surface.stylex.ts +326 -0
- package/src/react/foil-card-surface.tsx +742 -0
- package/src/react/foil-mark.tsx +35 -0
- package/src/react/foil.stylex.ts +163 -0
- package/src/react/haptics.ts +228 -0
- package/src/react/hero-backdrop.tsx +22 -0
- package/src/react/index.ts +38 -0
- package/src/react/keyboard-shortcuts.ts +228 -0
- package/src/react/lantern-material-gallery.tsx +166 -0
- package/src/react/lantern-material.stylex.ts +39 -0
- package/src/react/launch-beats.tsx +73 -0
- package/src/react/navigation-rail.stylex.ts +130 -0
- package/src/react/navigation-rail.tsx +228 -0
- package/src/react/particle-halo.tsx +115 -0
- package/src/react/phaser-dots.tsx +501 -0
- package/src/react/platform-icons.tsx +94 -0
- package/src/react/platform-install.stylex.ts +385 -0
- package/src/react/platform-install.tsx +389 -0
- package/src/react/playback-transport.stylex.ts +14 -0
- package/src/react/playback-transport.tsx +112 -0
- package/src/react/procedural-backdrop.tsx +192 -0
- package/src/react/procedural-recipe.ts +323 -0
- package/src/react/product-marketing.stylex.ts +4469 -0
- package/src/react/product-marketing.tsx +1611 -0
- package/src/react/production-data-preview-notice.stylex.ts +40 -0
- package/src/react/production-data-preview-notice.tsx +34 -0
- package/src/react/provider-mark.stylex.ts +132 -0
- package/src/react/provider-mark.tsx +120 -0
- package/src/react/relative-time.tsx +117 -0
- package/src/react/route-state.stylex.ts +39 -0
- package/src/react/route-state.tsx +350 -0
- package/src/react/server.ts +11 -0
- package/src/react/social-kit-panel.tsx +103 -0
- package/src/react/sticky-offset.tsx +33 -0
- package/src/react/surfaces.stylex.ts +179 -0
- package/src/react/surfaces.tsx +330 -0
- package/src/react/syntax-code.tsx +33 -0
- package/src/react/theme-color-sync.ts +1 -0
- package/src/react/theme-resolution.ts +11 -0
- package/src/react/theme.stylex.ts +276 -0
- package/src/react/theme.tsx +402 -0
- package/src/reading.css +72 -0
- package/src/relative-time.ts +185 -0
- package/src/reset.css +2 -0
- package/src/site-shell.css +16 -0
- package/src/status-page-html.ts +63 -0
- package/src/status-page.css +276 -0
- package/src/status-page.ts +323 -0
- package/src/styles.css +21 -0
- package/src/syntax-code-lexers.ts +303 -0
- package/src/syntax-highlighting.css +78 -0
- package/src/syntax-highlighting.ts +477 -0
- package/src/syntax-tokens.ts +33 -0
- package/src/testing.ts +307 -0
- package/src/tokens.css +3 -0
- package/src/typography.css +86 -0
- package/vendor/evilcharts/LICENSE +21 -0
- package/vendor/evilcharts/UPSTREAM.md +14 -0
- package/vendor/platform-marks/LICENSE +30 -0
- package/vendor/platform-marks/UPSTREAM.md +15 -0
- package/vendor/platform-marks/apple.svg +1 -0
- package/vendor/platform-marks/linux.svg +1 -0
- package/vendor/provider-marks/CRUSH-LICENSE.md +134 -0
- package/vendor/provider-marks/LICENSE +21 -0
- package/vendor/provider-marks/UPSTREAM.md +27 -0
- package/vendor/provider-marks/aider.svg +3 -0
- package/vendor/provider-marks/crush-heartbit.svg +8 -0
- package/vendor/provider-marks/lobehub/alibabacloud-color.svg +1 -0
- package/vendor/provider-marks/lobehub/alibabacloud.svg +1 -0
- package/vendor/provider-marks/lobehub/amp-color.svg +1 -0
- package/vendor/provider-marks/lobehub/amp.svg +1 -0
- package/vendor/provider-marks/lobehub/anthropic.svg +1 -0
- package/vendor/provider-marks/lobehub/claude-color.svg +1 -0
- package/vendor/provider-marks/lobehub/claude.svg +1 -0
- package/vendor/provider-marks/lobehub/claudecode-color.svg +1 -0
- package/vendor/provider-marks/lobehub/claudecode.svg +1 -0
- package/vendor/provider-marks/lobehub/codex-color.svg +1 -0
- package/vendor/provider-marks/lobehub/codex.svg +1 -0
- package/vendor/provider-marks/lobehub/cursor.svg +1 -0
- package/vendor/provider-marks/lobehub/deepseek-color.svg +1 -0
- package/vendor/provider-marks/lobehub/deepseek.svg +1 -0
- package/vendor/provider-marks/lobehub/devin-color.svg +1 -0
- package/vendor/provider-marks/lobehub/devin.svg +1 -0
- package/vendor/provider-marks/lobehub/gemini-color.svg +1 -0
- package/vendor/provider-marks/lobehub/gemini.svg +1 -0
- package/vendor/provider-marks/lobehub/geminicli-color.svg +1 -0
- package/vendor/provider-marks/lobehub/geminicli.svg +1 -0
- package/vendor/provider-marks/lobehub/goose.svg +1 -0
- package/vendor/provider-marks/lobehub/meta-color.svg +1 -0
- package/vendor/provider-marks/lobehub/meta.svg +1 -0
- package/vendor/provider-marks/lobehub/mistral-color.svg +1 -0
- package/vendor/provider-marks/lobehub/mistral.svg +1 -0
- package/vendor/provider-marks/lobehub/moonshot.svg +1 -0
- package/vendor/provider-marks/lobehub/nvidia-color.svg +1 -0
- package/vendor/provider-marks/lobehub/nvidia.svg +1 -0
- package/vendor/provider-marks/lobehub/openai.svg +1 -0
- package/vendor/provider-marks/lobehub/opencode.svg +1 -0
- package/vendor/provider-marks/lobehub/perplexity-color.svg +1 -0
- package/vendor/provider-marks/lobehub/perplexity.svg +1 -0
- package/vendor/provider-marks/lobehub/qwen-color.svg +1 -0
- package/vendor/provider-marks/lobehub/qwen.svg +1 -0
- package/vendor/provider-marks/lobehub/xai.svg +1 -0
- package/vendor/provider-marks/lobehub/zai.svg +1 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Skeleton,
|
|
5
|
+
Spinner,
|
|
6
|
+
cn,
|
|
7
|
+
type ContentHeadingLevel,
|
|
8
|
+
} from "@hraness/ui";
|
|
9
|
+
import * as stylex from "@stylexjs/stylex";
|
|
10
|
+
import { useEffect, useId, useRef, type ReactNode } from "react";
|
|
11
|
+
|
|
12
|
+
import { attachStatusPage } from "../browser/status-page.js";
|
|
13
|
+
import { colors } from "../index.js";
|
|
14
|
+
import {
|
|
15
|
+
STATUS_PAGE_AGENT_PREFIX,
|
|
16
|
+
STATUS_PAGE_BACK_LABEL,
|
|
17
|
+
STATUS_PAGE_HINT_PREFIX,
|
|
18
|
+
STATUS_PAGE_NEXT_HEADING_ID,
|
|
19
|
+
resolveStatusPage,
|
|
20
|
+
statusPageRoutesAttribute,
|
|
21
|
+
type StatusPageContent,
|
|
22
|
+
} from "../status-page.js";
|
|
23
|
+
import { PageCanvas } from "./surfaces.js";
|
|
24
|
+
import { routeStateStyles } from "./route-state.stylex.js";
|
|
25
|
+
import {
|
|
26
|
+
defaultDesignTheme,
|
|
27
|
+
DesignThemeProvider,
|
|
28
|
+
type DesignTheme,
|
|
29
|
+
ThemeColorSync,
|
|
30
|
+
ThemeMenuButton,
|
|
31
|
+
} from "./theme.js";
|
|
32
|
+
|
|
33
|
+
type StatusHeadingLevel = Exclude<ContentHeadingLevel, "h6">;
|
|
34
|
+
|
|
35
|
+
export interface StatusPageProps extends StatusPageContent {
|
|
36
|
+
readonly canvasAs?: "div" | "main";
|
|
37
|
+
/** Adds a standalone header menu; product layouts should normally own it. */
|
|
38
|
+
readonly showThemeToggle?: boolean;
|
|
39
|
+
readonly titleAs?: StatusHeadingLevel;
|
|
40
|
+
/** Error pages only: renders Try again as the primary action. */
|
|
41
|
+
readonly onRetry?: () => void;
|
|
42
|
+
/** Error pages only: moves focus to the page and announces it. */
|
|
43
|
+
readonly announce?: boolean;
|
|
44
|
+
readonly autoFocus?: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const lowerHeading: Readonly<Record<StatusHeadingLevel, ContentHeadingLevel>> = {
|
|
48
|
+
h1: "h2", h2: "h3", h3: "h4", h4: "h5", h5: "h6",
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Shared full-page status composition: the 404 page and recoverable errors.
|
|
53
|
+
* Markup matches `renderStatusPageHtml`, styled by `status-page.css`; the
|
|
54
|
+
* browser enhancement adds the dot field, the closest-page hint, and Back.
|
|
55
|
+
*/
|
|
56
|
+
export function StatusPage({
|
|
57
|
+
announce = true,
|
|
58
|
+
autoFocus = true,
|
|
59
|
+
canvasAs = "main",
|
|
60
|
+
onRetry,
|
|
61
|
+
showThemeToggle = false,
|
|
62
|
+
titleAs = "h1",
|
|
63
|
+
...content
|
|
64
|
+
}: StatusPageProps) {
|
|
65
|
+
const page = resolveStatusPage(content);
|
|
66
|
+
const rootRef = useRef<HTMLElement>(null);
|
|
67
|
+
const focusId = `${useId()}-status`;
|
|
68
|
+
const error = page.kind === "error";
|
|
69
|
+
const notFound = page.kind === "not-found";
|
|
70
|
+
const routes = notFound ? statusPageRoutesAttribute(page.routes) : undefined;
|
|
71
|
+
const Root = canvasAs;
|
|
72
|
+
const Title = titleAs;
|
|
73
|
+
const NextHeading = lowerHeading[titleAs];
|
|
74
|
+
const headerPresentation = stylex.props(routeStateStyles.header);
|
|
75
|
+
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
const root = rootRef.current;
|
|
78
|
+
if (!root) return;
|
|
79
|
+
return attachStatusPage(root);
|
|
80
|
+
}, [routes]);
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (error && autoFocus) rootRef.current?.focus();
|
|
83
|
+
}, [autoFocus, error]);
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<Root
|
|
87
|
+
aria-label={error ? page.title : undefined}
|
|
88
|
+
aria-live={error && announce ? "assertive" : undefined}
|
|
89
|
+
className="hraness-status-page"
|
|
90
|
+
data-hraness-status-routes={routes}
|
|
91
|
+
data-kind={page.kind}
|
|
92
|
+
id={error ? focusId : undefined}
|
|
93
|
+
ref={rootRef as never}
|
|
94
|
+
tabIndex={error ? -1 : undefined}
|
|
95
|
+
>
|
|
96
|
+
{showThemeToggle ? (
|
|
97
|
+
<header
|
|
98
|
+
{...headerPresentation}
|
|
99
|
+
className={cn("hraness-design-route-state__header", headerPresentation.className)}
|
|
100
|
+
>
|
|
101
|
+
<ThemeMenuButton />
|
|
102
|
+
</header>
|
|
103
|
+
) : null}
|
|
104
|
+
<div className="hraness-status-page__inner">
|
|
105
|
+
<div aria-hidden="true" className="hraness-status-page__code">
|
|
106
|
+
<span className="hraness-status-page__glyph">{page.glyph}</span>
|
|
107
|
+
<canvas className="hraness-status-page__field" />
|
|
108
|
+
</div>
|
|
109
|
+
<Title className="hraness-status-page__title">{page.title}</Title>
|
|
110
|
+
<p className="hraness-status-page__summary">{page.summary}</p>
|
|
111
|
+
{notFound ? (
|
|
112
|
+
<p className="hraness-status-page__hint" hidden>
|
|
113
|
+
{STATUS_PAGE_HINT_PREFIX} <a className="hraness-status-page__hint-link" href="/" />?
|
|
114
|
+
</p>
|
|
115
|
+
) : null}
|
|
116
|
+
<div className="hraness-status-page__actions">
|
|
117
|
+
{onRetry ? (
|
|
118
|
+
<>
|
|
119
|
+
<button
|
|
120
|
+
className="hraness-status-page__action hraness-foil"
|
|
121
|
+
data-emphasis="primary"
|
|
122
|
+
data-foil=""
|
|
123
|
+
onClick={onRetry}
|
|
124
|
+
type="button"
|
|
125
|
+
>
|
|
126
|
+
Try again
|
|
127
|
+
</button>
|
|
128
|
+
<a className="hraness-status-page__action" href={page.primaryAction.href}>
|
|
129
|
+
{page.primaryAction.label}
|
|
130
|
+
</a>
|
|
131
|
+
</>
|
|
132
|
+
) : (
|
|
133
|
+
<a
|
|
134
|
+
className="hraness-status-page__action hraness-foil"
|
|
135
|
+
data-emphasis="primary"
|
|
136
|
+
data-foil=""
|
|
137
|
+
href={page.primaryAction.href}
|
|
138
|
+
>
|
|
139
|
+
{page.primaryAction.label}
|
|
140
|
+
</a>
|
|
141
|
+
)}
|
|
142
|
+
<a className="hraness-status-page__back" hidden href="/">{STATUS_PAGE_BACK_LABEL}</a>
|
|
143
|
+
</div>
|
|
144
|
+
{page.next.length === 0 ? null : (
|
|
145
|
+
<nav aria-labelledby={STATUS_PAGE_NEXT_HEADING_ID} className="hraness-status-page__next">
|
|
146
|
+
<NextHeading className="hraness-status-page__next-heading" id={STATUS_PAGE_NEXT_HEADING_ID}>
|
|
147
|
+
{page.nextHeading}
|
|
148
|
+
</NextHeading>
|
|
149
|
+
<ul className="hraness-status-page__next-list">
|
|
150
|
+
{page.next.map((link, index) => (
|
|
151
|
+
<li key={`${String(index)}:${link.href}`}>
|
|
152
|
+
<a className="hraness-status-page__next-link" href={link.href}>
|
|
153
|
+
<span className="hraness-status-page__next-label">{link.label}</span>
|
|
154
|
+
{link.description === undefined ? null : (
|
|
155
|
+
<span className="hraness-status-page__next-description">{link.description}</span>
|
|
156
|
+
)}
|
|
157
|
+
</a>
|
|
158
|
+
</li>
|
|
159
|
+
))}
|
|
160
|
+
</ul>
|
|
161
|
+
</nav>
|
|
162
|
+
)}
|
|
163
|
+
{page.agentIndexHref === undefined ? null : (
|
|
164
|
+
<p className="hraness-status-page__agent">
|
|
165
|
+
{STATUS_PAGE_AGENT_PREFIX} <a href={page.agentIndexHref}>{page.agentIndexHref}</a>
|
|
166
|
+
</p>
|
|
167
|
+
)}
|
|
168
|
+
</div>
|
|
169
|
+
</Root>
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export interface RouteErrorPageProps {
|
|
174
|
+
/** Set false only for an already-visible, inert demonstration of this state. */
|
|
175
|
+
readonly announce?: boolean;
|
|
176
|
+
/** Disable only when the full-page composition is rendered as an inert preview. */
|
|
177
|
+
readonly autoFocus?: boolean;
|
|
178
|
+
readonly canvasAs?: "div" | "main";
|
|
179
|
+
readonly error: Error & { readonly digest?: string };
|
|
180
|
+
readonly reset: () => void;
|
|
181
|
+
/** Adds a standalone header menu; product layouts should normally own it. */
|
|
182
|
+
readonly showThemeToggle?: boolean;
|
|
183
|
+
readonly titleAs?: StatusHeadingLevel;
|
|
184
|
+
/** Product name for the home action ("Go to Sponge"). */
|
|
185
|
+
readonly siteName?: string;
|
|
186
|
+
readonly homeHref?: string;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export type RouteNotFoundPageProps = Omit<StatusPageProps, "kind" | "onRetry" | "announce" | "autoFocus">;
|
|
190
|
+
|
|
191
|
+
export interface RouteLoadingPageProps {
|
|
192
|
+
/** Set false only for an already-visible, inert demonstration of this state. */
|
|
193
|
+
readonly announce?: boolean;
|
|
194
|
+
readonly canvasAs?: "div" | "main";
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export interface GlobalErrorDocumentProps extends RouteErrorPageProps {
|
|
198
|
+
readonly bodyClassName?: string;
|
|
199
|
+
/** Browser chrome color used whenever the resolved appearance is Dark. */
|
|
200
|
+
readonly darkColor?: string;
|
|
201
|
+
readonly diagnostics?: ReactNode;
|
|
202
|
+
/** Browser chrome color used whenever the resolved appearance is Light. */
|
|
203
|
+
readonly lightColor?: string;
|
|
204
|
+
/** Defaults to the shared stored preference with a System first-visit choice. */
|
|
205
|
+
readonly theme?: DesignTheme;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** Shared root-segment 404 treatment for Next products. */
|
|
209
|
+
export function RouteNotFoundPage(props: RouteNotFoundPageProps = {}) {
|
|
210
|
+
return <StatusPage {...props} kind="not-found" />;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** Shared recoverable route-error treatment for Next products. */
|
|
214
|
+
export function RouteErrorPage({
|
|
215
|
+
announce = true,
|
|
216
|
+
autoFocus = true,
|
|
217
|
+
canvasAs = "main",
|
|
218
|
+
error,
|
|
219
|
+
homeHref = "/",
|
|
220
|
+
reset,
|
|
221
|
+
showThemeToggle = false,
|
|
222
|
+
siteName,
|
|
223
|
+
titleAs = "h1",
|
|
224
|
+
}: RouteErrorPageProps) {
|
|
225
|
+
return (
|
|
226
|
+
<StatusPage
|
|
227
|
+
announce={announce}
|
|
228
|
+
autoFocus={autoFocus}
|
|
229
|
+
canvasAs={canvasAs}
|
|
230
|
+
key={error.digest ?? error.message}
|
|
231
|
+
kind="error"
|
|
232
|
+
onRetry={reset}
|
|
233
|
+
primaryAction={{ href: homeHref, label: siteName ? `Go to ${siteName}` : "Return home" }}
|
|
234
|
+
showThemeToggle={showThemeToggle}
|
|
235
|
+
titleAs={titleAs}
|
|
236
|
+
/>
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/** Shared root loading treatment for Next products. */
|
|
241
|
+
export function RouteLoadingPage({
|
|
242
|
+
announce = true,
|
|
243
|
+
canvasAs = "main",
|
|
244
|
+
}: RouteLoadingPageProps = {}) {
|
|
245
|
+
const rootPresentation = stylex.props(routeStateStyles.root);
|
|
246
|
+
const loadingPresentation = stylex.props(routeStateStyles.loading);
|
|
247
|
+
const titlePresentation = stylex.props(routeStateStyles.row);
|
|
248
|
+
const skeletonPresentation = stylex.props(routeStateStyles.skeletons);
|
|
249
|
+
|
|
250
|
+
return (
|
|
251
|
+
<PageCanvas
|
|
252
|
+
aria-busy={announce ? "true" : undefined}
|
|
253
|
+
as={canvasAs}
|
|
254
|
+
className={cn(
|
|
255
|
+
"hraness-design-route-state",
|
|
256
|
+
rootPresentation.className,
|
|
257
|
+
)}
|
|
258
|
+
>
|
|
259
|
+
<section
|
|
260
|
+
{...loadingPresentation}
|
|
261
|
+
className={cn(
|
|
262
|
+
"hraness-design-route-state__loading",
|
|
263
|
+
loadingPresentation.className,
|
|
264
|
+
)}
|
|
265
|
+
role={announce ? "status" : undefined}
|
|
266
|
+
>
|
|
267
|
+
<div
|
|
268
|
+
{...titlePresentation}
|
|
269
|
+
className={cn(
|
|
270
|
+
"hraness-design-route-state__loading-title",
|
|
271
|
+
titlePresentation.className,
|
|
272
|
+
)}
|
|
273
|
+
>
|
|
274
|
+
<Spinner />
|
|
275
|
+
<strong>Loading page</strong>
|
|
276
|
+
</div>
|
|
277
|
+
<div
|
|
278
|
+
{...skeletonPresentation}
|
|
279
|
+
aria-hidden="true"
|
|
280
|
+
className={cn(
|
|
281
|
+
"hraness-design-route-state__skeletons",
|
|
282
|
+
skeletonPresentation.className,
|
|
283
|
+
)}
|
|
284
|
+
>
|
|
285
|
+
<Skeleton height="1rem" isText width="88%" />
|
|
286
|
+
<Skeleton height="1rem" isText width="64%" />
|
|
287
|
+
<Skeleton height="8rem" width="100%" />
|
|
288
|
+
</div>
|
|
289
|
+
</section>
|
|
290
|
+
</PageCanvas>
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Last-resort Next boundary. It owns the document because global-error replaces
|
|
296
|
+
* the root layout, including its normal appearance provider.
|
|
297
|
+
*/
|
|
298
|
+
export function GlobalErrorDocument({
|
|
299
|
+
bodyClassName,
|
|
300
|
+
darkColor = colors.dark.background,
|
|
301
|
+
diagnostics,
|
|
302
|
+
lightColor = colors.light.background,
|
|
303
|
+
theme = defaultDesignTheme,
|
|
304
|
+
...props
|
|
305
|
+
}: GlobalErrorDocumentProps) {
|
|
306
|
+
const content = (
|
|
307
|
+
<>
|
|
308
|
+
{diagnostics}
|
|
309
|
+
<RouteErrorPage {...props} showThemeToggle={false} />
|
|
310
|
+
</>
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
return (
|
|
314
|
+
<html data-theme={theme === "system" ? "light" : theme} lang="en" suppressHydrationWarning>
|
|
315
|
+
<head>
|
|
316
|
+
<meta
|
|
317
|
+
content={theme === "system" ? "light dark" : theme}
|
|
318
|
+
name="color-scheme"
|
|
319
|
+
/>
|
|
320
|
+
{theme === "system" ? (
|
|
321
|
+
<>
|
|
322
|
+
<meta
|
|
323
|
+
content={lightColor}
|
|
324
|
+
media="(prefers-color-scheme: light)"
|
|
325
|
+
name="theme-color"
|
|
326
|
+
/>
|
|
327
|
+
<meta
|
|
328
|
+
content={darkColor}
|
|
329
|
+
media="(prefers-color-scheme: dark)"
|
|
330
|
+
name="theme-color"
|
|
331
|
+
/>
|
|
332
|
+
</>
|
|
333
|
+
) : (
|
|
334
|
+
<meta
|
|
335
|
+
content={theme === "dark" ? darkColor : lightColor}
|
|
336
|
+
name="theme-color"
|
|
337
|
+
/>
|
|
338
|
+
)}
|
|
339
|
+
</head>
|
|
340
|
+
<body className={bodyClassName}>
|
|
341
|
+
{theme === "system" ? (
|
|
342
|
+
<DesignThemeProvider>
|
|
343
|
+
<ThemeColorSync darkColor={darkColor} lightColor={lightColor} />
|
|
344
|
+
{content}
|
|
345
|
+
</DesignThemeProvider>
|
|
346
|
+
) : content}
|
|
347
|
+
</body>
|
|
348
|
+
</html>
|
|
349
|
+
);
|
|
350
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from "./article.js";
|
|
2
|
+
export * from "./particle-halo.js";
|
|
3
|
+
export * from "./procedural-backdrop.js";
|
|
4
|
+
export * from "./procedural-recipe.js";
|
|
5
|
+
export * from "./product-marketing.js";
|
|
6
|
+
export * from "./surfaces.js";
|
|
7
|
+
export * from "./syntax-code.js";
|
|
8
|
+
export * from "./foil-mark.js";
|
|
9
|
+
export * from "./provider-mark.js";
|
|
10
|
+
export * from "./platform-icons.js";
|
|
11
|
+
export * from "./launch-beats.js";
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { useCallback, useId, useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
blueskyPostLength,
|
|
4
|
+
characterLength,
|
|
5
|
+
LAUNCH_LIMITS,
|
|
6
|
+
xPostLength,
|
|
7
|
+
type SocialKit,
|
|
8
|
+
} from "../launch.js";
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
* Client component: a closed <details> that lists every post in a social kit
|
|
12
|
+
* with its length against the channel limit and a copy button. It is for the
|
|
13
|
+
* person posting, so products render it only on their own post page, never
|
|
14
|
+
* in the article outline.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
type Entry = Readonly<{ key: string; label: string; text: string; length: number; limit: number }>;
|
|
18
|
+
|
|
19
|
+
function kitEntries(kit: SocialKit): readonly Entry[] {
|
|
20
|
+
const thread = (channel: string, label: string, posts: readonly string[], measure: (text: string) => number, limit: number): Entry[] =>
|
|
21
|
+
posts.map((text, index) => ({ key: `${channel}.${index}`, label: `${label} ${index + 1} of ${posts.length}`, text, length: measure(text), limit }));
|
|
22
|
+
return [
|
|
23
|
+
...thread("x", "X post", kit.x, xPostLength, LAUNCH_LIMITS.x),
|
|
24
|
+
...thread("bluesky", "Bluesky post", kit.bluesky, blueskyPostLength, LAUNCH_LIMITS.bluesky),
|
|
25
|
+
...thread("threads", "Threads post", kit.threads, characterLength, LAUNCH_LIMITS.threads),
|
|
26
|
+
{ key: "linkedin", label: "LinkedIn post", text: kit.linkedin, length: characterLength(kit.linkedin), limit: LAUNCH_LIMITS.linkedin },
|
|
27
|
+
{ key: "productHunt.tagline", label: "Product Hunt tagline", text: kit.productHunt.tagline, length: characterLength(kit.productHunt.tagline), limit: LAUNCH_LIMITS.productHuntTagline },
|
|
28
|
+
{
|
|
29
|
+
key: "productHunt.description",
|
|
30
|
+
label: "Product Hunt description",
|
|
31
|
+
text: kit.productHunt.description,
|
|
32
|
+
length: characterLength(kit.productHunt.description),
|
|
33
|
+
limit: LAUNCH_LIMITS.productHuntDescription,
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function writeClipboard(text: string): Promise<boolean> {
|
|
39
|
+
try {
|
|
40
|
+
await navigator.clipboard.writeText(text);
|
|
41
|
+
return true;
|
|
42
|
+
} catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The social kit for a launch post: each post with a character counter and a
|
|
49
|
+
* copy button, plus the fact sheet for anyone writing their own post.
|
|
50
|
+
* Closed by default.
|
|
51
|
+
*/
|
|
52
|
+
export function SocialKitPanel({
|
|
53
|
+
className,
|
|
54
|
+
kit,
|
|
55
|
+
summary = "Social posts for this launch",
|
|
56
|
+
}: Readonly<{ className?: string; kit: SocialKit; summary?: string }>) {
|
|
57
|
+
const id = useId();
|
|
58
|
+
const [status, setStatus] = useState<Readonly<{ key: string; ok: boolean }> | null>(null);
|
|
59
|
+
const copy = useCallback(async (entry: Entry) => {
|
|
60
|
+
setStatus({ key: entry.key, ok: await writeClipboard(entry.text) });
|
|
61
|
+
}, []);
|
|
62
|
+
const entries = kitEntries(kit);
|
|
63
|
+
return (
|
|
64
|
+
<details className={["plain-publication__social-kit", className].filter(Boolean).join(" ")} data-hraness-social-kit="">
|
|
65
|
+
<summary>{summary}</summary>
|
|
66
|
+
<ol className="plain-publication__social-kit-list">
|
|
67
|
+
{entries.map((entry) => {
|
|
68
|
+
const over = entry.length > entry.limit;
|
|
69
|
+
const counterId = `${id}-${entry.key}-count`;
|
|
70
|
+
return (
|
|
71
|
+
<li className="plain-publication__social-kit-item" data-over={over ? "" : undefined} key={entry.key}>
|
|
72
|
+
<div className="plain-publication__social-kit-head">
|
|
73
|
+
<span className="plain-publication__social-kit-label">{entry.label}</span>
|
|
74
|
+
<span className="plain-publication__social-kit-count" id={counterId}>
|
|
75
|
+
{entry.length} of {entry.limit}
|
|
76
|
+
</span>
|
|
77
|
+
<button
|
|
78
|
+
aria-describedby={counterId}
|
|
79
|
+
className="plain-publication__social-kit-copy"
|
|
80
|
+
onClick={() => void copy(entry)}
|
|
81
|
+
type="button"
|
|
82
|
+
>
|
|
83
|
+
{status?.key === entry.key ? (status.ok ? "Copied" : "Copy failed") : "Copy"}
|
|
84
|
+
<span className="plain-publication__visually-hidden"> {entry.label}</span>
|
|
85
|
+
</button>
|
|
86
|
+
</div>
|
|
87
|
+
<p className="plain-publication__social-kit-text">{entry.text}</p>
|
|
88
|
+
</li>
|
|
89
|
+
);
|
|
90
|
+
})}
|
|
91
|
+
</ol>
|
|
92
|
+
{kit.showHnFacts.length === 0 ? null : (
|
|
93
|
+
<div className="plain-publication__social-kit-facts">
|
|
94
|
+
<p>Facts for your own post</p>
|
|
95
|
+
<ul>{kit.showHnFacts.map((fact) => <li key={fact}>{fact}</li>)}</ul>
|
|
96
|
+
</div>
|
|
97
|
+
)}
|
|
98
|
+
<p aria-live="polite" className="plain-publication__visually-hidden">
|
|
99
|
+
{status === null ? "" : status.ok ? "Copied to the clipboard." : "Copying failed. Select the text and copy it."}
|
|
100
|
+
</p>
|
|
101
|
+
</details>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
measureStickyOffset,
|
|
7
|
+
publishStickyOffset,
|
|
8
|
+
stickyOffsetCustomProperty,
|
|
9
|
+
stickyOffsetHeaderSelector,
|
|
10
|
+
syncStickyOffset,
|
|
11
|
+
} from "../browser/sticky-offset.js";
|
|
12
|
+
|
|
13
|
+
export type { StickyOffsetSyncOptions } from "../browser/sticky-offset.js";
|
|
14
|
+
export {
|
|
15
|
+
measureStickyOffset,
|
|
16
|
+
publishStickyOffset,
|
|
17
|
+
stickyOffsetCustomProperty,
|
|
18
|
+
stickyOffsetHeaderSelector,
|
|
19
|
+
syncStickyOffset,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Measure sticky marketing chrome and publish --hraness-sticky-offset. Render
|
|
24
|
+
* once beside the site header; the helper does not run on module import.
|
|
25
|
+
*/
|
|
26
|
+
export function StickyOffsetSync({
|
|
27
|
+
header,
|
|
28
|
+
}: Readonly<{
|
|
29
|
+
header?: string;
|
|
30
|
+
}> = {}) {
|
|
31
|
+
useEffect(() => syncStickyOffset(header === undefined ? {} : { header }), [header]);
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import * as stylex from "@stylexjs/stylex";
|
|
2
|
+
|
|
3
|
+
export const ditherSurfaceStyles = stylex.create({
|
|
4
|
+
coarse: {
|
|
5
|
+
"--hraness-design-dither-size": "7px",
|
|
6
|
+
},
|
|
7
|
+
fine: {
|
|
8
|
+
"--hraness-design-dither-size": "3px",
|
|
9
|
+
},
|
|
10
|
+
texture: {
|
|
11
|
+
backgroundImage: {
|
|
12
|
+
default:
|
|
13
|
+
"radial-gradient(color-mix(in srgb, currentColor 18%, transparent) 0.75px, transparent 0.75px)",
|
|
14
|
+
"@media (forced-colors: active)": "none",
|
|
15
|
+
},
|
|
16
|
+
backgroundSize:
|
|
17
|
+
"var(--hraness-design-dither-size, 4px) var(--hraness-design-dither-size, 4px)",
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const forcedColors = "@media (forced-colors: active)";
|
|
22
|
+
|
|
23
|
+
export const layoutSurfaceStyles = stylex.create({
|
|
24
|
+
bar: {
|
|
25
|
+
alignItems: "center",
|
|
26
|
+
display: "flex",
|
|
27
|
+
gap: "var(--space-3)",
|
|
28
|
+
"min-inline-size": 0,
|
|
29
|
+
},
|
|
30
|
+
barContent: {
|
|
31
|
+
flex: "1 1 auto",
|
|
32
|
+
},
|
|
33
|
+
barPart: {
|
|
34
|
+
alignItems: "center",
|
|
35
|
+
display: "flex",
|
|
36
|
+
gap: "var(--space-2)",
|
|
37
|
+
"min-inline-size": 0,
|
|
38
|
+
},
|
|
39
|
+
bottomBar: {
|
|
40
|
+
"border-block-start-style": "solid",
|
|
41
|
+
"border-block-start-width": 1,
|
|
42
|
+
"min-block-size": "var(--bottom-bar-height)",
|
|
43
|
+
"padding-block": "var(--layout-chrome-inset)",
|
|
44
|
+
"padding-inline": "var(--layout-chrome-inset)",
|
|
45
|
+
},
|
|
46
|
+
dockedAbsolute: {
|
|
47
|
+
position: "absolute",
|
|
48
|
+
},
|
|
49
|
+
dockedContent: {
|
|
50
|
+
"inline-size": "min(100%, var(--page-canvas-width))",
|
|
51
|
+
"margin-inline": "auto",
|
|
52
|
+
},
|
|
53
|
+
dockedContentCompactInset: {
|
|
54
|
+
"padding-block":
|
|
55
|
+
"var(--space-1) max(var(--space-1), env(safe-area-inset-bottom))",
|
|
56
|
+
"padding-inline":
|
|
57
|
+
"max(var(--layout-edge-inset), env(safe-area-inset-left)) max(var(--layout-edge-inset), env(safe-area-inset-right))",
|
|
58
|
+
},
|
|
59
|
+
dockedContentCompactNoInset: {
|
|
60
|
+
"padding-block":
|
|
61
|
+
"var(--space-1) max(var(--space-1), env(safe-area-inset-bottom))",
|
|
62
|
+
"padding-inline":
|
|
63
|
+
"max(var(--layout-chrome-inset), env(safe-area-inset-left)) max(var(--layout-chrome-inset), env(safe-area-inset-right))",
|
|
64
|
+
},
|
|
65
|
+
dockedContentDefaultInset: {
|
|
66
|
+
"padding-block":
|
|
67
|
+
"var(--layout-chrome-inset) max(var(--layout-chrome-inset), env(safe-area-inset-bottom))",
|
|
68
|
+
"padding-inline":
|
|
69
|
+
"max(var(--layout-edge-inset), env(safe-area-inset-left)) max(var(--layout-edge-inset), env(safe-area-inset-right))",
|
|
70
|
+
},
|
|
71
|
+
dockedContentDefaultNoInset: {
|
|
72
|
+
"padding-block":
|
|
73
|
+
"var(--layout-chrome-inset) max(var(--layout-chrome-inset), env(safe-area-inset-bottom))",
|
|
74
|
+
"padding-inline":
|
|
75
|
+
"max(var(--layout-chrome-inset), env(safe-area-inset-left)) max(var(--layout-chrome-inset), env(safe-area-inset-right))",
|
|
76
|
+
},
|
|
77
|
+
dockedFixed: {
|
|
78
|
+
position: "fixed",
|
|
79
|
+
},
|
|
80
|
+
dockedFooter: {
|
|
81
|
+
"border-block-start-style": "solid",
|
|
82
|
+
"border-block-start-width": 1,
|
|
83
|
+
"inset-block-end": 0,
|
|
84
|
+
"inset-inline": 0,
|
|
85
|
+
zIndex: "var(--z-chrome)",
|
|
86
|
+
},
|
|
87
|
+
dockedSticky: {
|
|
88
|
+
position: "sticky",
|
|
89
|
+
},
|
|
90
|
+
fullSize: {
|
|
91
|
+
"max-inline-size": "none",
|
|
92
|
+
},
|
|
93
|
+
pageCanvas: {
|
|
94
|
+
"inline-size": "min(100%, var(--page-canvas-width))",
|
|
95
|
+
"margin-inline": "auto",
|
|
96
|
+
"min-inline-size": 0,
|
|
97
|
+
},
|
|
98
|
+
pageContentInset: {
|
|
99
|
+
"padding-block": "var(--layout-edge-inset)",
|
|
100
|
+
"padding-inline": "var(--layout-edge-inset)",
|
|
101
|
+
},
|
|
102
|
+
pageNoInset: {
|
|
103
|
+
"padding-block": 0,
|
|
104
|
+
"padding-inline": 0,
|
|
105
|
+
},
|
|
106
|
+
surface: {
|
|
107
|
+
backgroundAttachment: "scroll",
|
|
108
|
+
backgroundClip: "border-box",
|
|
109
|
+
backgroundColor: {
|
|
110
|
+
default: "var(--background)",
|
|
111
|
+
[forcedColors]: "Canvas",
|
|
112
|
+
},
|
|
113
|
+
backgroundImage: "none",
|
|
114
|
+
backgroundOrigin: "padding-box",
|
|
115
|
+
backgroundPosition: "0% 0%",
|
|
116
|
+
backgroundRepeat: "repeat",
|
|
117
|
+
backgroundSize: "auto",
|
|
118
|
+
"border-block-end-color": {
|
|
119
|
+
default: "var(--line)",
|
|
120
|
+
[forcedColors]: "CanvasText",
|
|
121
|
+
},
|
|
122
|
+
"border-block-start-color": {
|
|
123
|
+
default: "var(--line)",
|
|
124
|
+
[forcedColors]: "CanvasText",
|
|
125
|
+
},
|
|
126
|
+
"border-inline-end-color": {
|
|
127
|
+
default: "var(--line)",
|
|
128
|
+
[forcedColors]: "CanvasText",
|
|
129
|
+
},
|
|
130
|
+
"border-inline-start-color": {
|
|
131
|
+
default: "var(--line)",
|
|
132
|
+
[forcedColors]: "CanvasText",
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
topBar: {
|
|
136
|
+
"border-block-end-color": {
|
|
137
|
+
default: "var(--hraness-design-top-bar-edge, var(--line))",
|
|
138
|
+
[forcedColors]: "CanvasText",
|
|
139
|
+
},
|
|
140
|
+
"border-block-end-style": "solid",
|
|
141
|
+
"border-block-end-width": 1,
|
|
142
|
+
"min-block-size": "var(--top-bar-height)",
|
|
143
|
+
},
|
|
144
|
+
topBarActions: {
|
|
145
|
+
"margin-inline-start": "auto",
|
|
146
|
+
},
|
|
147
|
+
topBarGlass: {
|
|
148
|
+
// The global capability/media boundary binds both values locally; atoms
|
|
149
|
+
// paint them without repeating feature queries in optimized delivery.
|
|
150
|
+
"-webkit-backdrop-filter": "var(--hraness-design-top-bar-backdrop, none)",
|
|
151
|
+
"backdrop-filter": "var(--hraness-design-top-bar-backdrop, none)",
|
|
152
|
+
backgroundColor: {
|
|
153
|
+
default: "var(--hraness-design-top-bar-background, var(--background))",
|
|
154
|
+
[forcedColors]: "Canvas",
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
topBarSticky: {
|
|
158
|
+
"inset-block-start": 0,
|
|
159
|
+
"padding-block":
|
|
160
|
+
"max(var(--layout-chrome-inset), env(safe-area-inset-top)) var(--layout-chrome-inset)",
|
|
161
|
+
"padding-inline":
|
|
162
|
+
"max(var(--layout-chrome-inset), env(safe-area-inset-left)) max(var(--layout-chrome-inset), env(safe-area-inset-right))",
|
|
163
|
+
position: "sticky",
|
|
164
|
+
zIndex: "var(--z-chrome)",
|
|
165
|
+
},
|
|
166
|
+
topBarStatic: {
|
|
167
|
+
"padding-block": "var(--layout-chrome-inset)",
|
|
168
|
+
"padding-inline": "var(--layout-chrome-inset)",
|
|
169
|
+
},
|
|
170
|
+
topBarTitle: {
|
|
171
|
+
fontWeight: "var(--font-weight-bold)",
|
|
172
|
+
overflow: "hidden",
|
|
173
|
+
textOverflow: "ellipsis",
|
|
174
|
+
whiteSpace: "nowrap",
|
|
175
|
+
},
|
|
176
|
+
wideSize: {
|
|
177
|
+
"max-inline-size": "var(--page-canvas-wide)",
|
|
178
|
+
},
|
|
179
|
+
});
|