Add storefront component migration: cards, badges, progress bars, animations, and React wrapper package

Major feature migration from dt-shopify-storefront into the design system:

- Card system: per-card color modes (normal/emphasis/warning/success/other),
  progress bars, full-bleed card body (card-body-flush), image bevel clip-paths,
  and visible structural borders at bevel corners
- Badge system: dt-card-badge with position-aware offsets for cards vs media frames
- Media frames: dt-bevel-media with inner surface fill, image clipping, and
  "MISSING MEDIA" placeholder for empty containers
- Interactive bevel buttons: dt-btn with hover/selected states and pulse animation
- Menu items: dt-menu-item with active states and level indentation
- Animations: scale-in, fade-in, slide-up, pulse, ping, spin keyframes
- Feature legend: CSS grid for product feature icons with state colors
- Scrollbar styling for DT brand
- New @dangerousthings/react package wrapping web CSS components
- New @dangerousthings/tailwind-preset package
- New @dangerousthings/hex-background package
- Desktop showcase rewritten in React with Tailwind CSS
- Mobile showcase updated with new screens (animations, filters, advanced cards)
- Tokens: added mode color tokens, RGB variants, and selected-state tokens

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
michael
2026-03-05 13:26:03 -08:00
parent 47e8085581
commit e74c285b70
109 changed files with 7196 additions and 1026 deletions

View File

@@ -0,0 +1,122 @@
import { useState } from 'react';
import {
DTTextInput,
DTCheckbox,
DTSwitch,
DTRadioGroup,
DTProgressBar,
DTAccordion,
DTQuantityStepper,
} from '@dangerousthings/react';
import type { DTAccordionSection } from '@dangerousthings/react';
import { Section, Row, CodeLabel, DemoLabel } from '../components/Section';
export function FormsPage() {
const [checks, setChecks] = useState({ a: false, b: true, c: true, d: false });
const [switches, setSwitches] = useState({ a: false, b: true, c: true, d: false });
const [radioValue, setRadioValue] = useState('nfc');
const [stepperValue, setStepperValue] = useState(1);
const accordionSections: DTAccordionSection[] = [
{ key: 'size', title: 'Size', children: <div style={{ padding: 'var(--space-4)' }}>Small, Medium, Large options available.</div> },
{ key: 'chip', title: 'Chip Type', children: <div style={{ padding: 'var(--space-4)' }}>NTAG, DESFire, MIFARE Classic.</div> },
{ key: 'freq', title: 'Frequency', children: <div style={{ padding: 'var(--space-4)' }}>13.56 MHz (HF), 125 kHz (LF).</div> },
];
return (
<>
<h1 className="page-title">Forms</h1>
<p className="page-subtitle">DT-branded form components using @dangerousthings/react.</p>
<Section title="Text Input" description="Sharp corners + focus glow bar. 2px solid border, no border-radius.">
<DTTextInput placeholder="Normal input — click to focus" style={{ maxWidth: 400 }} />
<CodeLabel text="<DTTextInput /> — focus glow bar" />
<br />
<DTTextInput error placeholder="Error state input" style={{ maxWidth: 400 }} />
<CodeLabel text="<DTTextInput error /> — red focus bar" />
<br />
<textarea placeholder="Textarea element" style={{ maxWidth: 400, minHeight: 80 }} />
<CodeLabel text="textarea — same styling" />
</Section>
<Section title="Checkbox" description="Beveled hexagon shape via clip-path. 30% corner cuts.">
<div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
<DTCheckbox checked={checks.a} onChange={v => setChecks(p => ({ ...p, a: v }))} label="Unchecked checkbox" />
<DTCheckbox checked={checks.b} onChange={v => setChecks(p => ({ ...p, b: v }))} label="Checked checkbox" />
<DTCheckbox checked={checks.c} onChange={() => {}} disabled label="Disabled checked" />
<DTCheckbox checked={checks.d} onChange={() => {}} disabled label="Disabled unchecked" />
</div>
<CodeLabel text="<DTCheckbox checked onChange label />" />
</Section>
<Section title="Switch / Toggle" description="Angular track + sliding square thumb. 48x26 track, 20x20 thumb.">
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
<DTSwitch checked={switches.a} onChange={v => setSwitches(p => ({ ...p, a: v }))} label="Off" />
<DTSwitch checked={switches.b} onChange={v => setSwitches(p => ({ ...p, b: v }))} label="On" />
<DTSwitch checked={switches.c} onChange={() => {}} disabled label="Disabled (on)" />
<DTSwitch checked={switches.d} onChange={() => {}} disabled label="Disabled (off)" />
</div>
<CodeLabel text="<DTSwitch checked onChange label />" />
</Section>
<Section title="Radio Button" description="Hexagonal indicator via clip-path. Flat-top hexagon shape.">
<DTRadioGroup
options={[
{ value: 'nfc', label: 'NFC (Near Field Communication)' },
{ value: 'rfid', label: 'RFID (Radio Frequency ID)' },
{ value: 'ble', label: 'BLE (Bluetooth Low Energy)' },
]}
value={radioValue}
onChange={setRadioValue}
/>
<CodeLabel text="<DTRadioGroup options value onChange />" />
</Section>
<Section title="Progress Bar" description="Angular, no border-radius. 4px default height.">
<DemoLabel text="25%" />
<DTProgressBar value={0.25} />
<DemoLabel text="50% WITH LABEL" />
<DTProgressBar value={0.5} label="50%" />
<DemoLabel text="75%" />
<DTProgressBar value={0.75} />
<DemoLabel text="100%" />
<DTProgressBar value={1.0} label="100%" />
<CodeLabel text="<DTProgressBar value={0.5} label='50%' />" />
</Section>
<Section title="Accordion" description="Click headers to expand. 5px top border, chevron rotation.">
<DTAccordion sections={accordionSections} />
<CodeLabel text="<DTAccordion sections={[{ key, title, children }]} />" />
</Section>
<Section title="Quantity Stepper" description="Beveled +/- buttons with center display.">
<DTQuantityStepper value={stepperValue} onChange={setStepperValue} min={0} max={10} />
<CodeLabel text="<DTQuantityStepper value onChange min max />" />
</Section>
<Section title="Filter Header" description="Thick top border accent. Active state switches to secondary color.">
<div style={{ maxWidth: 400 }}>
<button className="dt-filter-header" type="button">FILTER CATEGORY</button>
<button className="dt-filter-header active" type="button">ACTIVE FILTER</button>
</div>
<CodeLabel text=".dt-filter-header | .dt-filter-header.active" />
</Section>
<Section title="Menu Items" description="Beveled filter menu items with active state and level indentation.">
<div style={{ maxWidth: 300 }}>
{['All Products', 'NFC Implants', 'RFID Tags', 'Accessories', 'Lab Products'].map((name, i) => (
<button
key={name}
className={`dt-menu-item${i === 0 ? ' active' : ''}${i === 4 ? ' mode-warning' : ''}`}
style={(i === 2 || i === 3) ? { '--dt-menu-level': '1' } as React.CSSProperties : undefined}
type="button"
>
{name}
</button>
))}
</div>
<CodeLabel text=".dt-menu-item | .active | --dt-menu-level: 1" />
</Section>
</>
);
}