Add brewery discovery & detail pages with location-based search (#253)

This commit is contained in:
Aaron Po
2026-08-29 00:44:33 -04:00
committed by GitHub
parent 92a30b11db
commit a580314583
90 changed files with 3874 additions and 187 deletions

View File

@@ -0,0 +1,71 @@
import type { Meta, StoryObj } from '@storybook/react-vite';
import { expect, within } from 'storybook/test';
import FormField from './FormField';
const formFieldDescription = `Reusable labeled input for Biergarten forms. This page shows guided, error, and password states so you can review label spacing, helper text, validation messaging, and ARIA behavior in the same card layout used across the app.`;
const meta = {
title: 'Forms/FormField',
component: FormField,
tags: ['autodocs'],
args: {
id: 'email',
name: 'email',
type: 'email',
label: 'Email address',
placeholder: 'you@example.com',
hint: 'We only use this to manage your account.',
},
parameters: {
layout: 'centered',
docs: {
description: {
component: formFieldDescription,
},
},
},
render: (args) => (
<div className="w-full max-w-md rounded-box bg-base-100 p-6 shadow-lg">
<FormField {...args} />
</div>
),
} satisfies Meta<typeof FormField>;
export default meta;
type Story = StoryObj<typeof meta>;
export const WithHint: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await expect(canvas.getByLabelText(/email address/i)).toBeInTheDocument();
await expect(canvas.getByText(/manage your account/i)).toBeInTheDocument();
},
};
export const WithError: Story = {
args: {
error: 'Please enter a valid email address.',
hint: undefined,
'aria-invalid': true,
defaultValue: 'not-an-email',
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await expect(canvas.getByText(/valid email address/i)).toBeInTheDocument();
await expect(canvas.getByLabelText(/email address/i)).toHaveAttribute(
'aria-invalid',
'true',
);
},
};
export const PasswordField: Story = {
args: {
id: 'password',
name: 'password',
type: 'password',
label: 'Password',
placeholder: 'Enter a strong password',
hint: 'Use 12 or more characters.',
},
};

View File

@@ -0,0 +1,52 @@
import type { Meta, StoryObj } from '@storybook/react-vite';
import { expect, within } from 'storybook/test';
import SubmitButton from './SubmitButton';
const submitButtonDescription = `Shared submit action for Biergarten forms. These stories cover the idle, loading, and custom-width states so you can verify button copy, disabled behavior during submission, and theme styling without wiring up a full form flow.`;
const meta = {
title: 'Forms/SubmitButton',
component: SubmitButton,
tags: ['autodocs'],
args: {
idleText: 'Save changes',
submittingText: 'Saving changes',
isSubmitting: false,
},
parameters: {
layout: 'centered',
docs: {
description: {
component: submitButtonDescription,
},
},
},
} satisfies Meta<typeof SubmitButton>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Idle: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await expect(canvas.getByRole('button', { name: /save changes/i })).toBeEnabled();
},
};
export const Submitting: Story = {
args: {
isSubmitting: true,
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await expect(canvas.getByRole('button', { name: /saving changes/i })).toBeDisabled();
},
};
export const CustomWidth: Story = {
args: {
className: 'btn btn-secondary min-w-64',
idleText: 'Register user',
submittingText: 'Registering user',
},
};