mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-10-14 17:54:42 +00:00
* Remove restating comments in backend * Remove restating comments in frontend stories * Remove restating comments in pipeline * Remove restating comments in pipeline scripts * Restore location-clear comment in BreweryRepository * Remove stale/restating comments found in second pass * Restore mock curated-data branch comment in main.cc * Remove more restating/filler comments in backend * Document account-management endpoints, compose files, and env generator * Squashed commit of the following: commit a8a5b8abd9969859c695092fae6990d03b2135ed Author: Aaron Po <aaron.po97@gmail.com> Date: Sun Aug 23 23:53:56 2026 -0400 Add reverse geocoding for brewery street addresses (#245) * Add geocoding to seed application, remove postal codes from generator Update comments * Update pipeline class diagram for OpenAI generator * Update pipeline activity diagram for brewery coordinates and OpenAI backend * Add mailpit, production, db-only, and minimal environments to deployment diagram * Fix authentication flow diagram for Identity migration * Add account-management flows to authentication diagram * Fix database schema diagram note referencing removed AuthRepository
158 lines
6.1 KiB
TypeScript
158 lines
6.1 KiB
TypeScript
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
import { expect, within } from 'storybook/test';
|
|
import { biergartenThemes } from '../app/features/theme/themes';
|
|
|
|
const themesDescription = `Palette reference for all Biergarten themes. Each panel shows the main semantic color pairs, status tokens, and custom content tokens so you can catch contrast issues, pairing mistakes, and mood drift before they show up in real components.`;
|
|
|
|
const ThemeSwatch = ({ label, className }: { label: string; className: string }) => {
|
|
return <div className={`rounded-box p-3 text-sm font-medium ${className}`}>{label}</div>;
|
|
};
|
|
|
|
/** For custom tokens not covered by Tailwind utilities (surface, muted, highlight). */
|
|
const CssVarSwatch = ({ label, bg, color }: { label: string; bg: string; color: string }) => {
|
|
return (
|
|
<div
|
|
className="rounded-box p-3 text-sm font-medium"
|
|
style={{ backgroundColor: `var(${bg})`, color: `var(${color})` }}
|
|
>
|
|
{label}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const TextTokenSample = ({
|
|
label,
|
|
background,
|
|
text,
|
|
}: {
|
|
label: string;
|
|
background: string;
|
|
text: string;
|
|
}) => {
|
|
return (
|
|
<div className="rounded-box p-3" style={{ backgroundColor: `var(${background})` }}>
|
|
<p className="text-xs font-semibold uppercase tracking-wide text-base-content/50">
|
|
{label}
|
|
</p>
|
|
<p className="mt-1 text-sm font-medium" style={{ color: `var(${text})` }}>
|
|
Secondary copy, placeholders, and helper text.
|
|
</p>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const ThemePanel = ({ label, value, vibe }: { label: string; value: string; vibe: string }) => {
|
|
return (
|
|
<section
|
|
data-theme={value}
|
|
className="rounded-box border border-base-300 bg-base-100 shadow-lg"
|
|
>
|
|
<div className="space-y-4 p-5">
|
|
<div className="space-y-1">
|
|
<h2 className="text-2xl font-bold">{label}</h2>
|
|
<p className="text-sm text-base-content/70">{vibe}</p>
|
|
</div>
|
|
|
|
<div>
|
|
<p className="mb-1.5 text-xs font-semibold uppercase tracking-wide text-base-content/50">
|
|
Core
|
|
</p>
|
|
<div className="grid gap-2 sm:grid-cols-2">
|
|
<ThemeSwatch label="Primary" className="bg-primary text-primary-content" />
|
|
<ThemeSwatch
|
|
label="Secondary"
|
|
className="bg-secondary text-secondary-content"
|
|
/>
|
|
<ThemeSwatch label="Accent" className="bg-accent text-accent-content" />
|
|
<ThemeSwatch label="Neutral" className="bg-neutral text-neutral-content" />
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<p className="mb-1.5 text-xs font-semibold uppercase tracking-wide text-base-content/50">
|
|
Status
|
|
</p>
|
|
<div className="grid gap-2 grid-cols-2 sm:grid-cols-4">
|
|
<ThemeSwatch label="Info" className="bg-info text-info-content" />
|
|
<ThemeSwatch label="Success" className="bg-success text-success-content" />
|
|
<ThemeSwatch label="Warning" className="bg-warning text-warning-content" />
|
|
<ThemeSwatch label="Error" className="bg-error text-error-content" />
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<p className="mb-1.5 text-xs font-semibold uppercase tracking-wide text-base-content/50">
|
|
Content
|
|
</p>
|
|
<div className="grid gap-2 sm:grid-cols-3">
|
|
<CssVarSwatch
|
|
label="Surface"
|
|
bg="--color-surface"
|
|
color="--color-surface-content"
|
|
/>
|
|
<TextTokenSample
|
|
label="Muted on Base"
|
|
background="--color-base-100"
|
|
text="--color-muted"
|
|
/>
|
|
<CssVarSwatch
|
|
label="Highlight"
|
|
bg="--color-highlight"
|
|
color="--color-highlight-content"
|
|
/>
|
|
</div>
|
|
<div className="mt-2">
|
|
<TextTokenSample
|
|
label="Muted on Surface"
|
|
background="--color-surface"
|
|
text="--color-muted"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex flex-wrap gap-2">
|
|
<button className="btn btn-primary btn-sm">Primary</button>
|
|
<button className="btn btn-secondary btn-sm">Secondary</button>
|
|
<button className="btn btn-outline btn-sm">Outline</button>
|
|
</div>
|
|
|
|
<div role="alert" className="alert alert-success alert-soft">
|
|
<span>Semantic tokens stay stable while the atmosphere changes.</span>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
const meta = {
|
|
title: 'Themes/Biergarten Themes',
|
|
parameters: {
|
|
layout: 'fullscreen',
|
|
docs: {
|
|
description: {
|
|
component: themesDescription,
|
|
},
|
|
},
|
|
},
|
|
tags: ['autodocs'],
|
|
render: () => (
|
|
<div className="grid gap-6 p-6 lg:grid-cols-2">
|
|
{biergartenThemes.map((theme) => (
|
|
<ThemePanel key={theme.value} {...theme} />
|
|
))}
|
|
</div>
|
|
),
|
|
} satisfies Meta;
|
|
|
|
export default meta;
|
|
type Story = StoryObj<typeof meta>;
|
|
|
|
export const Gallery: Story = {
|
|
play: async ({ canvasElement }) => {
|
|
const canvas = within(canvasElement);
|
|
for (const theme of biergartenThemes) {
|
|
await expect(canvas.getByRole('heading', { name: theme.label })).toBeInTheDocument();
|
|
}
|
|
},
|
|
};
|