@evoke-ui/budx
v0.2.2
Published
Cannabis production calendar components with day detail views, notes management, and phase visualization for React and Tailwind CSS
Downloads
26
Maintainers
Readme
@evoke-ui/budx
Cannabis production calendar components with day detail views, notes management, and phase visualization for React and Tailwind CSS.
Features
- 📅 Production Calendar - Track grow cycles with visual phase indicators
- 🌱 Growth Phase Tracking - Germination, Seedling, Vegetative, Flowering, Harvest
- 📝 Note Management - Add detailed notes with room conditions and nutrient tracking
- 🎨 Customizable Themes - Light/dark mode with CSS variables
- 📱 Responsive Design - Works seamlessly on desktop and mobile
- ♿ Accessible - WCAG compliant with keyboard navigation
- 🎯 TypeScript - Full type safety and IntelliSense support
- 🎨 Tailwind CSS 4 - Modern utility-first styling
Installation
npm install @evoke-ui/budxPeer Dependencies
This package requires the following peer dependencies:
npm install react react-dom tailwindcss
npm install @radix-ui/react-accordion @radix-ui/react-avatar @radix-ui/react-dialog
npm install @radix-ui/react-dropdown-menu @radix-ui/react-scroll-area @radix-ui/react-separator
npm install lucide-reactFor Next.js projects:
npm install nextQuick Start
1. Import Styles
Add the styles to your app's entry point:
import '@evoke-ui/budx/styles.css'Note: The package includes pre-compiled Tailwind CSS utilities, so you don't need to configure Tailwind to scan the package files.
2. Basic Calendar Usage
import { CalendarView } from '@evoke-ui/budx/calendar'
function App() {
const grows = [
{
id: '1',
name: 'Northern Lights',
strain: 'Indica',
startDate: '2024-01-15',
phase: 'vegetative',
customColor: '#22c55e',
},
]
return (
<CalendarView
grows={grows}
currentDate="2024-01-28"
onDateChange={(date) => console.log('Date changed:', date)}
/>
)
}3. Note Management Integration
'use client'
import { useState, useCallback } from 'react'
import { CalendarView } from '@evoke-ui/budx/calendar'
import type { GrowNote } from '@evoke-ui/budx/calendar'
export function MyCalendar() {
const [currentDate, setCurrentDate] = useState('2024-01-28')
const grows = [
{
id: '1',
name: 'Northern Lights',
strain: 'Indica',
startDate: '2024-01-15',
phase: 'vegetative',
customColor: '#22c55e',
},
]
// Handle note creation
const handleNoteAdded = useCallback(async (newNote: GrowNote) => {
// Call your API to create the note
const response = await fetch('/api/notes', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newNote),
})
if (!response.ok) throw new Error('Failed to create note')
// Re-fetch notes or update local state as needed
}, [])
// Handle note updates
const handleNoteUpdated = useCallback(async (updatedNote: GrowNote) => {
const response = await fetch(`/api/notes/${updatedNote.id}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(updatedNote),
})
if (!response.ok) throw new Error('Failed to update note')
// Re-fetch notes or update local state as needed
}, [])
return (
<CalendarView
grows={grows}
currentDate={currentDate}
onDateChange={(date) => setCurrentDate(date)}
onNoteAdded={handleNoteAdded}
onNoteUpdated={handleNoteUpdated}
/>
)
}Key Points:
- ✅ Your app handles API calls and data persistence
- ✅ Components handle UI, validation, and user interactions
- ✅ Re-throw errors in callbacks to keep forms open for retry
- ✅ Full TypeScript support with type inference
📖 View Complete Integration Guide
Subpath Exports
The package provides granular imports for better tree-shaking:
// Main entry - exports everything
import { CalendarView, Button, cn } from '@evoke-ui/budx'
// Calendar components only
import { CalendarView, CalendarHeader, CalendarGrid } from '@evoke-ui/budx/calendar'
// UI components only
import { Button, Card, Input, Badge } from '@evoke-ui/budx/ui'
// Hooks only
import { useMediaQuery } from '@evoke-ui/budx/hooks'
// Utilities only
import { cn, getInitials } from '@evoke-ui/budx/utils'
// Styles
import '@evoke-ui/budx/styles.css'Components
CalendarView
Main calendar component with grow cycle visualization.
import { CalendarView } from '@evoke-ui/budx/calendar'
<CalendarView
grows={grows}
initialYear={2024}
initialMonth={1}
onDayClick={(day) => console.log('Day clicked:', day)}
onMonthChange={(year, month) => console.log('Month changed:', year, month)}
onNoteAdded={async (note) => { /* API call to create note */ }}
onNoteUpdated={async (note) => { /* API call to update note */ }}
onNoteDeleted={async (id) => { /* API call to delete note */ }}
/>Props:
| Prop | Type | Description |
|------|------|-------------|
| grows? | Grow[] | Array of grow cycles to display |
| initialYear? | number | Initial year to display (defaults to current year) |
| initialMonth? | number | Initial month to display (1-12, defaults to current month) |
| phaseColors? | Partial<PhaseColorConfig> | Custom phase color configuration |
| onDayClick? | (date: Date) => void | Callback when a day cell is clicked |
| onPhaseClick? | (phase: GrowPhase, grow: Grow) => void | Callback when a phase bar is clicked |
| onMonthChange? | (year: number, month: number) => void | Callback when month changes |
| showAdjacentMonths? | boolean | Whether to show days from adjacent months (default: true) |
| maxVisiblePhases? | number | Max phase bars per day before overflow (default: 3) |
| showLegend? | boolean | Whether to show phase legend (default: true) |
| onNoteAdded? | (note: GrowNote) => Promise<void> | Async callback when a note is added |
| onNoteUpdated? | (note: GrowNote) => Promise<void> | Async callback when a note is updated |
| onNoteDeleted? | (noteId: string) => Promise<void> | Async callback when a note is deleted |
| className? | string | Additional CSS classes |
UI Components
Pre-built UI components based on shadcn/ui:
import { Button, Card, Badge, Input, Avatar } from '@evoke-ui/budx/ui'
// Button
<Button variant="default" size="md">Click me</Button>
// Card
<Card>
<CardHeader>
<CardTitle>Title</CardTitle>
</CardHeader>
<CardContent>Content here</CardContent>
</Card>
// Badge
<Badge variant="default">New</Badge>
// Input
<Input placeholder="Enter text..." />
// Avatar
<Avatar name="John Doe" src="/avatar.jpg" size="md" />Types
GrowWithPhaseDates
interface GrowWithPhaseDates {
id: string
name: string
strain?: string
startDate: string // ISO date
phase: GrowPhase
customColor?: string // Hex or OKLCH color
phaseDates?: {
germination?: { start: string; end: string }
seedling?: { start: string; end: string }
vegetative?: { start: string; end: string }
flowering?: { start: string; end: string }
harvest?: { start: string; end: string }
}
}
type GrowPhase = 'germination' | 'seedling' | 'vegetative' | 'flowering' | 'harvest'GrowNote
interface GrowNote {
id: string
grow: GrowWithPhaseDates
date: string // ISO date
title?: string
notes?: string
room?: RoomConditions
nutrients?: Record<string, number>
}
interface RoomConditions {
lights: string // e.g., '18/6', '1000W HPS'
temps: string // e.g., '75-80F', '24C'
humidity: string // e.g., '55%', '50-60%'
vpd: string // e.g., '1.2 kPa'
}Theming
The package uses CSS variables for theming. Customize by overriding variables:
:root {
/* Colors */
--primary: 221 83% 53%;
--primary-foreground: 0 0% 98%;
--background: 0 0% 100%;
--foreground: 0 0% 9%;
/* Border radius */
--radius: 0.5rem;
/* Transitions */
--transition-base: 200ms;
}Dark Mode
Dark mode is automatically applied based on system preference:
@media (prefers-color-scheme: dark) {
:root {
--background: 0 0% 4%;
--foreground: 0 0% 93%;
/* ... other dark mode variables */
}
}Utilities
cn
Utility for merging Tailwind CSS classes:
import { cn } from '@evoke-ui/budx/utils'
<div className={cn('base-class', isActive && 'active-class')} />getInitials
Extract initials from a name:
import { getInitials } from '@evoke-ui/budx/utils'
getInitials('John Doe') // 'JD'Browser Support
- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
Contributing
Contributions are welcome! Please read our Contributing Guide for details.
License
MIT © Evoke UI
