Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ ps-qa --app tests/ps-qa/ps-qa.ron qa-hosted \
--checks tests/ps-qa/checks
```

The UI 3.2.2 registry build passes all 669 native checks across 13 groups,
The UI 3.2.3 candidate build passes all 675 native checks across 13 groups,
including Calendar selection, month navigation, and keyboard and pointer-driven
Slider and Color Picker outcomes. The release gate includes every group.
The Layouts route uses its own document marker, and decorative cards are
articles rather than controls that promise an action.

The production response policy is a separate release check because chuzz does
not emulate browser CSP enforcement. It rejects a policy that blocks UI's
dynamic Slider and theme-preview styles, and it rejects stale Google Fonts
sources:
not emulate browser CSP enforcement. When CSP is enabled, it rejects a policy
that blocks UI's dynamic Slider and theme-preview styles. It always rejects
stale Google Fonts sources:

```sh
bun run qa:production-policy
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"@iconify-json/lucide": "^1.2.127",
"@iconify-json/mdi": "^1.2.3",
"@iconify/tailwind4": "^1.0.6",
"@pathscale/ui": "^3.2.2",
"@pathscale/ui": "^3.2.3",
"@rsbuild/core": "^1.3.20",
"@rsbuild/plugin-babel": "^1.0.5",
"@solidjs/router": "2.0.0-next.19",
Expand Down
16 changes: 15 additions & 1 deletion scripts/verify-production-policy.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ if (/fonts\.(googleapis|gstatic)\.com/i.test(productionSource)) {
}

if (!policy) {
console.log(`Production policy accepts runtime theme styles and has no Google Fonts source: ${targetUrl} has no CSP header.`);
console.log(
`Production policy has no enforced CSP and no Google Fonts source: ${targetUrl}`,
);
process.exit(0);
}

Expand Down Expand Up @@ -71,6 +73,18 @@ if (!styleAttributeSources.includes("'unsafe-inline'")) {
);
}

const styleElementSources =
directives.get("style-src-elem") ??
directives.get("style-src") ??
directives.get("default-src") ??
[];

if (!styleElementSources.includes("'unsafe-inline'")) {
throw new Error(
"Production CSP blocks the style elements used by the UI runtime.",
);
}

console.log(
`Production policy accepts runtime theme styles and has no Google Fonts source: ${targetUrl}`,
);
151 changes: 151 additions & 0 deletions src/components/AuthPoweredByShowcase.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import { AuthPoweredBy, Flex, Icon, Link } from "@pathscale/ui";
import ShowcaseLayout from "./ShowcaseLayout";
import { CodeBlock } from "./showcase/CodeBlock";
import { PropsTable } from "./showcase/PropsTable";
import { ShowcaseSection } from "./showcase/ShowcaseSection";

const sections = [
{ id: "default", title: "Default Honey attribution" },
{ id: "variants", title: "Variants" },
{ id: "alignment", title: "Alignment" },
{ id: "custom", title: "Custom content" },
{ id: "props", title: "Props" },
] as const;

const props = [
{
name: "label",
type: "string",
default: '"Secure Auth by Honey"',
description: "Accessible attribution text shown beside the provider mark.",
},
{
name: "href",
type: "string",
default: '"https://honey.id/"',
description: "Provider destination opened in a separate browser tab.",
},
{
name: "variant",
type: '"subtle" | "card" | "inline"',
default: '"subtle"',
description: "Visual treatment for the attribution.",
},
{
name: "align",
type: '"left" | "center" | "right"',
default: '"center"',
description: "Horizontal placement inside the component root.",
},
{
name: "logo",
type: "JSX.Element",
description: "Optional provider mark rendered before the label.",
},
{
name: "id",
type: "string",
description: "Stable root identity; the link receives an --link suffix.",
},
];

