Vue Component Development
Patterns and conventions for building Vue 3 frontend components in this project.
Component Architecture
Directory Structure
views/layouts/— Layout wrappers (Page, Menu, Auth)views/components/— Reusable UI components (Button, TextInput, Table, Modal, etc.)views/components/icons/— Icon system (Icon, Avatar, Spinner)views/components/input/— Form input componentsviews/components/filters/— Filter components for list pagesviews/pages/— Page-level components organized by auth/private/sharedstores/— Pinia stores (auth, toast, alert, global)services/— TypeScript API service classes extending BaseServicehelpers/— Pure utility functions
Component Conventions
- Use Options API with
defineComponent()andsetup()function (project convention) - Use
reactive()for form state,ref()for simple values,computed()for derived state - Import components explicitly — no global registration
- Props use camelCase in JS, kebab-case in templates
UI Framework: DaisyUI 5
This project uses DaisyUI 5 on top of Tailwind CSS 4. Prefer DaisyUI component classes over hand-rolled Tailwind.
Key classes
- Buttons:
btn btn-primary,btn-success,btn-error,btn-outline,btn-ghost,btn-sm - Inputs:
input input-bordered,textarea textarea-bordered,select - Cards:
card bg-base-100 shadow,card-body,card-title - Tables:
tablewithhoveron<tr> - Badges:
badge badge-success,badge-error,badge-warning,badge-info - Alerts:
alert alert-success,alert-error - Modal:
modal,modal-open,modal-box,modal-backdrop - Navigation:
navbar,menu,breadcrumbs,dropdown - Loading:
loading loading-spinner,skeleton - Layout:
drawer,drawer-side,drawer-content
Theme Colors
Use semantic DaisyUI colors, not raw Tailwind colors:
primary(teal),secondary,accent,neutralsuccess,warning,error,infobase-100(surface),base-200(background),base-300(border),base-content(text)- Opacity variants:
text-base-content/50,border-base-300/50
Dark Mode
The project supports light/dark themes via data-theme attribute on <html>. Both themes use the same teal primary. Custom sidebar colors use --color-sidebar / --color-sidebar-content CSS variables that adapt per theme. Never hardcode white/black — use semantic DaisyUI colors.
Icon System
Icons use a thin wrapper around Heroicons:
vue<Icon name="users" class="h-5 w-5" />
To add a new icon: import it in views/components/icons/Icon.vue from @heroicons/vue/24/outline and add a name→component entry to the iconMap.
Toast Notifications
Use the toast store for user feedback instead of inline alerts:
jsimport {useToastStore} from "@/stores/toast"; const toastStore = useToastStore(); toastStore.success('Done!'); toastStore.error('Failed.'); toastStore.info('FYI...'); toastStore.warning('Careful!');
Toasts auto-dismiss after 5 seconds. They accept strings, arrays, or validation error objects.
Drawer Pattern for CRUD
List pages use a slide-in drawer instead of separate create/edit pages:
- Drawer state:
reactive({ open, mode, loading, form }) - Open with
drawer.open = trueand setdrawer.modeto'create'or'edit' - Close with
drawer.open = false, refresh list on success - Use
<Transition name="slide-right">for animation and<Teleport>if needed
API Services
- Services extend
BaseServiceorModelService(for CRUD) ModelServiceprovides:index(),store(),update(),delete(),edit(),find()handleCreate()andhandleUpdate()manage loading states and toast notifications- PUT/PATCH use POST with
_methodfield to support FormData file uploads
Form Handling
- Use
reactive()for form state - Use
reduceProperties(form, ['roles'], 'id')to flatten nested objects before submission - Use
fillObject(form, data)to populate form from API response - Use
clearObject(form)to reset form


