The root `ci` script was never what runs in GitHub CI, and the name worked
against us three ways: it collides with the built-in `npm ci` (which does
something else entirely and is one keystroke away), it invites the
cross-engine passes into a workflow by looking like the thing a workflow
should call, and it blurs "GitHub CI" and "the local gate" in every doc
that names it.
- Rename `ci` → `local:gate` and `ci:storybook` → `local:storybook`, with
no back-compat alias: `npm run ci` now fails with npm's missing-script
error, which prints the available scripts.
- Add `scripts/lib/workflow-gate.mjs` + its `test:scripts` suite, which
runs over the repo's real `.github/workflows/**` and fails on an
invocation of a `local:*` script, of a non-Chromium engine pass (derived
from SUPPORTED_BROWSERS), or of `smoke:web:engine`, or on `SMOKE_BROWSER`
set to anything but a literal `chromium`. It does not forbid
`npm run smoke`, `smoke:web:chromium` or `smoke:tui` — those belong in CI
and are there today. Comments are not scanned, so the workflow can still
explain itself. This is the durable half; the rest is prose.
- Document the two-tier model once, in the root README ("Two tiers: GitHub
CI and the local gate"), and point the other docs at it rather than
restating the split.
- Sweep the ~40 stale references across README, AGENTS.md,
.github/copilot-instructions.md, the client READMEs, the roadmap doc and
the script headers. AGENTS.md and copilot-instructions.md change
together, per the mirror rule.
No gate changes what it actually runs.
Signed-off-by: Cliff Hall <cliff@futurescale.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
99 lines
3 KiB
TypeScript
99 lines
3 KiB
TypeScript
import type { Preview } from "@storybook/react-vite";
|
|
import { MantineProvider, useMantineColorScheme } from "@mantine/core";
|
|
import { Notifications } from "@mantine/notifications";
|
|
import "@mantine/core/styles.css";
|
|
import "@mantine/notifications/styles.css";
|
|
import "../src/App.css";
|
|
import { theme } from "../src/theme/theme";
|
|
import { cssVariablesResolver } from "../src/theme/cssVariables";
|
|
import { useEffect } from "react";
|
|
|
|
// eslint-disable-next-line react-refresh/only-export-components
|
|
function ColorSchemeWrapper({
|
|
colorScheme,
|
|
children,
|
|
}: {
|
|
colorScheme: "light" | "dark";
|
|
children: React.ReactNode;
|
|
}) {
|
|
const { setColorScheme } = useMantineColorScheme();
|
|
|
|
useEffect(() => {
|
|
setColorScheme(colorScheme);
|
|
}, [colorScheme, setColorScheme]);
|
|
|
|
return <>{children}</>;
|
|
}
|
|
|
|
const preview: Preview = {
|
|
globalTypes: {
|
|
colorScheme: {
|
|
description: "Mantine color scheme",
|
|
toolbar: {
|
|
title: "Color Scheme",
|
|
icon: "mirror",
|
|
items: [
|
|
{ value: "light", title: "Light", icon: "sun" },
|
|
{ value: "dark", title: "Dark", icon: "moon" },
|
|
],
|
|
dynamicTitle: true,
|
|
},
|
|
},
|
|
},
|
|
initialGlobals: {
|
|
colorScheme: "light",
|
|
},
|
|
decorators: [
|
|
(Story, context) => {
|
|
const isFullscreen = context.parameters?.layout === "fullscreen";
|
|
return (
|
|
<MantineProvider
|
|
theme={theme}
|
|
defaultColorScheme="light"
|
|
cssVariablesResolver={cssVariablesResolver}
|
|
>
|
|
<ColorSchemeWrapper
|
|
colorScheme={context.globals.colorScheme ?? "light"}
|
|
>
|
|
<Notifications position="top-right" />
|
|
{isFullscreen ? (
|
|
<div style={{ height: "100vh", overflow: "hidden" }}>
|
|
<Story />
|
|
</div>
|
|
) : (
|
|
<Story />
|
|
)}
|
|
</ColorSchemeWrapper>
|
|
</MantineProvider>
|
|
);
|
|
},
|
|
],
|
|
parameters: {
|
|
controls: {
|
|
matchers: {
|
|
color: /(background|color)$/i,
|
|
date: /Date$/i,
|
|
},
|
|
},
|
|
a11y: {
|
|
// `'error'` fails the Storybook play-function tests (part of `npm run local:gate`)
|
|
// on any axe violation, so the zero-violation state this PR reached is
|
|
// enforced going forward rather than being a point-in-time result.
|
|
test: "error",
|
|
// Stories render presentational components (and whole screens) in
|
|
// isolation, outside the app's `AppShell` — which is what provides the
|
|
// page landmarks (`<main>`, nav) in the real app. The `region` rule
|
|
// ("all content must live inside a landmark") is therefore a page-level
|
|
// concern that can't be satisfied in Storybook isolation and would fire on
|
|
// essentially every story; it's covered by the app shell at runtime, not
|
|
// by the components under test. Disable it here so the a11y panel surfaces
|
|
// only rules the components can actually own.
|
|
config: {
|
|
rules: [{ id: "region", enabled: false }],
|
|
},
|
|
},
|
|
layout: "centered",
|
|
},
|
|
};
|
|
|
|
export default preview;
|