diff --git a/v2/guidelines/Guidelines.md b/v2/guidelines/Guidelines.md new file mode 100644 index 000000000..e01435ab4 --- /dev/null +++ b/v2/guidelines/Guidelines.md @@ -0,0 +1,458 @@ +# Data Station Dashboard Design Guidelines + +## Overview +This dashboard is designed for 7-inch capacitive touchscreen displays used in industrial/environmental monitoring stations. The interface prioritizes touch-friendly interactions, clear information hierarchy, and robust functionality for field use. + +--- + +## Design Language + +### Color Palette + +**Background Colors:** +- Primary Background: `bg-gray-900` - Main content areas +- Secondary Background: `bg-gray-950` - Sidebar, header, elevated surfaces +- Tertiary Background: `bg-gray-800` - Cards, input fields, nested elements + +**Accent Colors:** +- Primary Action: `bg-blue-600`, `hover:bg-blue-700` - Buttons, active states +- Success/Positive: `text-green-400` - Online status, calibrated sensors, positive values +- Warning: `text-yellow-400` - Pending states, warnings +- Error/Critical: `text-red-400` - Offline status, errors, delete actions +- Info: `text-blue-400` - Icons, informational highlights +- Data Values: `text-cyan-400`, `text-purple-400` - Different data categories + +**Text Colors:** +- Primary Text: `text-white` - Headings, labels +- Secondary Text: `text-gray-300` - Body text, menu items +- Tertiary Text: `text-gray-400` - Supporting information, metadata +- Disabled Text: `text-gray-500` - Disabled states + +**Border Colors:** +- Default Borders: `border-gray-700` - Cards, inputs, dividers + +### Typography + +**Font Sizes:** +- Page Headers: `text-2xl` (h1) +- Card Titles: `text-sm` to `text-base` +- Body Text: `text-sm` +- Metadata/Labels: `text-xs` +- Tiny Text: `text-[10px]` (for dense information) +- Monospace: Use `font-mono` for time, data values, file contents + +**Font Weights:** +- Bold: `font-bold` - Page headers, important labels +- Semibold: `font-semibold` - Card titles, emphasized values +- Normal: Default weight for body text + +### Spacing + +**Component Spacing:** +- Between major sections: `space-y-4` +- Within cards: `space-y-3` or `space-y-4` +- Compact spacing: `space-y-2` +- Card padding: `p-3` or `p-4` +- Grid gaps: `gap-3` or `gap-4` + +**Touch Targets:** +- Minimum button height: `h-14` (56px) for primary touch actions +- Standard button size: `size-lg` +- Navigation buttons: `h-14 w-14` (56x56px minimum) +- List items: `p-2` to `p-3` for adequate touch area + +--- + +## Navigation + +### Sidebar Navigation + +**Structure:** +- Collapsible sidebar with icon-only mode +- Width: `w-64` (expanded), `w-16` (collapsed) +- Always visible on left side +- Dark background (`bg-gray-950`) + +**Menu Hierarchy:** +- Primary menu items: Icon + Label +- Expandable items: Show chevron indicator +- Sub-menu items: Indented with `pl-11` +- Active state: `bg-blue-600 text-white` +- Hover state: `hover:bg-gray-800 hover:text-white` + +**Menu Items:** +1. HOME - Rainfall dashboard (default view) +2. GRAPH - Data visualization +3. UTILITY - Expandable with 10 sub-items +4. CALIBRATION - Sensor calibration +5. FLASH MEMORY - File manager +6. SETTING - System settings +7. LOGIN - Authentication + +### Page Navigation + +**No Traditional Scrollbars:** +- All scrollbars are hidden for touchscreen usability +- Use permanent Up/Down buttons in top-right corner +- Buttons: 56x56px, `bg-blue-600`, positioned `fixed top-20 right-4` +- Smooth scroll behavior with 300px increments + +**Routing:** +- Use React Router for multi-page navigation +- Route structure: `/` (home), `/graph`, `/utility/[setting]`, etc. +- URL updates on navigation for state management + +--- + +## UI Elements + +### Buttons + +**Primary Button:** +- Style: `bg-blue-600 hover:bg-blue-700 text-white` +- Use for: Main actions, saving, applying settings +- Size: Default or `size-lg` for touch + +**Secondary Button (Outline):** +- Style: `variant="outline" border-gray-700 text-gray-300 hover:bg-gray-800` +- Use for: Alternative actions, cancel, secondary functions + +**Destructive Button:** +- Style: `variant="outline" border-red-700 text-red-400 hover:bg-red-950` +- Use for: Delete, reset, dangerous actions + +**Icon Buttons:** +- Size: Minimum 44x44px for touch +- Include text labels when space allows +- Use Lucide React icons consistently + +### Cards + +**Standard Card:** +```tsx + + + Title + + + {/* Content */} + + +``` + +**Data Display Card:** +- Use color-coded backgrounds for data categories +- Format: Value (large) + Unit (small) +- Example: `text-4xl font-bold text-blue-400` for values + +### Form Elements + +**Input Fields:** +- Style: `bg-gray-800 border-gray-700 text-white` +- Labels: `text-gray-300` above inputs +- Grid layout for multiple fields: `grid grid-cols-2 gap-4` + +**Switches:** +- Use for enable/disable settings +- Layout: Label on left, switch on right +- Container: `flex items-center justify-between p-3 bg-gray-800 rounded` + +**Dropdowns:** +- Style: `bg-gray-800 border border-gray-700 rounded text-white` +- Use native ` + ); +} + +export { Input }; diff --git a/v2/src/app/components/ui/label.tsx b/v2/src/app/components/ui/label.tsx new file mode 100644 index 000000000..af250e577 --- /dev/null +++ b/v2/src/app/components/ui/label.tsx @@ -0,0 +1,24 @@ +"use client"; + +import * as React from "react"; +import * as LabelPrimitive from "@radix-ui/react-label"; + +import { cn } from "./utils"; + +function Label({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { Label }; diff --git a/v2/src/app/components/ui/menubar.tsx b/v2/src/app/components/ui/menubar.tsx new file mode 100644 index 000000000..7d7ac86ff --- /dev/null +++ b/v2/src/app/components/ui/menubar.tsx @@ -0,0 +1,276 @@ +"use client"; + +import * as React from "react"; +import * as MenubarPrimitive from "@radix-ui/react-menubar"; +import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"; + +import { cn } from "./utils"; + +function Menubar({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function MenubarMenu({ + ...props +}: React.ComponentProps) { + return ; +} + +function MenubarGroup({ + ...props +}: React.ComponentProps) { + return ; +} + +function MenubarPortal({ + ...props +}: React.ComponentProps) { + return ; +} + +function MenubarRadioGroup({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function MenubarTrigger({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function MenubarContent({ + className, + align = "start", + alignOffset = -4, + sideOffset = 8, + ...props +}: React.ComponentProps) { + return ( + + + + ); +} + +function MenubarItem({ + className, + inset, + variant = "default", + ...props +}: React.ComponentProps & { + inset?: boolean; + variant?: "default" | "destructive"; +}) { + return ( + + ); +} + +function MenubarCheckboxItem({ + className, + children, + checked, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ); +} + +function MenubarRadioItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ); +} + +function MenubarLabel({ + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + ); +} + +function MenubarSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function MenubarShortcut({ + className, + ...props +}: React.ComponentProps<"span">) { + return ( + + ); +} + +function MenubarSub({ + ...props +}: React.ComponentProps) { + return ; +} + +function MenubarSubTrigger({ + className, + inset, + children, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + {children} + + + ); +} + +function MenubarSubContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { + Menubar, + MenubarPortal, + MenubarMenu, + MenubarTrigger, + MenubarContent, + MenubarGroup, + MenubarSeparator, + MenubarLabel, + MenubarItem, + MenubarShortcut, + MenubarCheckboxItem, + MenubarRadioGroup, + MenubarRadioItem, + MenubarSub, + MenubarSubTrigger, + MenubarSubContent, +}; diff --git a/v2/src/app/components/ui/navigation-menu.tsx b/v2/src/app/components/ui/navigation-menu.tsx new file mode 100644 index 000000000..6a8d6f252 --- /dev/null +++ b/v2/src/app/components/ui/navigation-menu.tsx @@ -0,0 +1,168 @@ +import * as React from "react"; +import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"; +import { cva } from "class-variance-authority"; +import { ChevronDownIcon } from "lucide-react"; + +import { cn } from "./utils"; + +function NavigationMenu({ + className, + children, + viewport = true, + ...props +}: React.ComponentProps & { + viewport?: boolean; +}) { + return ( + + {children} + {viewport && } + + ); +} + +function NavigationMenuList({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function NavigationMenuItem({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +const navigationMenuTriggerStyle = cva( + "group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1", +); + +function NavigationMenuTrigger({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + {children}{" "} + + ); +} + +function NavigationMenuContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function NavigationMenuViewport({ + className, + ...props +}: React.ComponentProps) { + return ( +
+ +
+ ); +} + +function NavigationMenuLink({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function NavigationMenuIndicator({ + className, + ...props +}: React.ComponentProps) { + return ( + +
+ + ); +} + +export { + NavigationMenu, + NavigationMenuList, + NavigationMenuItem, + NavigationMenuContent, + NavigationMenuTrigger, + NavigationMenuLink, + NavigationMenuIndicator, + NavigationMenuViewport, + navigationMenuTriggerStyle, +}; diff --git a/v2/src/app/components/ui/pagination.tsx b/v2/src/app/components/ui/pagination.tsx new file mode 100644 index 000000000..a23239db5 --- /dev/null +++ b/v2/src/app/components/ui/pagination.tsx @@ -0,0 +1,127 @@ +import * as React from "react"; +import { + ChevronLeftIcon, + ChevronRightIcon, + MoreHorizontalIcon, +} from "lucide-react"; + +import { cn } from "./utils"; +import { Button, buttonVariants } from "./button"; + +function Pagination({ className, ...props }: React.ComponentProps<"nav">) { + return ( +