diff --git a/packages/react/src/components/DTFeatureLegend.tsx b/packages/react/src/components/DTFeatureLegend.tsx index b9a9303..3964717 100644 --- a/packages/react/src/components/DTFeatureLegend.tsx +++ b/packages/react/src/components/DTFeatureLegend.tsx @@ -1,20 +1,25 @@ /** - * DTFeatureLegend — Grid of product feature icons with rotated labels. + * DTFeatureLegend — Interactive grid of product feature icons with rotated labels. * - * CSS reference: feature-legend.css .dt-feature-legend, .dt-feature-legend-header, - * .dt-feature-legend-grid, .dt-feature-legend-item, .dt-feature-supported, etc. + * Matches dt-shopify-storefront UseCaseLegend: header bar with hover details, + * rotated vertical labels (above for row 0, below for row 1), ? toggle, + * bordered grid with dark cell backgrounds, and pulse-on-hover icons. + * + * CSS reference: feature-legend.css */ -import type { ReactNode, CSSProperties } from 'react'; +import { useState, type ReactNode, type CSSProperties } from 'react'; import type { DTVariant } from '@dangerousthings/tokens'; import { cx } from '../utils/cx'; -import { getVariantClass, featureStateToVariant } from '../utils/variantClasses'; +import { getVariantClass } from '../utils/variantClasses'; export interface DTFeatureItem { key: string; name: string; icon: ReactNode; state: 'supported' | 'disabled' | 'unsupported'; + /** Optional detail text shown in the header on hover */ + detail?: string; } const stateClassMap: Record = { @@ -32,6 +37,8 @@ interface DTFeatureLegendProps { columns?: number; /** Icon size in px @default 42 */ iconSize?: number; + /** Show rotated labels initially @default true */ + showLabels?: boolean; className?: string; style?: CSSProperties; } @@ -42,35 +49,93 @@ export function DTFeatureLegend({ variant = 'normal', columns = 5, iconSize = 42, + showLabels: initialShowLabels = true, className, style, }: DTFeatureLegendProps) { - // Suppress unused import warning — featureStateToVariant is available for consumers - void featureStateToVariant; + const [showLabels, setShowLabels] = useState(initialShowLabels); + const [hoveredFeature, setHoveredFeature] = useState(null); + + const hoveredItem = hoveredFeature + ? features.find(f => f.key === hoveredFeature) + : null; + + const rowCount = Math.ceil(features.length / columns); + const hasBottomRow = rowCount >= 2; return (
+ + {/* Header bar — title + hovered feature detail + ? toggle */} {title && ( -
{title}
- )} -
- {features.map(feature => ( -
-
- {feature.icon} +
+
+
{title}
+
+ {hoveredItem ? ( + + {hoveredItem.name}{hoveredItem.detail ? ': ' : ''} + {hoveredItem.detail && {hoveredItem.detail}} + + ) : ( + + Hover a feature for details + + )}
-
{feature.name}
- ))} + +
+ )} + + {/* Icon grid with border */} +
+
+ {features.map((feature, index) => { + const row = Math.floor(index / columns); + const labelPosition = rowCount >= 2 ? (row === 0 ? 'above' : 'below') : 'above'; + + return ( +
setHoveredFeature(feature.key)} + onMouseLeave={() => setHoveredFeature(null)}> + + {/* Rotated vertical label — always in DOM, visibility via CSS */} +
+ {feature.name} +
+ +
+ {feature.icon} +
+
+ ); + })} +
); diff --git a/packages/react/src/components/DTRadioGroup.tsx b/packages/react/src/components/DTRadioGroup.tsx index 2f47896..a8a5827 100644 --- a/packages/react/src/components/DTRadioGroup.tsx +++ b/packages/react/src/components/DTRadioGroup.tsx @@ -1,7 +1,10 @@ /** * DTRadioGroup — Hexagonal radio buttons. * - * CSS reference: forms-dt.css input[type="radio"], .dt-radio-option + * Uses a custom span for the hexagon indicator since ::before pseudo-elements + * on are unreliable in Chromium/Electron. + * + * CSS reference: forms-dt.css .dt-radio-hex, .dt-radio-option */ import { useId, type CSSProperties } from 'react'; @@ -39,20 +42,27 @@ export function DTRadioGroup({ className={cx('dt-radio-group', className)} style={{ display: 'flex', flexDirection: 'column', gap: '4px', ...style }} role="radiogroup"> - {options.map(option => ( - - ))} + {options.map(option => { + const checked = value === option.value; + return ( + + ); + })}
); } diff --git a/packages/showcase/desktop/src/renderer/pages/AnimationsPage.tsx b/packages/showcase/desktop/src/renderer/pages/AnimationsPage.tsx index 52d3c9b..3ebf6db 100644 --- a/packages/showcase/desktop/src/renderer/pages/AnimationsPage.tsx +++ b/packages/showcase/desktop/src/renderer/pages/AnimationsPage.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useState, useEffect, useRef } from 'react'; import { DTCard, DTStaggerContainer } from '@dangerousthings/react'; import { Section, Row, CodeLabel } from '../components/Section'; @@ -25,6 +25,69 @@ function AnimBox({ className, label }: { className: string; label: string }) { ); } +const VARIANTS = ['normal', 'emphasis', 'warning', 'success', 'other'] as const; + +function ProgressBarDemo() { + const [progress, setProgress] = useState([0, 0, 0, 0, 0]); + const intervalRef = useRef | null>(null); + const [running, setRunning] = useState(false); + + const animate = () => { + // Reset then animate up + setProgress([0, 0, 0, 0, 0]); + setRunning(true); + let tick = 0; + if (intervalRef.current) clearInterval(intervalRef.current); + intervalRef.current = setInterval(() => { + tick++; + setProgress(prev => + prev.map((_, i) => Math.min(100, Math.round(tick * (1.5 + i * 0.4)))) + ); + if (tick > 80) { + if (intervalRef.current) clearInterval(intervalRef.current); + setRunning(false); + } + }, 40); + }; + + useEffect(() => { + // Auto-run on mount + const t = setTimeout(animate, 500); + return () => { + clearTimeout(t); + if (intervalRef.current) clearInterval(intervalRef.current); + }; + }, []); + + return ( +
+
+ {VARIANTS.map((v, i) => ( + +
+ Progress fills the left edge from bottom to top +
+
+ ))} +
+ +
+ ); +} + export function AnimationsPage() { const [entranceKey, setEntranceKey] = useState(0); const [staggerKey, setStaggerKey] = useState(0); @@ -126,6 +189,11 @@ export function AnimationsPage() { +
+ + +
+
createElement(C, { style: { fontSize: '2rem' } }); // Full chip feature legend (9 features — from storefront UseCaseLegend) +// detail text simulates what the storefront shows for an NExT implant const chipFeatures: DTFeatureItem[] = [ - { key: 'smartphone', name: 'Smartphone', icon: ico(MdOutlinePhonelinkRing), state: 'supported' }, - { key: 'access_control', name: 'Access Control', icon: ico(MdOutlineVpnKey), state: 'supported' }, - { key: 'digital_security', name: 'Digital Security', icon: ico(FaUserShield), state: 'supported' }, - { key: 'cryptography', name: 'Cryptography', icon: ico(LuBinary), state: 'unsupported' }, - { key: 'data_sharing', name: 'Data Sharing', icon: ico(MdOutlineMobileScreenShare), state: 'supported' }, - { key: 'payment', name: 'Payment', icon: ico(MdOutlineCreditCard), state: 'disabled' }, - { key: 'magic', name: 'UID Magic', icon: ico(MdOutlineCopyAll), state: 'supported' }, - { key: 'illumination', name: 'Illumination', icon: ico(MdOutlineLightbulb), state: 'unsupported' }, - { key: 'temperature', name: 'Temperature', icon: ico(MdOutlineThermostat), state: 'unsupported' }, + { key: 'smartphone', name: 'Smartphone', icon: ico(MdOutlinePhonelinkRing), state: 'supported', detail: 'Full NFC smartphone support' }, + { key: 'access_control', name: 'Access Control', icon: ico(MdOutlineVpnKey), state: 'supported', detail: 'DESFire, MIFARE Classic, iCLASS' }, + { key: 'digital_security', name: 'Digital Security', icon: ico(FaUserShield), state: 'supported', detail: 'FIDO2 / WebAuthn' }, + { key: 'cryptography', name: 'Cryptography', icon: ico(LuBinary), state: 'unsupported', detail: 'Not Supported' }, + { key: 'data_sharing', name: 'Data Sharing', icon: ico(MdOutlineMobileScreenShare), state: 'supported', detail: 'NDEF records, vCard, URL' }, + { key: 'payment', name: 'Payment', icon: ico(MdOutlineCreditCard), state: 'disabled', detail: 'Apex required' }, + { key: 'magic', name: 'Magic', icon: ico(MdOutlineCopyAll), state: 'supported', detail: 'Gen2 Magic UID' }, + { key: 'Illumination', name: 'Illumination', icon: ico(MdOutlineLightbulb), state: 'unsupported', detail: 'None' }, + { key: 'temperature', name: 'Sensors', icon: ico(MdOutlineThermostat), state: 'unsupported', detail: 'None' }, ]; // Full biomagnet feature legend (4 features — from storefront MagnetUseCaseLegend) const magnetFeatures: DTFeatureItem[] = [ - { key: 'sensing', name: 'Sensing', icon: ico(MdOutlineSensors), state: 'supported' }, - { key: 'lifting', name: 'Lifting', icon: ico(MdOutlineFitbit), state: 'supported' }, - { key: 'haptics', name: 'Haptics', icon: ico(MdOutlineVibration), state: 'supported' }, - { key: 'polarity', name: 'Polarity Detection', icon: ico(MdOutlineExplore), state: 'unsupported' }, + { key: 'sensing', name: 'Sensing', icon: ico(MdOutlineSensors), state: 'supported', detail: 'Electromagnetic field detection' }, + { key: 'lifting', name: 'Lifting', icon: ico(MdOutlineFitbit), state: 'supported', detail: '2.1 kg lifting force' }, + { key: 'haptics', name: 'Haptics', icon: ico(MdOutlineVibration), state: 'supported', detail: 'Tactile vibration feedback' }, + { key: 'polarity', name: 'Polarity Detection', icon: ico(MdOutlineExplore), state: 'unsupported', detail: 'Not Supported' }, ]; // Full aesthetic feature legend (2 features — from storefront AestheticUseCaseLegend) const aestheticFeatures: DTFeatureItem[] = [ - { key: 'illumination', name: 'Illumination', icon: ico(MdLightbulbOutline), state: 'supported' }, - { key: 'prominence', name: 'Prominence', icon: ico(MdOutlineVisibility), state: 'supported' }, + { key: 'illumination', name: 'Illumination', icon: ico(MdLightbulbOutline), state: 'supported', detail: 'LED: Red, Green, Blue, White' }, + { key: 'prominence', name: 'Prominence', icon: ico(MdOutlineVisibility), state: 'supported', detail: 'High visibility under skin' }, ]; export function CardsAdvancedPage() { @@ -108,30 +109,36 @@ export function CardsAdvancedPage() {
-
+
- {['All Products', 'NFC Implants', 'RFID Tags', 'Accessories', 'Lab Products'].map((item, i) => ( + {[ + { name: 'All Products', cls: ' active', pad: 0 }, + { name: 'NFC Implants', cls: '', pad: 0 }, + { name: 'RFID Tags', cls: '', pad: 32 }, + { name: 'Accessories', cls: '', pad: 32 }, + { name: 'Lab Products', cls: ' mode-warning', pad: 0 }, + ].map(item => ( ))}
- +
-
- +
+
- +
- +
- +
diff --git a/packages/showcase/desktop/src/renderer/pages/FormsPage.tsx b/packages/showcase/desktop/src/renderer/pages/FormsPage.tsx index ee436f8..2731486 100644 --- a/packages/showcase/desktop/src/renderer/pages/FormsPage.tsx +++ b/packages/showcase/desktop/src/renderer/pages/FormsPage.tsx @@ -102,20 +102,26 @@ export function FormsPage() {
-
+
- {['All Products', 'NFC Implants', 'RFID Tags', 'Accessories', 'Lab Products'].map((name, i) => ( + {[ + { name: 'All Products', cls: ' active', pad: 0 }, + { name: 'NFC Implants', cls: '', pad: 0 }, + { name: 'RFID Tags', cls: '', pad: 32 }, + { name: 'Accessories', cls: '', pad: 32 }, + { name: 'Lab Products', cls: ' mode-warning', pad: 0 }, + ].map(item => ( ))}
- +
); diff --git a/packages/showcase/desktop/src/renderer/pages/GlowsPage.tsx b/packages/showcase/desktop/src/renderer/pages/GlowsPage.tsx deleted file mode 100644 index a87b7f7..0000000 --- a/packages/showcase/desktop/src/renderer/pages/GlowsPage.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { DTCard } from '@dangerousthings/react'; -import { Section, Row, CodeLabel } from '../components/Section'; - -export function GlowsPage() { - return ( - <> -

Glows

-

Neon drop-shadow and text-shadow effects. Active on the DT brand.

- -
- - - - - -
- - - - -
- -
- - - Hover this link for text glow - - - -
- -
- - {(['normal', 'emphasis', 'warning', 'success', 'other'] as const).map(mode => ( - - ))} - - -
- -
-
- {'$ dt-web-theme --install\n> Installing design tokens...\n> Applying cyberpunk aesthetic...\n> Done. Welcome to the future.'} -
- -
- -
- -
Cards get a drop-shadow glow on hover.
-
- -
- -
- - -
- -
- -
.dt-glow
-
.dt-glow-strong
-
- - -
.dt-glow-inset
-
.dt-text-glow
-
- -
- - ); -} diff --git a/packages/showcase/desktop/src/renderer/pages/HomePage.tsx b/packages/showcase/desktop/src/renderer/pages/HomePage.tsx index ab36b4e..3a459c7 100644 --- a/packages/showcase/desktop/src/renderer/pages/HomePage.tsx +++ b/packages/showcase/desktop/src/renderer/pages/HomePage.tsx @@ -4,7 +4,6 @@ import { Section, CodeLabel } from '../components/Section'; const categories: { hash: string; title: string; desc: string; mode: DTVariant; count: number }[] = [ { hash: 'bevels', title: 'Bevels', desc: 'Angular clip-path patterns — cards, buttons, badges, media frames, modals, drawers', mode: 'normal', count: 8 }, - { hash: 'glows', title: 'Glows', desc: 'Neon drop-shadow and text-shadow effects for the DT brand', mode: 'emphasis', count: 6 }, { hash: 'forms', title: 'Forms', desc: 'Text inputs, checkboxes, switches, radios, progress bars, accordions, steppers', mode: 'success', count: 7 }, { hash: 'animations', title: 'Animations', desc: 'Entrance animations, stagger containers, transition utilities, scrollbar styling', mode: 'other', count: 5 }, { hash: 'cards-advanced', title: 'Advanced Cards', desc: 'Card color modes, progress bars, badge overlays, interactive bevel buttons, feature legend', mode: 'warning', count: 6 }, diff --git a/packages/web/package.json b/packages/web/package.json index 3a35460..38c42a3 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -28,6 +28,7 @@ "main": "dist/index.css", "exports": { ".": "./dist/index.css", + "./dist/index.css": "./dist/index.css", "./tokens/*": "./dist/tokens/*", "./components/*": "./dist/components/*", "./fonts/*": "./dist/fonts/*", diff --git a/packages/web/src/components/bevels.css b/packages/web/src/components/bevels.css index 46e916b..526fb2d 100644 --- a/packages/web/src/components/bevels.css +++ b/packages/web/src/components/bevels.css @@ -450,14 +450,13 @@ /* ============================================================================ Card Color Modes — per-instance color overrides Sets --dt-card-color, --dt-card-color-selected, --dt-card-color-rgb, - --dt-glow-color, and --accent-mode for use by all card sub-components. + and --accent-mode for use by all card sub-components. Source: dt-shopify-storefront .mode-* classes ============================================================================ */ [data-brand="dt"] .mode-normal { --dt-card-color: var(--mode-normal); --dt-card-color-rgb: var(--mode-normal-rgb); --dt-card-color-selected: var(--mode-normal-selected); - --dt-glow-color: var(--mode-normal); --accent-mode: var(--mode-emphasis); } @@ -465,7 +464,6 @@ --dt-card-color: var(--mode-emphasis); --dt-card-color-rgb: var(--mode-emphasis-rgb); --dt-card-color-selected: var(--mode-emphasis-selected); - --dt-glow-color: var(--mode-emphasis); --accent-mode: var(--mode-normal); } @@ -473,7 +471,6 @@ --dt-card-color: var(--mode-warning); --dt-card-color-rgb: var(--mode-warning-rgb); --dt-card-color-selected: var(--mode-warning-selected); - --dt-glow-color: var(--mode-warning); --accent-mode: var(--mode-emphasis); } @@ -481,7 +478,6 @@ --dt-card-color: var(--mode-success); --dt-card-color-rgb: var(--mode-success-rgb); --dt-card-color-selected: var(--mode-success-selected); - --dt-glow-color: var(--mode-success); --accent-mode: var(--mode-emphasis); } @@ -489,7 +485,6 @@ --dt-card-color: var(--mode-other); --dt-card-color-rgb: var(--mode-other-rgb); --dt-card-color-selected: var(--mode-other-selected); - --dt-glow-color: var(--mode-other); --accent-mode: var(--mode-normal); } diff --git a/packages/web/src/components/feature-legend.css b/packages/web/src/components/feature-legend.css index dfaa936..c60fcf4 100644 --- a/packages/web/src/components/feature-legend.css +++ b/packages/web/src/components/feature-legend.css @@ -2,55 +2,184 @@ /* Source: dt-shopify-storefront UseCaseLegend component */ /* ============================================================================ - Feature Legend — icon grid with rotated labels + Feature Legend — interactive icon grid with rotated labels, hover details, + ? toggle, bordered grid with dark cell backgrounds. ============================================================================ */ .dt-feature-legend { display: flex; flex-direction: column; - gap: 0; } +/* ---- Header bar ---- */ .dt-feature-legend-header { - padding: 8px 16px; + display: flex; + flex-direction: row; background: var(--dt-card-color, var(--color-primary)); color: var(--color-bg); + transition: height 0.2s ease-out, opacity 0.2s ease-out; +} + +.dt-feature-legend-header-content { + flex: 1; + display: flex; + flex-direction: column; + padding: 8px 12px 6px; +} + +.dt-feature-legend-title { font-weight: 700; + font-size: 1.75rem; + line-height: 1.1; + color: var(--color-bg); +} + +.dt-feature-legend-detail { font-size: 0.875rem; - text-transform: uppercase; - letter-spacing: 0.05em; + margin-top: 2px; + min-height: 1.25em; +} + +.dt-feature-legend-detail .dt-feature-supported { color: var(--color-bg); } +.dt-feature-legend-detail .dt-feature-disabled { color: var(--color-bg); opacity: 0.7; } +.dt-feature-legend-detail .dt-feature-unsupported { color: #7f1d1d; } + +.dt-feature-legend-hint { + opacity: 0.5; +} + +/* ? toggle button on right edge */ +.dt-feature-legend-toggle { + display: flex; + justify-content: center; + align-items: center; + min-width: 30px; + background: var(--dt-card-color, var(--color-primary)); + color: var(--color-bg); + border: none; + font-weight: 700; + font-size: 1.25rem; + cursor: pointer; + transition: opacity 0.15s; +} + +.dt-feature-legend-toggle:hover { + opacity: 0.8; +} + +/* ---- Grid body ---- */ +.dt-feature-legend-body { + display: flex; + flex-direction: row; + overflow: hidden; } .dt-feature-legend-grid { display: flex; flex-wrap: wrap; - gap: 0; + justify-content: space-around; + flex: 1; + border: 2px solid var(--dt-card-color, var(--color-primary)); + padding-top: 8px; + padding-bottom: 8px; + overflow: visible; + transition: padding 0.3s ease-out; } +.dt-feature-legend-grid.with-labels { + padding-top: 160px; + padding-bottom: 8px; +} + +.dt-feature-legend-grid.with-labels.with-labels-bottom { + padding-bottom: 160px; +} + +/* ---- Grid item / cell ---- */ .dt-feature-legend-item { + position: relative; display: flex; flex-direction: column; align-items: center; - gap: 4px; + justify-content: center; padding: 8px 4px; - flex: 0 0 20%; /* 5 columns */ + background: var(--color-bg); + cursor: pointer; } +/* ---- Icon ---- */ .dt-feature-legend-icon { + display: flex; + align-items: center; + justify-content: center; font-size: 42px; line-height: 1; color: var(--dt-feature-color, var(--color-primary)); + transition: opacity 0.15s; } -.dt-feature-legend-label { - font-size: 0.75rem; +.dt-feature-legend-item:hover .dt-feature-legend-icon { + animation: dt-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; +} + +/* ---- Rotated vertical label ---- */ +.dt-feature-legend-rotated-label { + position: absolute; + left: 0; + right: 0; + display: flex; + justify-content: center; + padding: 8px 2px; + z-index: 1; + opacity: 0; + transition: opacity 0.3s ease-out 0.15s; /* delay so padding opens first */ + pointer-events: none; +} + +.dt-feature-legend-rotated-label.label-visible { + opacity: 1; + pointer-events: auto; +} + +.dt-feature-legend-rotated-label.label-above { + bottom: 100%; +} + +.dt-feature-legend-rotated-label.label-below { + top: 100%; +} + +.dt-feature-legend-rotated-label span { + writing-mode: vertical-rl; + transform: rotate(180deg); + color: var(--dt-feature-color, var(--color-primary)); + font-size: 1rem; font-weight: 600; - color: var(--dt-feature-color, var(--color-text-primary)); - text-align: center; - line-height: 1.2; - overflow-wrap: break-word; + white-space: nowrap; + padding: 4px 2px; } -/* Feature state color classes */ +/* ---- Feature state color classes ---- */ .dt-feature-supported { --dt-feature-color: var(--mode-normal, var(--color-primary)); } .dt-feature-disabled { --dt-feature-color: var(--mode-emphasis, var(--color-secondary)); } .dt-feature-unsupported { --dt-feature-color: var(--mode-warning, var(--color-error)); } + +/* ---- Variant header colors ---- */ +.mode-normal .dt-feature-legend-header, +.mode-normal .dt-feature-legend-toggle { background: var(--mode-normal, var(--color-primary)); } +.mode-normal .dt-feature-legend-grid { border-color: var(--mode-normal, var(--color-primary)); } + +.mode-emphasis .dt-feature-legend-header, +.mode-emphasis .dt-feature-legend-toggle { background: var(--mode-emphasis, var(--color-secondary)); } +.mode-emphasis .dt-feature-legend-grid { border-color: var(--mode-emphasis, var(--color-secondary)); } + +.mode-warning .dt-feature-legend-header, +.mode-warning .dt-feature-legend-toggle { background: var(--mode-warning, var(--color-error)); } +.mode-warning .dt-feature-legend-grid { border-color: var(--mode-warning, var(--color-error)); } + +.mode-success .dt-feature-legend-header, +.mode-success .dt-feature-legend-toggle { background: var(--mode-success, var(--color-accent)); } +.mode-success .dt-feature-legend-grid { border-color: var(--mode-success, var(--color-accent)); } + +.mode-other .dt-feature-legend-header, +.mode-other .dt-feature-legend-toggle { background: var(--mode-other, var(--color-other)); } +.mode-other .dt-feature-legend-grid { border-color: var(--mode-other, var(--color-other)); } diff --git a/packages/web/src/components/forms-dt.css b/packages/web/src/components/forms-dt.css index d1cb8b2..a406f3f 100644 --- a/packages/web/src/components/forms-dt.css +++ b/packages/web/src/components/forms-dt.css @@ -143,49 +143,38 @@ /* ============================================================================ Radio Button — Hexagonal indicator Matches RN DTRadioGroup: outlined hexagon with inner filled dot on check. - Outer hexagon is always stroked (accent border); inner dot appears on check. + Uses a custom span (.dt-radio-hex) since ::before on is unreliable. ============================================================================ */ -[data-brand="dt"] input[type="radio"] { - appearance: none; - -webkit-appearance: none; - display: grid; - place-content: center; +[data-brand="dt"] .dt-radio-hex { + position: relative; + display: inline-block; width: 22px; height: 22px; flex-shrink: 0; - margin: 0; - border: none; background: var(--color-primary); - cursor: pointer; clip-path: polygon( 50% 0%, 93% 25%, 93% 75%, 50% 100%, 7% 75%, 7% 25% ); transition: background var(--transition-fast); } -/* Inner surface — creates the outlined hexagon look (accent border + transparent center) */ -[data-brand="dt"] input[type="radio"]::before { - content: ''; +/* Inner surface — outlined hexagon look (accent border + dark center) */ +[data-brand="dt"] .dt-radio-hex-inner { position: absolute; inset: 2px; background: var(--color-bg); clip-path: polygon( 50% 0%, 93% 25%, 93% 75%, 50% 100%, 7% 75%, 7% 25% ); - transition: background var(--transition-fast); + transition: all var(--transition-fast); } -/* Checked: inner dot fills with accent color (smaller inset for the dot effect) */ -[data-brand="dt"] input[type="radio"]:checked::before { +/* Checked: inner dot fills with accent color (smaller inset) */ +[data-brand="dt"] .dt-radio-hex.checked .dt-radio-hex-inner { inset: 5px; background: var(--color-primary); } -[data-brand="dt"] input[type="radio"]:disabled { - opacity: 0.5; - cursor: not-allowed; -} - /* Radio group option container */ .dt-radio-option { display: flex; @@ -403,11 +392,6 @@ animation: dt-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; } -/* Nested level indentation */ -.dt-menu-item[style*="--dt-menu-level"] { - padding-left: calc(0.75rem + var(--dt-menu-level, 0) * 1rem); -} - /* Classic brand: rounded, thinner borders */ [data-brand="classic"] .dt-menu-item { border-top-width: 2px; diff --git a/packages/web/src/components/glows.css b/packages/web/src/components/glows.css deleted file mode 100644 index 808a0b3..0000000 --- a/packages/web/src/components/glows.css +++ /dev/null @@ -1,81 +0,0 @@ -/* dt-web-theme: Glow & Neon Effects */ -/* Source: dt-shopify-storefront glow patterns */ -/* */ -/* Elements with clip-path use filter: drop-shadow() instead of box-shadow */ -/* because clip-path clips box-shadow but filter follows the clipped shape. */ - -/* ============================================================================ - Button Glows — filter: drop-shadow (buttons have clip-path) - ============================================================================ */ -[data-brand="dt"] .btn-primary { - box-shadow: none; - filter: drop-shadow(0 0 10px rgba(var(--color-primary-rgb), 0.3)); -} - -[data-brand="dt"] .btn-primary:hover { - box-shadow: none; - filter: drop-shadow(0 0 15px rgba(var(--color-accent-rgb), 0.4)); -} - -[data-brand="dt"] .btn-secondary:hover { - filter: drop-shadow(0 0 8px rgba(var(--color-primary-rgb), 0.3)); -} - -[data-brand="dt"] .btn-danger { - box-shadow: none; - filter: drop-shadow(0 0 10px rgba(var(--color-error-rgb), 0.3)); -} - -[data-brand="dt"] .btn-danger:hover { - box-shadow: none; - filter: drop-shadow(0 0 15px rgba(var(--color-error-rgb), 0.4)); -} - -/* ============================================================================ - Link Glow - ============================================================================ */ -[data-brand="dt"] a:hover { - text-shadow: 0 0 8px var(--dt-glow-color, var(--color-primary)); -} - -/* ============================================================================ - Terminal Inset Glow (no clip-path, box-shadow OK) - ============================================================================ */ -[data-brand="dt"] .terminal { - box-shadow: inset 0 0 10px rgba(var(--color-accent-rgb), 0.05), - 0 0 10px rgba(var(--color-accent-rgb), 0.1); -} - -/* ============================================================================ - Card Hover Glow — filter: drop-shadow (cards have clip-path) - ============================================================================ */ -[data-brand="dt"] .card:hover, -[data-brand="dt"] .dt-bevel-card:hover { - filter: drop-shadow(0 0 8px rgba(var(--dt-card-color-rgb, var(--color-primary-rgb)), 0.3)); -} - -/* ============================================================================ - Input Focus Glow (no clip-path on inputs, box-shadow OK) - ============================================================================ */ -[data-brand="dt"] .input:focus { - box-shadow: 0 4px 0 1px var(--color-primary); -} - -/* ============================================================================ - Generic Glow Utilities - ============================================================================ */ -.dt-glow { - filter: drop-shadow(0 0 10px rgba(var(--color-primary-rgb), 0.3)); -} - -.dt-glow-strong { - filter: drop-shadow(0 0 15px rgba(var(--color-primary-rgb), 0.5)); -} - -.dt-glow-inset { - box-shadow: inset 0 0 10px rgba(var(--color-primary-rgb), 0.1); -} - -.dt-text-glow { - text-shadow: 0 0 8px currentColor; -} diff --git a/packages/web/src/index.css b/packages/web/src/index.css index 7fe49ec..3ec14d8 100644 --- a/packages/web/src/index.css +++ b/packages/web/src/index.css @@ -13,7 +13,6 @@ /* Component styles — DT visual identity */ @import './components/bevels.css'; -@import './components/glows.css'; @import './components/forms-dt.css'; @import './components/animations.css'; @import './components/scrollbar.css';