nutriguard-ui
v1.0.1
Published
NutriGuard Design System - Black/White/Red Minimalism Component Library based on Google Stitch architecture
Maintainers
Readme
nutriguard-ui
🎨 Philosophy
NutriGuard is a design system that combines:
- Google Stitch (Material You 3) dynamic architecture
- Black/White/Red strict minimalism
- Motion as information flow, not decoration
Core Principles
- Strict Color Palette: Only Black (#000), White (#FFF), Red (#DC2626), and limited Gray scale
- 4px Grid System: All spacing must be multiples of 4px
- Hard Shadows Only: No soft blur shadows
- Minimal Border Radius: 0px or 8px maximum
- No Emoji Policy: SVG icons only (Lucide React)
- Bold Borders: 2px standard, no 1px lines
- Framer Motion: All animations use spring physics
📦 Installation
npm install nutriguard-ui framer-motion lucide-reactPeer Dependencies
{
"react": "^18.0.0",
"react-dom": "^18.0.0"
}Tailwind CSS Setup
Add to your tailwind.config.js:
module.exports = {
content: [
"./src/**/*.{js,ts,jsx,tsx}",
"./node_modules/nutriguard-ui/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {
colors: {
black: '#000000',
white: '#FFFFFF',
red: '#DC2626',
},
boxShadow: {
'hard': '4px 4px 0 0 #000',
'hard-lg': '8px 8px 0 0 #000',
},
},
},
}🚀 Quick Start
Basic Usage
import { Button, Card, Modal, ToastProvider, useToast } from 'nutriguard-ui';
function App() {
const [isModalOpen, setIsModalOpen] = useState(false);
return (
<ToastProvider>
<Card padding="md" hoverable>
<h1>Welcome to NutriGuard</h1>
<Button
variant="primary"
onClick={() => setIsModalOpen(true)}
>
Open Modal
</Button>
</Card>
<Modal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
title="Example Modal"
>
<p>This is a modal with backdrop blur and hard shadow.</p>
</Modal>
</ToastProvider>
);
}Toast Notifications
import { useToast } from 'nutriguard-ui';
function MyComponent() {
const { success, error, warning, info } = useToast();
return (
<Button onClick={() => success('Operation completed!')}>
Show Success
</Button>
);
}🧩 Components
Button
Interactive button with motion and multiple variants.
<Button variant="primary" size="md" loading={false}>
Click Me
</Button>Props:
variant:'default' | 'primary' | 'red' | 'outline' | 'ghost'size:'sm' | 'md' | 'lg'loading: booleaniconLeft,iconRight: React.ReactNode
Card
Container with border and hover shadow effect.
<Card hoverable largeShadow padding="md">
<CardHeader>
<CardTitle>Card Title</CardTitle>
</CardHeader>
<CardContent>
Content goes here
</CardContent>
<CardFooter>
<Button>Action</Button>
</CardFooter>
</Card>Modal
Full-screen overlay with centered content.
<Modal
isOpen={isOpen}
onClose={onClose}
title="Modal Title"
size="md"
closeOnBackdrop={true}
>
<p>Modal content</p>
<ModalFooter>
<Button onClick={onClose}>Close</Button>
</ModalFooter>
</Modal>Toast
Auto-dismiss notification system.
// Wrap your app with ToastProvider
<ToastProvider maxToasts={5}>
<App />
</ToastProvider>
// Use in components
const { success, error, warning, info } = useToast();
success('Success message', 'Optional Title', 5000);Drawer
Slide-in panel from screen edges.
<Drawer
isOpen={isOpen}
onClose={onClose}
position="right"
size="md"
title="Drawer Title"
>
<p>Drawer content</p>
<DrawerFooter>
<Button onClick={onClose}>Close</Button>
</DrawerFooter>
</Drawer>Dialog
Simple confirmation dialog.
<Dialog
isOpen={isOpen}
onClose={onClose}
title="Confirm Action"
description="Are you sure you want to proceed?"
confirmText="Yes, proceed"
cancelText="Cancel"
onConfirm={handleConfirm}
variant="danger"
showIcon
/>Input & Textarea
Text input with validation states.
<Input
label="Email"
type="email"
placeholder="Enter your email"
state="default"
helperText="We'll never share your email"
iconLeft={<Mail />}
/>
<Textarea
label="Message"
placeholder="Enter your message"
rows={4}
helperText="Max 500 characters"
/>Spinner & Badge
<Spinner size="md" />
<Badge variant="primary" size="sm">NEW</Badge>
<Badge variant="red">Alert</Badge>🎬 Animations
Using Variants
import { buttonVariants, cardVariants } from 'nutriguard-ui';
import { motion } from 'framer-motion';
<motion.div variants={cardVariants} initial="initial" whileHover="hover">
Animated Card
</motion.div>Available Variants
buttonVariants- Scale on hover/tapcardVariants- Shadow lift on hovermodalVariants- Center entrancedrawerVariants- Slide from edgestoastVariants- Slide from top-rightdialogVariants- Drop from topstaggerContainerVariants- Stagger childrencollapseVariants- Accordion animation
🎨 Design Tokens
Colors
import { colors } from 'nutriguard-ui';
colors.black // #000000
colors.white // #FFFFFF
colors.red // #DC2626
colors.gray[400] // #9CA3AFSpacing (4px Grid)
import { spacing } from 'nutriguard-ui';
spacing[1] // 4px
spacing[2] // 8px
spacing[4] // 16px
spacing[6] // 24px
spacing[12] // 48pxTypography
import { typography } from 'nutriguard-ui';
typography.fontFamily.sans // 'Inter'
typography.fontSize.base // '16px'
typography.fontWeight.bold // 700🚫 Anti-Patterns
❌ DON'T
// ❌ Using emoji
<Button>Save 💾</Button>
// ❌ Soft shadows
<div style={{ boxShadow: '0 4px 12px rgba(0,0,0,0.1)' }} />
// ❌ Non-grid spacing
<div style={{ padding: '13px' }} />
// ❌ Unauthorized colors
<Button style={{ background: '#3B82F6' }} />
// ❌ Large border radius
<Card style={{ borderRadius: '20px' }} />✅ DO
// ✅ Use SVG icons
<Button iconLeft={<Save />}>Save</Button>
// ✅ Hard shadows
<Card hoverable largeShadow />
// ✅ 4px grid spacing
<div className="p-4" /> // 16px
// ✅ Strict palette
<Button variant="primary" />
// ✅ Minimal radius
<Card /> // 8px default📚 Examples
Full Page Example
import {
Button,
Card,
CardHeader,
CardTitle,
CardContent,
Modal,
ToastProvider,
useToast,
} from 'nutriguard-ui';
import { ArrowRight } from 'lucide-react';
function Dashboard() {
const [isModalOpen, setIsModalOpen] = useState(false);
const { success } = useToast();
const handleSave = () => {
success('Changes saved successfully!');
setIsModalOpen(false);
};
return (
<div className="max-w-[1440px] mx-auto px-8 py-16">
<div className="grid grid-cols-3 gap-6">
<Card hoverable>
<CardHeader>
<CardTitle>Analytics</CardTitle>
</CardHeader>
<CardContent>
<p className="text-4xl font-black">1,234</p>
<p className="text-sm text-gray-600">Total Users</p>
</CardContent>
</Card>
<Card hoverable onClick={() => setIsModalOpen(true)}>
<CardHeader>
<CardTitle>Settings</CardTitle>
</CardHeader>
<CardContent>
<p>Click to configure</p>
</CardContent>
</Card>
</div>
<Modal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
title="Settings"
size="md"
>
<p>Configure your settings here.</p>
<div className="flex gap-4 mt-6">
<Button variant="outline" fullWidth onClick={() => setIsModalOpen(false)}>
Cancel
</Button>
<Button variant="primary" fullWidth onClick={handleSave} iconRight={<ArrowRight />}>
Save Changes
</Button>
</div>
</Modal>
</div>
);
}
function App() {
return (
<ToastProvider>
<Dashboard />
</ToastProvider>
);
}🛠 Development
# Install dependencies
npm install
# Start dev server
npm run dev
# Build library
npm run build
# Run tests
npm test
# Start Storybook
npm run storybook📄 License
MIT © Nutrivision
🙏 Credits
- Google Material Design Team - Stitch architecture inspiration
- Framer - Motion library
- Lucide - Icon system
- Tailwind CSS - Utility-first CSS
📞 Support
- Documentation: docs.nutrivision.com
- Issues: GitHub Issues
- Email: [email protected]
