688a18af22
Foundation for the mobile-responsive-parity change. Adds: - useIsMobile() hook: single source of truth for the md:768px cut (SSR-safe) - MobileCardRow<T>: stacked card list for wide tables below md, with getRowId stable keys, primary field as title, optional onRowClick + actions slot - SheetForm: full-height form host (h-[100dvh], flex column, sticky header + footer via flex not position:sticky) for mobile edit flows - HoverEditButton: mobile prop (default 'always') -- always visible below md, hover-revealed at md+; desktop aesthetic preserved - .mobile-touch-target CSS utility: 44x44 min hit area below md (WCAG 2.5.5) - App.tsx refactored to use useIsMobile(); shell behavior unchanged Tests cover primary/field rendering, onRowClick, actions slot, empty rows, no-primary, stable keys (no duplicate-key warning), and all SheetForm interactions. 86 tests pass; lint/build green. MobileCardRow key strategy: uses getRowId when provided (falls back to index); per design §trade-offs, fields are declared per-table to prioritize by mobile importance rather than auto-derived from column defs. Refs openspec/changes/mobile-responsive-parity/ (design §Shared primitives, spec R1/R5/R6, tasks slice 1).
119 lines
3.4 KiB
CSS
119 lines
3.4 KiB
CSS
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
|
|
@import "tailwindcss";
|
|
|
|
@theme {
|
|
--font-sans: 'Inter', ui-sans-serif, system-ui, sans-serif;
|
|
|
|
--color-background: #fafafa;
|
|
--color-foreground: #0f172a;
|
|
--color-card: #ffffff;
|
|
--color-card-foreground: #0f172a;
|
|
--color-popover: #ffffff;
|
|
--color-popover-foreground: #0f172a;
|
|
--color-primary: #4f8cff;
|
|
--color-primary-foreground: #ffffff;
|
|
--color-secondary: #f1f5f9;
|
|
--color-secondary-foreground: #0f172a;
|
|
--color-muted: #f1f5f9;
|
|
--color-muted-foreground: #64748b;
|
|
--color-accent: #f1f5f9;
|
|
--color-accent-foreground: #0f172a;
|
|
--color-destructive: #ef4444;
|
|
--color-destructive-foreground: #ffffff;
|
|
--color-border: #e2e8f0;
|
|
--color-input: #e2e8f0;
|
|
--color-ring: #4f8cff;
|
|
/* Status / Grafana-link semantic cues — single source of truth for Badges.
|
|
chart-1=info/brand, chart-2=success, chart-3=warning,
|
|
chart-4=destructive, chart-5=neutral-accent. */
|
|
--color-chart-1: #4f8cff;
|
|
--color-chart-2: #22c55e;
|
|
--color-chart-3: #f59e0b;
|
|
--color-chart-4: #ef4444;
|
|
--color-chart-5: #8b5cf6;
|
|
--radius: 0.625rem;
|
|
--color-sidebar-background: #fafafa;
|
|
--color-sidebar-foreground: #0f172a;
|
|
--color-sidebar-primary: #4f8cff;
|
|
--color-sidebar-primary-foreground: #ffffff;
|
|
--color-sidebar-accent: #f1f5f9;
|
|
--color-sidebar-accent-foreground: #0f172a;
|
|
--color-sidebar-border: #e2e8f0;
|
|
--color-sidebar-ring: #4f8cff;
|
|
}
|
|
|
|
.dark {
|
|
--color-background: #0f172a;
|
|
--color-foreground: #f8fafc;
|
|
--color-card: #1e293b;
|
|
--color-card-foreground: #f8fafc;
|
|
--color-popover: #1e293b;
|
|
--color-popover-foreground: #f8fafc;
|
|
--color-primary: #4f8cff;
|
|
--color-primary-foreground: #ffffff;
|
|
--color-secondary: #1e293b;
|
|
--color-secondary-foreground: #f8fafc;
|
|
--color-muted: #334155;
|
|
--color-muted-foreground: #94a3b8;
|
|
--color-accent: #334155;
|
|
--color-accent-foreground: #f8fafc;
|
|
--color-destructive: #ef4444;
|
|
--color-destructive-foreground: #ffffff;
|
|
--color-border: #334155;
|
|
--color-input: #334155;
|
|
--color-ring: #4f8cff;
|
|
/* Status / Grafana-link semantic cues — single source of truth for Badges.
|
|
chart-1=info/brand, chart-2=success, chart-3=warning,
|
|
chart-4=destructive, chart-5=neutral-accent. */
|
|
--color-chart-1: #4f8cff;
|
|
--color-chart-2: #22c55e;
|
|
--color-chart-3: #f59e0b;
|
|
--color-chart-4: #ef4444;
|
|
--color-chart-5: #8b5cf6;
|
|
--color-sidebar-background: #0f172a;
|
|
--color-sidebar-foreground: #f8fafc;
|
|
--color-sidebar-primary: #4f8cff;
|
|
--color-sidebar-primary-foreground: #ffffff;
|
|
--color-sidebar-accent: #334155;
|
|
--color-sidebar-accent-foreground: #f8fafc;
|
|
--color-sidebar-border: #334155;
|
|
--color-sidebar-ring: #4f8cff;
|
|
}
|
|
|
|
@layer base {
|
|
body {
|
|
background-color: var(--color-background);
|
|
color: var(--color-foreground);
|
|
font-family: var(--font-sans);
|
|
}
|
|
}
|
|
|
|
html,
|
|
body,
|
|
#root {
|
|
margin: 0;
|
|
width: 100%;
|
|
min-height: 100%;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/*
|
|
* Mobile touch-target utility (spec R6.1).
|
|
*
|
|
* Applies a 44x44px minimum hit area to interactive elements ONLY below the
|
|
* `md:` (768px) breakpoint, satisfying WCAG 2.5.5 / Apple HIG on touch devices.
|
|
* At md+ the class is inert so desktop sizing is not regressed. Pages sprinkle
|
|
* this on icon buttons, checkboxes, switches, and row taps. See OpenSpec
|
|
* change `mobile-responsive-parity`, design §`mobile-touch-target`.
|
|
*/
|
|
@media (max-width: 767px) {
|
|
.mobile-touch-target {
|
|
min-height: 44px;
|
|
min-width: 44px;
|
|
}
|
|
}
|