export default function AuthPoweredByShowcase() {
return (
<ShowcaseLayout>
<Flex direction="col" gap="lg">
<ShowcaseSection id="contents" title="Contents">
<Flex as="nav" direction="col" gap="sm">
{sections.map((section) => (
<Link href={`#${section.id}`} underline="hover">
{section.title}
</Link>
))}
</Flex>
</ShowcaseSection>

<ShowcaseSection id="default" title="Default Honey attribution">
<Flex direction="col" gap="md">
<AuthPoweredBy id="honey-default" />
<CodeBlock code={`<AuthPoweredBy />`} />
</Flex>
</ShowcaseSection>

<ShowcaseSection id="variants" title="Variants">
<Flex direction="col" gap="md">
<AuthPoweredBy
id="honey-subtle"
href="#honey-subtle"
label="Honey subtle attribution"
variant="subtle"
/>
<AuthPoweredBy
id="honey-card"
href="#honey-card"
label="Honey card attribution"
variant="card"
/>
<AuthPoweredBy
id="honey-inline"
href="#honey-inline"
label="Honey inline attribution"
variant="inline"
/>
<CodeBlock
code={`<AuthPoweredBy variant="subtle" />
<AuthPoweredBy variant="card" />
<AuthPoweredBy variant="inline" />`}
/>
</Flex>
</ShowcaseSection>

<ShowcaseSection id="alignment" title="Alignment">
<Flex direction="col" gap="md">
<AuthPoweredBy
id="honey-left"
href="#honey-left"
label="Honey attribution aligned left"
align="left"
variant="card"
/>
<AuthPoweredBy
id="honey-center"
href="#honey-center"
label="Honey attribution aligned center"
align="center"
variant="card"
/>
<AuthPoweredBy
id="honey-right"
href="#honey-right"
label="Honey attribution aligned right"
align="right"
variant="card"
/>
</Flex>
</ShowcaseSection>

<ShowcaseSection id="custom" title="Custom content">
<Flex direction="col" gap="md">
<AuthPoweredBy
id="honey-custom"
href="#honey-custom"
label="Identity secured by Honey"
variant="card"
logo={<Icon src="icon-[lucide--shield-check]" width={18} height={18} />}
/>
<CodeBlock
code={`<AuthPoweredBy
label="Identity secured by Honey"
logo={<Icon src="icon-[lucide--shield-check]" />}
/>`}
/>
</Flex>
</ShowcaseSection>

<ShowcaseSection id="props" title="Props">
<PropsTable props={props} />
</ShowcaseSection>
</Flex>
</ShowcaseLayout>
);
}
4 changes: 0 additions & 4 deletions src/components/Preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ export default function Preview(props: PreviewProps) {
<div
id="theme-preview"
class="text-base-content pt-6 transition-colors duration-500 bg-base-300"
style={{
"background-image":
"linear-gradient(rgb(0 0 0 / var(--theme-glass-scrim-opacity, 0%)), rgb(0 0 0 / var(--theme-glass-scrim-opacity, 0%)))",
}}
>
<div class="flex flex-col items-start gap-3 px-3 sm:flex-row sm:items-center sm:justify-between sm:px-8 sm:ps-10">
<h2 class="font-title text-lg">{TAB_TITLES[selectedKey()]}</h2>
Expand Down
13 changes: 11 additions & 2 deletions src/components/ShowcaseLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { useLocation } from "@solidjs/router";
import { routes } from "../routes";
import type { JSX } from "@solidjs/web";
import type { ParentComponent } from "solid-js";
import { Flex } from "@pathscale/ui";
import { Flex, Link } from "@pathscale/ui";
import { ROUTES } from "../config/routes";

interface ShowcaseLayoutProps {
children: JSX.Element;
Expand Down Expand Up @@ -31,8 +32,16 @@ const ShowcaseLayout: ParentComponent = (props) => {
<div class="mx-auto max-w-5xl">
<Flex direction="col" gap="lg" class="max-w-4xl mx-auto">
<div>
<Link
id="showcase-all-components"
href={ROUTES.SHOWCASES}
underline="hover"
class="mb-3"
>
All components
</Link>
<h1 class="text-3xl font-bold mb-2">{current()?.name}</h1>
<p class="text-gray-600 dark:text-gray-400">
<p class="text-base-content/70">
{current()?.description}
</p>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/content/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const Search: Component<SearchProps> = (props) => {
DOCS_LAYOUTS: "Solid Layouts",
DOCS_USAGE: "Usage Cheatsheet",
THEMING: "Theme Editor",
SHOWCASES: "Component Showcases",
SHOWCASES: "Components",
CHAT_BUBBLE: "Chat Bubble",
COLOR_PICKER: "Color Picker",
FILE_INPUT: "File Input",
Expand Down
37 changes: 18 additions & 19 deletions src/components/layout/Header/MarketingHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, Show } from "solid-js";
import { Button, Flex, Navbar } from "@pathscale/ui";
import { Button, Flex, Link, Navbar } from "@pathscale/ui";
import { useNavigation } from "./hooks/useNavigation";
import { MainNavigation } from "./components/MainNavigation";
import { ComponentsMenu } from "./components/ComponentsMenu";
Expand Down Expand Up @@ -47,18 +47,18 @@ export const MarketingHeader: Component<MarketingHeaderProps> = (props) => {
</Navbar.Start>

<Navbar.Start class="hidden lg:flex">
<a
<Link
href={ROUTES.HOME}
class="text-xl font-bold normal-case hover:text-primary transition-colors px-4 py-2"
class="text-base-content text-xl font-bold normal-case hover:text-primary transition-colors px-4 py-2"
>
UI
</a>
</Link>
</Navbar.Start>

<Navbar.Center class="lg:hidden">
<a href={ROUTES.HOME} class="text-xl font-bold normal-case px-4 py-2">
<Link href={ROUTES.HOME} class="text-base-content text-xl font-bold normal-case px-4 py-2">
UI
</a>
</Link>
</Navbar.Center>

<Navbar.Center class="hidden lg:flex">
Expand All @@ -68,35 +68,34 @@ export const MarketingHeader: Component<MarketingHeaderProps> = (props) => {
<Navbar.End class="hidden lg:flex">
<Flex gap="md" align="center">
<Search class="w-48" />
<a
<Link
id="github-source-link"
href={EXTERNAL_ROUTES.GITHUB}
target="_blank"
rel="noopener noreferrer"
isExternal
aria-label="View UI on GitHub"
class="hover:text-primary p-2 rounded-full transition-colors"
class="text-base-content hover:text-primary p-2 rounded-full transition-colors"
>
<GitHubIcon />
</a>
<a
</Link>
<Button
href={ROUTES.DOCS_INSTALLATION}
class="bg-primary text-white hover:bg-primary/90 px-6 py-2 rounded-lg font-semibold transition-all whitespace-nowrap"
flavor="primary"
class="whitespace-nowrap"
>
Get Started
</a>
</Button>
</Flex>
</Navbar.End>

<Navbar.End class="lg:hidden">
<a
<Link
href={EXTERNAL_ROUTES.GITHUB}
target="_blank"
rel="noopener noreferrer"
isExternal
aria-label="View UI on GitHub from mobile navigation"
class="p-2 rounded-full"
class="text-base-content p-2 rounded-full"
>
<GitHubIcon />
</a>
</Link>
</Navbar.End>
</Navbar.Row>
</div>
Expand Down
22 changes: 14 additions & 8 deletions src/components/layout/Header/components/ComponentsMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { Component, For, createMemo } from "solid-js";
import { Button, Flex, Navbar } from "@pathscale/ui";
import { navigationItems } from "../navigationData";
import { Button, Flex, Link, Navbar } from "@pathscale/ui";
import {
DEFAULT_COMPONENT_CATEGORY,
navigationItems,
} from "../navigationData";
import { useNavigation } from "../hooks/useNavigation";
import clsx from "clsx";

Expand Down Expand Up @@ -33,9 +36,10 @@ export const ComponentsMenu: Component<ComponentsMenuProps> = (props) => {
class={clsx(
"px-3 py-1 rounded-md text-sm transition-colors",
activeCategory() === subcategory.title ||
(activeCategory() === "Components" && subcategory === componentsItem?.subcategories?.[0])
? "bg-primary text-white"
: "hover:bg-base-300"
(activeCategory() === "Components" &&
subcategory.title === DEFAULT_COMPONENT_CATEGORY)
? "bg-primary text-primary-content"
: "text-base-content hover:bg-base-300"
)}
>
{subcategory.title}
Expand All @@ -49,15 +53,17 @@ export const ComponentsMenu: Component<ComponentsMenuProps> = (props) => {
<Flex wrap="wrap" gap="sm" align="center">
<For each={selectedSubcategory()?.items || []}>
{(item) => (
<a
<Link
href={item.href}
class={clsx(
"px-3 py-1 rounded-md text-sm transition-colors",
isActive(item.href) ? "bg-primary text-white" : "hover:bg-base-300"
isActive(item.href)
? "bg-primary text-primary-content"
: "text-base-content hover:bg-base-300"
)}
>
{item.title}
</a>
</Link>
)}
</For>
</Flex>
Expand Down
Loading
Loading