From 8a8d4d4adc46fb0bac5944e70e9d60fc358df077 Mon Sep 17 00:00:00 2001 From: michael Date: Thu, 5 Mar 2026 16:13:23 -0800 Subject: [PATCH] Improve showcase pages: drawers, modals, badges, and Vite caching fix - DTDrawer: storefront-matching dual-element bevel border, slide-in/out animations from correct edge, 99vh height, bold 2em header, box shadow - DTModal: interactive demos on Bevels page with all 5 mode variants - Badges: solid color fill with contrasting text (black on dark, white on light) instead of transparent fill with colored text - Animations: add dt-slide-right and dt-slide-left keyframes for drawers - Bevels page: remove trash "Button Bevels", add interactive modal/drawer demos, fix media frame to use real images with proper bevel styling - Advanced Cards: remove redundant media frame sections, rename "Menu Items" to "Buttons", remove DTButton/dt-btn references - Forms page: rename "Menu Items" to "Buttons" - Vite config: exclude design system packages from optimizeDeps pre-bundling and watch dist directories to prevent stale CSS during development Co-Authored-By: Claude Opus 4.6 --- packages/react/src/components/DTDrawer.tsx | 139 +++++++++++++----- .../desktop/src/renderer/pages/BevelsPage.tsx | 84 ++++++----- .../src/renderer/pages/CardsAdvancedPage.tsx | 51 +------ .../desktop/src/renderer/pages/FormsPage.tsx | 2 +- packages/showcase/desktop/vite.config.ts | 12 ++ packages/web/src/components/animations.css | 10 ++ packages/web/src/components/bevels.css | 58 ++++++-- 7 files changed, 217 insertions(+), 139 deletions(-) diff --git a/packages/react/src/components/DTDrawer.tsx b/packages/react/src/components/DTDrawer.tsx index 8cde678..832d2ab 100644 --- a/packages/react/src/components/DTDrawer.tsx +++ b/packages/react/src/components/DTDrawer.tsx @@ -1,15 +1,24 @@ /** * DTDrawer — Sliding side panel with beveled edges. * + * Matches the dt-shopify-storefront Aside pattern: + * - Outer colored shell (mode color) with beveled clip-path + * - Inner dark surface with inset bevel clip-path (creates colored border) + * - Colored header bar with bold heading + close button + * - Scrollable content area + * - Slides in and out from the correct edge + * * CSS reference: bevels.css .dt-bevel-drawer-right, .dt-bevel-drawer-left */ -import { useEffect, useCallback, type ReactNode, type CSSProperties } from 'react'; +import { useEffect, useState, useCallback, useRef, type ReactNode, type CSSProperties } from 'react'; import { createPortal } from 'react-dom'; import type { DTVariant } from '@dangerousthings/tokens'; import { cx } from '../utils/cx'; import { getVariantClass } from '../utils/variantClasses'; +const DURATION = 200; + interface DTDrawerProps { visible: boolean; onDismiss: () => void; @@ -36,6 +45,30 @@ export function DTDrawer({ className, style, }: DTDrawerProps) { + const [mounted, setMounted] = useState(false); + const [closing, setClosing] = useState(false); + const timerRef = useRef>(); + + // Open: mount immediately + useEffect(() => { + if (visible) { + setClosing(false); + setMounted(true); + } + }, [visible]); + + // Close: play exit animation, then unmount + useEffect(() => { + if (!visible && mounted && !closing) { + setClosing(true); + timerRef.current = setTimeout(() => { + setMounted(false); + setClosing(false); + }, DURATION); + } + return () => clearTimeout(timerRef.current); + }, [visible, mounted, closing]); + const handleKeyDown = useCallback( (e: KeyboardEvent) => { if (e.key === 'Escape') onDismiss(); @@ -44,16 +77,21 @@ export function DTDrawer({ ); useEffect(() => { - if (visible) { + if (mounted && !closing) { document.addEventListener('keydown', handleKeyDown); return () => document.removeEventListener('keydown', handleKeyDown); } - }, [visible, handleKeyDown]); + }, [mounted, closing, handleKeyDown]); - if (!visible) return null; + if (!mounted) return null; const bevelClass = position === 'right' ? 'dt-bevel-drawer-right' : 'dt-bevel-drawer-left'; + const innerBevelClass = position === 'right' ? 'dt-bevel-drawer-right-inner' : 'dt-bevel-drawer-left-inner'; const widthValue = typeof width === 'number' ? `${width}px` : width; + const varCSSVar = getVariantCSSVar(headingVariant); + + // Slide direction for exit: reverse of entry + const slideOut = position === 'right' ? 'translateX(100%)' : 'translateX(-100%)'; return createPortal(
{/* Backdrop */}
- {/* Panel */} + {/* Outer shell */}
- {/* Header */} + {/* Inner surface */}
- {heading} - -
- {/* Content */} -
- {children} + height: 64, + padding: '0 1em', + background: `var(${varCSSVar}, var(--color-primary))`, + color: 'var(--color-bg)', + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + fontWeight: 900, + fontSize: '2em', + letterSpacing: '0.05em', + textTransform: 'uppercase', + borderBottom: '1px solid var(--color-bg)', + }}> + {heading} + +
+ {/* Content */} +
+ {children} +
, diff --git a/packages/showcase/desktop/src/renderer/pages/BevelsPage.tsx b/packages/showcase/desktop/src/renderer/pages/BevelsPage.tsx index 18901fa..8aa6cdb 100644 --- a/packages/showcase/desktop/src/renderer/pages/BevelsPage.tsx +++ b/packages/showcase/desktop/src/renderer/pages/BevelsPage.tsx @@ -1,10 +1,14 @@ -import { DTCard, DTMediaFrame } from '@dangerousthings/react'; +import { useState } from 'react'; +import { DTCard, DTModal, DTDrawer } from '@dangerousthings/react'; import type { DTVariant } from '@dangerousthings/tokens'; import { Section, Row, CodeLabel } from '../components/Section'; const modes: DTVariant[] = ['normal', 'emphasis', 'warning', 'success', 'other']; export function BevelsPage() { + const [modalVariant, setModalVariant] = useState(null); + const [drawerSide, setDrawerSide] = useState<'right' | 'left' | null>(null); + return ( <>

Bevels

@@ -21,55 +25,59 @@ export function BevelsPage() { -
+
- - - - - -
- -
- - Default - Success - Error - Warning - Info + DEFAULT + IN STOCK + SOLD OUT + LAB + NFC
-
- -
- MEDIA FRAME +
+
+
+
- - -
- -
-
-
-
Modal Content
-
Large dual bottom bevels
+
+
+
- +
-
+
-
- RIGHT -
-
- LEFT -
+ {modes.map(mode => ( + + ))}
- + + setModalVariant(null)} variant={modalVariant ?? 'normal'} title={`${(modalVariant ?? 'normal').toUpperCase()} MODAL`}> +

This is a {modalVariant} modal with beveled card shape, backdrop blur, and scale-in animation.

+

Click the backdrop or press Escape to dismiss.

+
+
+ +
+ + + + + + setDrawerSide(null)} position={drawerSide ?? 'right'} heading={`${(drawerSide ?? 'right').toUpperCase()} DRAWER`} headingVariant={drawerSide === 'left' ? 'other' : 'emphasis'}> +

Sliding panel from the {drawerSide} edge with beveled corners and backdrop blur.

+

Click the backdrop, press Escape, or click ✕ to dismiss.

+
diff --git a/packages/showcase/desktop/src/renderer/pages/CardsAdvancedPage.tsx b/packages/showcase/desktop/src/renderer/pages/CardsAdvancedPage.tsx index 1250c22..55d8171 100644 --- a/packages/showcase/desktop/src/renderer/pages/CardsAdvancedPage.tsx +++ b/packages/showcase/desktop/src/renderer/pages/CardsAdvancedPage.tsx @@ -1,13 +1,12 @@ import { createElement, useState, type CSSProperties } from 'react'; import { DTCard, - DTButton, DTStaggerContainer, DTFeatureLegend, } from '@dangerousthings/react'; import type { DTFeatureItem } from '@dangerousthings/react'; import type { DTVariant } from '@dangerousthings/tokens'; -import { Section, Row, CodeLabel } from '../components/Section'; +import { Section, CodeLabel } from '../components/Section'; // Feature icons from dt-shopify-storefront import { @@ -91,7 +90,7 @@ export function CardsAdvancedPage() {
-
+
{[ { label: 'LAB', mode: 'warning' as DTVariant, img: 'https://images.unsplash.com/photo-1526374965328-7f61d4dc18c5?w=400&h=400&fit=crop' }, @@ -106,52 +105,10 @@ export function CardsAdvancedPage() { ))}
- - -

- Also works on beveled media frames: -

-
- {[ - { label: 'LAB', mode: 'warning' as DTVariant, img: 'https://images.unsplash.com/photo-1526374965328-7f61d4dc18c5?w=400&h=400&fit=crop' }, - { label: 'BUNDLE', mode: 'other' as DTVariant, img: 'https://images.unsplash.com/photo-1518770660439-4636190af475?w=400&h=400&fit=crop' }, - { label: 'NFC', mode: 'normal' as DTVariant, img: 'https://images.unsplash.com/photo-1550751827-4bd374c3f58b?w=400&h=400&fit=crop' }, - ].map(badge => ( -
- - {badge.label} -
- ))} -
- - -

- Missing image placeholder (no img element): -

-
- {(['warning', 'other', 'normal'] as DTVariant[]).map(mode => ( -
- ))} -
- +
-
- - {modes.map(mode => ( - {mode.toUpperCase()} - ))} - - - - {modes.map(mode => ( - {mode.toUpperCase()} SEL - ))} - - -
- -
+
{['All Products', 'NFC Implants', 'RFID Tags', 'Accessories', 'Lab Products'].map((item, i) => (
-
+
{['All Products', 'NFC Implants', 'RFID Tags', 'Accessories', 'Lab Products'].map((name, i) => (