diff --git a/README.md b/README.md
index b4c2dfe..7e70a62 100644
--- a/README.md
+++ b/README.md
@@ -63,11 +63,15 @@ pnpm format # format everything with Prettier
# Storybook (run per package)
pnpm --filter @surfnet/react storybook # http://localhost:6006
-pnpm --filter @surfnet/angular storybook # http://localhost:6006
+pnpm --filter @surfnet/angular storybook # http://localhost:6007
```
Each component ships a Storybook story covering its full surface (variants, sizes,
-states). Start there to see what's available.
+states). Start there to see what's available. Both Storybooks are also deployed
+to GitHub Pages on every push to `main`:
+
+- **React** — https://surfnet.github.io/DesignSystem/react/
+- **Angular** — https://surfnet.github.io/DesignSystem/angular/
## Demo app
diff --git a/packages/angular/.storybook/manager.ts b/packages/angular/.storybook/manager.ts
index 662f673..4acf61d 100644
--- a/packages/angular/.storybook/manager.ts
+++ b/packages/angular/.storybook/manager.ts
@@ -1,3 +1,3 @@
import { registerManager } from '@surfnet/storybook-config/manager';
-registerManager();
+registerManager('angular');
diff --git a/packages/angular/.storybook/preview.ts b/packages/angular/.storybook/preview.ts
index 20f3f2b..6a99806 100644
--- a/packages/angular/.storybook/preview.ts
+++ b/packages/angular/.storybook/preview.ts
@@ -14,5 +14,15 @@ export default {
initialGlobals: { framework: 'angular', ...themeInitialGlobals },
globalTypes: { ...frameworkGlobalTypes, ...themeGlobalTypes },
decorators: [frameworkSwitcher('angular'), themeSwitcher()],
- parameters: sharedParameters,
+ parameters: {
+ ...sharedParameters,
+ // Must be a literal (Storybook reads it via static analysis, not
+ // execution). Keep in sync with packages/react/.storybook/preview.ts.
+ options: {
+ storySort: {
+ method: 'alphabetical',
+ order: ['Foundations', 'Components'],
+ },
+ },
+ },
};
diff --git a/packages/react/.storybook/manager.ts b/packages/react/.storybook/manager.ts
index 662f673..63862db 100644
--- a/packages/react/.storybook/manager.ts
+++ b/packages/react/.storybook/manager.ts
@@ -1,3 +1,3 @@
import { registerManager } from '@surfnet/storybook-config/manager';
-registerManager();
+registerManager('react');
diff --git a/packages/react/.storybook/preview.ts b/packages/react/.storybook/preview.ts
index 0c09272..b459c19 100644
--- a/packages/react/.storybook/preview.ts
+++ b/packages/react/.storybook/preview.ts
@@ -24,5 +24,13 @@ export default {
// `args` param) is treated as a non-args story, so Storybook prints the whole
// story object instead of the JSX. See @storybook/react's `skipJsxRender`.
docs: { source: { type: 'dynamic' } },
+ // Must be a literal (Storybook reads it via static analysis, not
+ // execution). Keep in sync with packages/angular/.storybook/preview.ts.
+ options: {
+ storySort: {
+ method: 'alphabetical',
+ order: ['Foundations', 'Components'],
+ },
+ },
},
};
diff --git a/packages/storybook-config/src/index.ts b/packages/storybook-config/src/index.ts
index 4793ab5..ad051ae 100644
--- a/packages/storybook-config/src/index.ts
+++ b/packages/storybook-config/src/index.ts
@@ -12,6 +12,10 @@ export type {
// Shared preview parameters so every framework's Storybook renders stories the
// same way.
+//
+// `options.storySort` isn't here: Storybook reads it via static analysis of
+// each preview.ts, not by executing this module, so it must be a literal in
+// every preview.ts instead (see those files for the actual value).
export const sharedParameters = {
layout: 'centered',
controls: {
diff --git a/packages/storybook-config/src/logo.ts b/packages/storybook-config/src/logo.ts
new file mode 100644
index 0000000..be268ed
--- /dev/null
+++ b/packages/storybook-config/src/logo.ts
@@ -0,0 +1,11 @@
+// Inlined as a string so it works under both the Vite and webpack manager
+// builds without extra loader config. Sized down from the 236x168 source.
+export const LOGO_SVG = ``;
diff --git a/packages/storybook-config/src/manager.ts b/packages/storybook-config/src/manager.ts
index ba448d3..cc77b59 100644
--- a/packages/storybook-config/src/manager.ts
+++ b/packages/storybook-config/src/manager.ts
@@ -1,14 +1,34 @@
import { addons } from 'storybook/manager-api';
import { create } from 'storybook/theming/create';
+import type { Framework } from './frameworks.js';
+import { LOGO_SVG } from './logo.js';
+
+const FRAMEWORK_TITLES: Record = {
+ react: 'React',
+ angular: 'Angular',
+};
+
+// Leaving brandImage unset makes Storybook render brandTitle as raw HTML
+// instead of plain text — the only way to show the logo and text together.
+const brandMarkup = (framework: Framework) => `
+
+ ${LOGO_SVG}
+
+ Design System
+ - ${FRAMEWORK_TITLES[framework]}
+
+
+`;
+
// Shared manager (chrome/sidebar) theme so every framework's Storybook is
-// branded identically.
-const theme = create({
- base: 'light',
- brandTitle: 'SURF Design System',
- brandUrl: 'https://www.surf.nl',
-});
-
-export function registerManager(): void {
+// branded identically, save for the framework name in the title.
+export function registerManager(framework: Framework): void {
+ const theme = create({
+ base: 'light',
+ brandTitle: brandMarkup(framework),
+ brandUrl: 'https://www.surf.nl',
+ });
+
addons.setConfig({ theme });
}