Meeting Agenda Notes
blockproductivityLinear and Notion style structured meeting document with attendee avatars, timeboxed agenda topics, rich discussion notes, interactive action items checklist, and key decisions log.
Installation
$pnpm dlx shadcn-vue@latest add https://uipkge.dev/r/vue/meeting-agenda-notes.json$npx shadcn-vue@latest add https://uipkge.dev/r/vue/meeting-agenda-notes.json$yarn dlx shadcn-vue@latest add https://uipkge.dev/r/vue/meeting-agenda-notes.json$bunx shadcn-vue@latest add https://uipkge.dev/r/vue/meeting-agenda-notes.jsonNamed registry:
npx shadcn-vue@latest add @uipkge/meeting-agenda-notesInstalls to:app/components/blocks/Variants
Loading interactive previews…
Loading interactive previews…
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
class | HTMLAttributes['class'] | — | optional |
Schema
Type aliases exported from this item's source. Use these to shape the data you pass in.
Attendeeinterface Attendee {
id: string
name: string
role: string
initials: string
isHost?: boolean
status: 'online' | 'busy' | 'away'
colorClass: string
}AgendaTopicinterface AgendaTopic {
id: string
number: number
title: string
duration: string
timeRange: string
lead: string
leadInitials: string
status: 'completed' | 'active' | 'upcoming'
summary: string
tags: string[]
}NoteEntryinterface NoteEntry {
id: string
author: string
authorInitials: string
authorColor: string
timestamp: string
content: string
tag: string
}ActionIteminterface ActionItem {
id: string
title: string
assignee: string
assigneeInitials: string
assigneeColor: string
dueDate: string
priority: 'Urgent' | 'High' | 'Medium' | 'Low'
completed: boolean
}KeyDecisioninterface KeyDecision {
id: string
number: number
title: string
context: string
status: 'Adopted' | 'Under Review'
decidedBy: string
time: string
}Files installed (1)
app/components/blocks/MeetingAgendaNotes.vue44.2 kB
<script setup lang="ts"> import { computed, ref, type HTMLAttributes } from 'vue' import { Calendar, Check, CheckCircle2, Clock, Copy, ExternalLink, FileDown, FileSpreadsheet, FileText, GitPullRequest, ListOrdered, Lock, Plus, Radio, UserCheck, Video, } from 'lucide-vue-next' import { cn } from '@/lib/utils' import { Avatar, AvatarFallback } from '@/components/ui/avatar' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Checkbox } from '@/components/ui/checkbox' import { Separator } from '@/components/ui/separator' interface Props { class?: HTMLAttributes['class'] } const props = defineProps<Props>() // Meeting Info State const copiedRoomLink = ref(false) const copiedNotes = ref(false) const copiedSnippet = ref(false) function copyRoomLink() { navigator.clipboard?.writeText('https://zoom.us/j/4829017734') copiedRoomLink.value = true setTimeout(() => { copiedRoomLink.value = false }, 2000) } function copyNotes() { navigator.clipboard?.writeText( 'Meeting Notes: UIPKGE Core Architecture Sync\nDate: Aug 21, 2026\nDecisions: Adopt OKLCH color spaces, reject monolithic npm bundle, ship dual-framework registry.', ) copiedNotes.value = true setTimeout(() => { copiedNotes.value = false }, 2000) } function copyCodeSnippet() { navigator.clipboard?.writeText( `export default defineRegistryItem({\n name: 'meeting-agenda-notes',\n type: 'registry:block',\n categories: ['productivity', 'collaboration'],\n dependencies: ['lucide-vue-next'],\n registryDependencies: [\n 'https://uipkge.dev/r/avatar.json',\n 'https://uipkge.dev/r/badge.json',\n 'https://uipkge.dev/r/button.json',\n 'https://uipkge.dev/r/card.json',\n 'https://uipkge.dev/r/checkbox.json',\n 'https://uipkge.dev/r/separator.json',\n ],\n})`, ) copiedSnippet.value = true setTimeout(() => { copiedSnippet.value = false }, 2000) } // Attendees List interface Attendee { id: string name: string role: string initials: string isHost?: boolean status: 'online' | 'busy' | 'away' colorClass: string } const attendees = ref<Attendee[]>([ { id: 'att-1', name: 'Elena Rostova', role: 'Lead Architect', initials: 'ER', isHost: true, status: 'online', colorClass: 'bg-primary/15 text-primary font-semibold', }, { id: 'att-2', name: 'Marcus Vance', role: 'Staff Engineer', initials: 'MV', status: 'online', colorClass: 'bg-info/15 text-info font-semibold', }, { id: 'att-3', name: 'Sarah Jenkins', role: 'Product Lead', initials: 'SJ', status: 'online', colorClass: 'bg-chart-1/15 text-chart-1 font-semibold', }, { id: 'att-4', name: 'David Chen', role: 'Core Infra', initials: 'DC', status: 'online', colorClass: 'bg-warning/15 text-warning font-semibold', }, { id: 'att-5', name: 'Sofia Rossi', role: 'Design Systems', initials: 'SR', status: 'online', colorClass: 'bg-destructive/15 text-destructive font-semibold', }, { id: 'att-6', name: 'Alex Rivera', role: 'DevRel', initials: 'AR', status: 'online', colorClass: 'bg-chart-2/15 text-chart-2 font-semibold', }, ]) // Timeboxed Agenda Topics interface AgendaTopic { id: string number: number title: string duration: string timeRange: string lead: string leadInitials: string status: 'completed' | 'active' | 'upcoming' summary: string tags: string[] } const agendaTopics = ref<AgendaTopic[]>([ { id: 'topic-1', number: 1, title: 'OKLCH Token Migration Status', duration: '15m', timeRange: '14:00 - 14:15', lead: 'Elena Rostova', leadInitials: 'ER', status: 'completed', summary: 'Audit of 140+ CSS custom properties completed. Confirmed wide-gamut Display P3 color spaces with zero degradation in legacy sRGB browsers.', tags: ['Design System', 'Tailwind v4'], }, { id: 'topic-2', number: 2, title: 'Dual-Framework AST Verification Pipeline', duration: '20m', timeRange: '14:15 - 14:35', lead: 'Marcus Vance', leadInitials: 'MV', status: 'active', summary: 'Live AST comparisons between Vue SFC templates and React TSX JSX trees. Validating component prop parity, variant definitions, and event handlers automatically in CI.', tags: ['Compiler', 'CI/CD', 'Parity'], }, { id: 'topic-3', number: 3, title: '100-Block Registry Expansion Strategy', duration: '15m', timeRange: '14:35 - 14:50', lead: 'Sarah Jenkins', leadInitials: 'SJ', status: 'upcoming', summary: 'Prioritization matrix for upcoming vertical blocks: Healthcare appointment management, HRMS payroll ledger, and DevTools query workbench.', tags: ['Roadmap', 'Blocks'], }, { id: 'topic-4', number: 4, title: 'Q&A & Retrospective', duration: '10m', timeRange: '14:50 - 15:00', lead: 'Open Floor', leadInitials: 'OF', status: 'upcoming', summary: 'Consensus check on flat URL dependency format, open architectural blockers, and sprint task assignment review.', tags: ['Open Floor', 'Review'], }, ]) // Discussion Notes & Live Comments interface NoteEntry { id: string author: string authorInitials: string authorColor: string timestamp: string content: string tag: string } const liveNotes = ref<NoteEntry[]>([ { id: 'note-1', author: 'Marcus Vance', authorInitials: 'MV', authorColor: 'bg-info/15 text-info', timestamp: '14:22 PST', content: 'The AST parity checker runs under 340ms locally with caching. We will add a strict blocking threshold in GitHub Actions.', tag: '#pipeline', }, { id: 'note-2', author: 'Sofia Rossi', authorInitials: 'SR', authorColor: 'bg-destructive/15 text-destructive', timestamp: '14:31 PST', content: 'All color tokens now satisfy WCAG AAA for text-foreground and AA for muted-foreground across dark surfaces.', tag: '#design-tokens', }, ]) const newNoteDraft = ref('') const newNoteTag = ref('#architecture') function addNote() { if (!newNoteDraft.value.trim()) return liveNotes.value.push({ id: `note-${Date.now()}`, author: 'Elena Rostova', authorInitials: 'ER', authorColor: 'bg-success/15 text-success', timestamp: 'Just now', content: newNoteDraft.value.trim(), tag: newNoteTag.value, }) newNoteDraft.value = '' } // Action Items Checklist interface ActionItem { id: string title: string assignee: string assigneeInitials: string assigneeColor: string dueDate: string priority: 'Urgent' | 'High' | 'Medium' | 'Low' completed: boolean } const actionItems = ref<ActionItem[]>([ { id: 'task-1', title: 'Publish OKLCH color token specification to documentation', assignee: 'Elena Rostova', assigneeInitials: 'ER', assigneeColor: 'bg-success/15 text-success', dueDate: 'Aug 24, 2026', priority: 'High', completed: true, }, { id: 'task-2', title: 'Configure AST parity tests in GitHub Actions CI workflow', assignee: 'Marcus Vance', assigneeInitials: 'MV', assigneeColor: 'bg-info/15 text-info', dueDate: 'Aug 26, 2026', priority: 'Urgent', completed: false, }, { id: 'task-3', title: 'Draft block wireframes for Healthcare & HRMS verticals', assignee: 'Sarah Jenkins', assigneeInitials: 'SJ', assigneeColor: 'bg-chart-1/15 text-chart-1', dueDate: 'Aug 28, 2026', priority: 'Medium', completed: false, }, { id: 'task-4', title: 'Benchmark bundle size delta across 50+ imported primitives', assignee: 'David Chen', assigneeInitials: 'DC', assigneeColor: 'bg-warning/15 text-warning', dueDate: 'Sep 02, 2026', priority: 'Low', completed: false, }, ]) const completedTasksCount = computed(() => actionItems.value.filter((t) => t.completed).length) const totalTasksCount = computed(() => actionItems.value.length) const completionPercentage = computed(() => totalTasksCount.value === 0 ? 0 : Math.round((completedTasksCount.value / totalTasksCount.value) * 100), ) function toggleTask(id: string, checked: boolean) { const item = actionItems.value.find((t) => t.id === id) if (item) { item.completed = checked } } const newTaskTitle = ref('') const newTaskAssignee = ref('Alex Rivera') const newTaskPriority = ref<'Urgent' | 'High' | 'Medium' | 'Low'>('Medium') function addTask() { if (!newTaskTitle.value.trim()) return const attendee = attendees.value.find((a) => a.name === newTaskAssignee.value) || attendees.value[0] actionItems.value.push({ id: `task-${Date.now()}`, title: newTaskTitle.value.trim(), assignee: attendee.name, assigneeInitials: attendee.initials, assigneeColor: attendee.colorClass, dueDate: 'Aug 30, 2026', priority: newTaskPriority.value, completed: false, }) newTaskTitle.value = '' } // Key Decisions Log interface KeyDecision { id: string number: number title: string context: string status: 'Adopted' | 'Under Review' decidedBy: string time: string } const keyDecisions = ref<KeyDecision[]>([ { id: 'dec-1', number: 1, title: 'Adopt flat registryDependencies URLs across all 300+ items', context: 'Declaring flat JSON URLs eliminates circular dependency warnings and simplifies downstream registry resolver graphs.', status: 'Adopted', decidedBy: 'Elena Rostova', time: '14:18 PST', }, { id: 'dec-2', number: 2, title: 'Enforce strict 120-char line width & no-semicolons styleguide', context: 'Standardizes AST transpilation outputs so generated Vue SFC and React TSX items maintain identical formatting invariants.', status: 'Adopted', decidedBy: 'Squad Consensus', time: '14:32 PST', }, { id: 'dec-3', number: 3, title: 'Deprecate legacy /r/nuxt/ aliases by end of Q3', context: 'Consumers will be directed to unified /r/vue/ endpoints while maintaining backwards-compatible 301 redirects.', status: 'Under Review', decidedBy: 'Sarah Jenkins', time: '14:45 PST', }, ]) // Export Notes Markdown Function function exportNotesMarkdown() { const md = `# Q3 Product Architecture & Monorepo Scaling Sync **Date:** Friday, Aug 21, 2026 · 14:00 - 15:00 PST **Meeting Room:** Zoom Room #482-901 **Attendees:** Elena Rostova (Host), Marcus Vance, Sarah Jenkins, David Chen, Sofia Rossi, Alex Rivera --- ## 📋 Timeboxed Agenda - [x] **OKLCH Token Migration Status** (15m · 14:00 - 14:15) - Elena Rostova - [x] **Dual-Framework AST Verification Pipeline** (20m · 14:15 - 14:35) - Marcus Vance [ACTIVE] - [ ] **100-Block Registry Expansion Strategy** (15m · 14:35 - 14:50) - Sarah Jenkins - [ ] **Q&A & Retrospective** (10m · 14:50 - 15:00) - Open Floor --- ## 💡 Key Architectural Decisions 1. **Adopt flat registryDependencies URLs across all 300+ items** [Adopted] - *Decided by:* Elena Rostova · 14:18 PST - *Context:* Eliminates circular dependency warnings in shadcn resolver. 2. **Enforce strict 120-char line width & no-semicolons styleguide** [Adopted] - *Decided by:* Squad Consensus · 14:32 PST - *Context:* Standardizes AST transpilation outputs across Vue & React. 3. **Deprecate legacy /r/nuxt/ aliases by end of Q3** [Under Review] - *Decided by:* Sarah Jenkins · 14:45 PST - *Context:* Directs consumers to unified /r/vue/ endpoints. --- ## ✅ Action Items ${actionItems.value .map( (task) => `- [${task.completed ? 'x' : ' '}] **${task.title}** (Assignee: @${task.assignee}, Due: ${task.dueDate}, Priority: ${task.priority})`, ) .join('\n')} ` navigator.clipboard?.writeText(md) copiedNotes.value = true setTimeout(() => { copiedNotes.value = false }, 2000) } </script> <template> <div data-slot="meeting-agenda-notes" :class="cn('text-foreground w-full space-y-6', props.class)"> <!-- Meeting Header Card --> <Card class="border-border bg-card shadow-xs"> <CardContent class="space-y-5 p-4 sm:p-6"> <!-- Top Badges & Status Row --> <div class="flex flex-wrap items-center justify-between gap-3"> <div class="flex flex-wrap items-center gap-2"> <Badge variant="secondary" class="gap-1.5 px-2.5 py-1 text-xs font-medium"> <span class="bg-destructive size-2 animate-pulse rounded-full" /> <span class="font-mono tracking-tight tabular-nums">REC · 45:12</span> </Badge> <Badge variant="outline" class="text-muted-foreground text-xs"> Architecture Sync </Badge> <Badge variant="outline" class="text-muted-foreground text-xs"> Bi-Weekly Cadence </Badge> </div> <!-- Meeting Actions --> <div class="flex flex-wrap items-center gap-2"> <Button variant="outline" size="sm" class="h-8 gap-1.5 text-xs shadow-xs" @click="exportNotesMarkdown"> <Check v-if="copiedNotes" class="text-success size-3.5" /> <FileDown v-else class="text-muted-foreground size-3.5" /> {{ copiedNotes ? 'Notes Copied!' : 'Export Notes Markdown' }} </Button> <Button size="sm" class="h-8 gap-1.5 text-xs shadow-xs"> <Video class="size-3.5" /> Join Call </Button> </div> </div> <!-- Meeting Title & Meta Info --> <div class="space-y-2"> <h1 class="text-foreground text-xl font-bold tracking-tight sm:text-2xl"> Q3 Product Architecture & Monorepo Scaling Sync </h1> <div class="text-muted-foreground flex flex-wrap items-center gap-x-5 gap-y-2 text-xs"> <!-- Date & Time --> <div class="flex items-center gap-1.5"> <Calendar class="text-foreground/70 size-3.5" /> <span class="text-foreground/90 font-medium">Friday, Aug 21, 2026</span> <span>·</span> <span class="font-mono tabular-nums">14:00 - 15:00 PST</span> </div> <!-- Duration Badge --> <div class="flex items-center gap-1.5"> <Clock class="text-foreground/70 size-3.5" /> <Badge variant="secondary" class="px-2 py-0.5 font-mono text-xs tabular-nums"> 60 mins · 45 mins elapsed </Badge> </div> <!-- Meeting Room Link --> <div class="flex items-center gap-1.5"> <Video class="text-foreground/70 size-3.5" /> <button type="button" class="text-foreground hover:text-primary inline-flex min-h-6 cursor-pointer items-center gap-1 font-medium transition-colors" @click="copyRoomLink" > <span>Zoom Room #482-901</span> <Check v-if="copiedRoomLink" class="text-success size-3" /> <Copy v-else class="text-muted-foreground size-3" /> </button> </div> </div> </div> <Separator class="bg-border/60" /> <!-- Attendee Avatars Row --> <div class="flex flex-col justify-between gap-4 sm:flex-row sm:items-center"> <div class="space-y-2"> <div class="flex items-center gap-2"> <span class="text-muted-foreground text-xs font-semibold tracking-wider uppercase"> Attendees </span> <Badge variant="secondary" class="h-4.5 px-1.5 py-0 font-mono text-xs tabular-nums"> 6 Present </Badge> </div> <!-- Avatars with online status dots --> <div class="flex flex-wrap items-center gap-2.5"> <div v-for="attendee in attendees" :key="attendee.id" class="group border-border/80 bg-background/80 hover:border-border hover:bg-muted/40 relative flex items-center gap-2 rounded-full border py-1 pr-2.5 pl-1 shadow-xs transition-colors" > <div class="relative flex items-center justify-center"> <Avatar size="sm" class="size-6 text-xs"> <AvatarFallback :class="attendee.colorClass"> {{ attendee.initials }} </AvatarFallback> </Avatar> <!-- Presence Status Dot --> <span class="border-background bg-success absolute -right-0.5 -bottom-0.5 size-2 rounded-full border-2" title="Present in meeting" /> </div> <span class="text-foreground text-xs font-medium"> {{ attendee.name }} </span> <Badge v-if="attendee.isHost" variant="default" class="h-4 px-1 text-xs leading-none font-semibold uppercase" > Host </Badge> </div> </div> </div> <!-- Quick Access Code / Status --> <div class="border-border/60 bg-muted/30 text-muted-foreground hidden items-center gap-3 rounded-lg border p-2.5 text-xs xl:flex" > <Radio class="text-success size-4 animate-pulse" /> <div> <div class="text-foreground font-medium">Live Transcription</div> <div class="text-muted-foreground font-mono">Whisper-v3 Active</div> </div> </div> </div> </CardContent> </Card> <!-- 2-Column Meeting Workspace --> <div class="grid grid-cols-1 gap-6 lg:grid-cols-12"> <!-- Left Panel: Timeboxed Agenda & Rich Notes (8 cols) --> <div class="space-y-6 lg:col-span-7 xl:col-span-8"> <!-- Section 1: 4 Timeboxed Agenda Topics --> <Card class="border-border bg-card shadow-xs"> <CardHeader class="px-5 pt-5 pb-3 sm:px-6"> <div class="flex flex-wrap items-center justify-between gap-2"> <div class="flex items-center gap-2"> <div class="bg-primary/10 text-primary flex size-7 items-center justify-center rounded-md"> <ListOrdered class="size-4" /> </div> <div> <CardTitle class="text-base font-semibold">Timeboxed Agenda</CardTitle> <CardDescription class="text-xs"> 4 topics structured with real-time progress indicators </CardDescription> </div> </div> <!-- Time Allocation Summary --> <Badge variant="outline" class="text-muted-foreground font-mono text-xs tabular-nums"> 60m Total · 45m Elapsed (75%) </Badge> </div> <!-- Elapsed Visual Bar --> <div class="bg-muted mt-3 h-1.5 w-full overflow-hidden rounded-full"> <div class="bg-primary h-full w-3/4 rounded-full" /> </div> </CardHeader> <CardContent class="space-y-3 p-5 pt-2 sm:p-6"> <div v-for="topic in agendaTopics" :key="topic.id" :class=" cn( 'group relative rounded-lg border p-4 transition-colors duration-150', topic.status === 'active' ? 'border-primary/50 bg-primary/[0.03] shadow-xs' : topic.status === 'completed' ? 'border-border/80 bg-muted/20' : 'border-border/60 bg-card hover:border-border', ) " > <div class="flex flex-col justify-between gap-3 sm:flex-row sm:items-start"> <!-- Topic Details --> <div class="flex-1 space-y-1.5"> <div class="flex flex-wrap items-center gap-2"> <span class="bg-muted text-muted-foreground flex size-5 items-center justify-center rounded-full font-mono text-xs font-semibold" > {{ topic.number }} </span> <h3 class="text-foreground text-sm font-semibold"> {{ topic.title }} </h3> <!-- Status Badges --> <Badge v-if="topic.status === 'completed'" variant="success" class="gap-1 text-xs"> <CheckCircle2 class="text-success size-3" /> Completed </Badge> <Badge v-else-if="topic.status === 'active'" variant="default" class="gap-1.5 text-xs font-medium"> <span class="bg-primary-foreground size-1.5 rounded-full" /> Current Topic </Badge> <Badge v-else variant="outline" class="text-muted-foreground gap-1 text-xs"> <Clock class="size-3" /> Upcoming </Badge> </div> <p class="text-muted-foreground text-xs leading-relaxed"> {{ topic.summary }} </p> <!-- Tags --> <div class="flex flex-wrap items-center gap-1.5 pt-1"> <Badge v-for="tag in topic.tags" :key="tag" variant="secondary" class="text-muted-foreground px-1.5 py-0 text-xs font-normal" > {{ tag }} </Badge> </div> </div> <!-- Presenter & Timebox Metadata --> <div class="border-border/50 flex shrink-0 items-center justify-between gap-1.5 border-t pt-2 sm:flex-col sm:items-end sm:border-t-0 sm:pt-0" > <div class="flex items-center gap-1.5"> <span class="text-muted-foreground font-mono text-xs tabular-nums"> {{ topic.duration }} </span> <span class="text-muted-foreground font-mono text-xs tabular-nums"> {{ topic.timeRange }} </span> </div> <div class="flex items-center gap-1.5"> <Avatar size="xs" class="size-4.5 text-xs"> <AvatarFallback class="bg-muted text-muted-foreground text-xs font-semibold"> {{ topic.leadInitials }} </AvatarFallback> </Avatar> <span class="text-foreground/80 text-xs font-medium"> {{ topic.lead }} </span> </div> </div> </div> </div> </CardContent> </Card> <!-- Section 2: Rich Discussion Notes Area --> <Card class="border-border bg-card shadow-xs"> <CardHeader class="px-5 pt-5 pb-3 sm:px-6"> <div class="flex flex-wrap items-center justify-between gap-2"> <div class="flex items-center gap-2"> <div class="bg-primary/10 text-primary flex size-7 items-center justify-center rounded-md"> <FileText class="size-4" /> </div> <div> <CardTitle class="text-base font-semibold">Discussion Notes & Technical Blueprint</CardTitle> <CardDescription class="text-xs"> Structured architectural takeaways and runtime benchmarks </CardDescription> </div> </div> <span class="text-muted-foreground font-mono text-xs tabular-nums"> Last edited 2m ago by Elena Rostova </span> </div> </CardHeader> <CardContent class="space-y-5 p-5 pt-2 sm:p-6"> <!-- Context Callout Box --> <div class="border-border bg-muted/40 space-y-1 rounded-lg border p-3.5"> <div class="text-foreground flex items-center gap-1.5 text-xs font-semibold"> <FileText class="text-primary size-3.5" /> Core Monorepo Mandate </div> <p class="text-muted-foreground text-xs leading-relaxed"> Components are the product, not an npm library. Consumers run <code class="bg-muted text-foreground rounded px-1.5 py-0.5 font-mono font-medium" >npx shadcn-vue add <url></code > and own the code directly. All block primitives must compose raw layouts without baking rigid data arrays into primitives. </p> </div> <!-- Structured Takeaways Section --> <div class="space-y-2.5"> <h4 class="text-muted-foreground text-xs font-bold tracking-wider uppercase">Architectural Takeaways</h4> <div class="space-y-2"> <div class="border-border/60 bg-card flex items-start gap-2.5 rounded-md border p-3 shadow-xs"> <div class="bg-success/10 text-success mt-0.5 flex size-5 shrink-0 items-center justify-center rounded-full" > <Check class="size-3" /> </div> <div class="space-y-0.5 text-xs"> <span class="text-foreground font-semibold">Zero Runtime Overhead Delivery Model</span> <p class="text-muted-foreground leading-relaxed"> Zero build-time vendor lock-in. Primitives handle focus rings, keyboard navigation, and accessibility semantics while leaving styling tokens fully customizable by end consumers. </p> </div> </div> <div class="border-border/60 bg-card flex items-start gap-2.5 rounded-md border p-3 shadow-xs"> <div class="bg-info/10 text-info mt-0.5 flex size-5 shrink-0 items-center justify-center rounded-full" > <Check class="size-3" /> </div> <div class="space-y-0.5 text-xs"> <span class="text-foreground font-semibold">Perceptually Uniform OKLCH Palette</span> <p class="text-muted-foreground leading-relaxed"> Color spaces mapped directly to standard OKLCH coordinates via Tailwind CSS v4 <code class="bg-muted text-foreground rounded px-1 py-0.5 font-mono">@theme inline</code> tokens, ensuring high-fidelity rendering across Apple P3 displays. </p> </div> </div> <div class="border-border/60 bg-card flex items-start gap-2.5 rounded-md border p-3 shadow-xs"> <div class="bg-primary/10 text-primary mt-0.5 flex size-5 shrink-0 items-center justify-center rounded-full" > <Check class="size-3" /> </div> <div class="space-y-0.5 text-xs"> <span class="text-foreground font-semibold">Flat Registry Dependencies Graph</span> <p class="text-muted-foreground leading-relaxed"> All <code class="bg-muted text-foreground rounded px-1 py-0.5 font-mono">registryDependencies</code> declare flat URLs (<code class="bg-muted text-foreground rounded px-1 py-0.5 font-mono" >https://uipkge.dev/r/button.json</code >), eliminating nested resolver locks in downstream CLIs. </p> </div> </div> </div> </div> <!-- Code Architecture Blueprint --> <div class="space-y-2"> <div class="flex items-center justify-between"> <h4 class="text-muted-foreground text-xs font-bold tracking-wider uppercase">Manifest Blueprint</h4> <button type="button" class="text-muted-foreground hover:text-foreground flex min-h-6 cursor-pointer items-center gap-1 text-xs transition-colors" @click="copyCodeSnippet" > <Check v-if="copiedSnippet" class="text-success size-3" /> <Copy v-else class="size-3" /> <span class="font-mono text-xs">{{ copiedSnippet ? 'Copied' : 'Copy Manifest' }}</span> </button> </div> <div class="border-border/80 bg-muted/60 relative overflow-hidden rounded-lg border p-3 font-mono text-xs" > <pre class="text-foreground/90 overflow-x-auto leading-relaxed" ><code><span class="text-primary font-semibold">export default</span> <span class="text-info">defineRegistryItem</span>({ name: <span class="text-success">'meeting-agenda-notes'</span>, type: <span class="text-success">'registry:block'</span>, categories: [<span class="text-success">'productivity'</span>, <span class="text-success">'collaboration'</span>], dependencies: [<span class="text-success">'lucide-vue-next'</span>], registryDependencies: [ <span class="text-warning">'https://uipkge.dev/r/avatar.json'</span>, <span class="text-warning">'https://uipkge.dev/r/badge.json'</span>, <span class="text-warning">'https://uipkge.dev/r/button.json'</span>, <span class="text-warning">'https://uipkge.dev/r/card.json'</span>, <span class="text-warning">'https://uipkge.dev/r/checkbox.json'</span>, <span class="text-warning">'https://uipkge.dev/r/separator.json'</span>, ], })</code></pre> </div> </div> <!-- Live Meeting Annotations & Comment Thread --> <div class="space-y-3 pt-2"> <h4 class="text-muted-foreground text-xs font-bold tracking-wider uppercase">Live Annotations</h4> <div class="space-y-2.5"> <div v-for="note in liveNotes" :key="note.id" class="border-border/60 bg-muted/20 flex items-start gap-2.5 rounded-lg border p-3" > <Avatar size="sm" class="size-6 shrink-0 text-xs"> <AvatarFallback :class="note.authorColor"> {{ note.authorInitials }} </AvatarFallback> </Avatar> <div class="flex-1 space-y-1"> <div class="flex items-center justify-between gap-2"> <div class="flex items-center gap-1.5"> <span class="text-foreground text-xs font-semibold">{{ note.author }}</span> <Badge variant="outline" class="text-muted-foreground px-1 py-0 font-mono text-xs"> {{ note.tag }} </Badge> </div> <span class="text-muted-foreground font-mono text-xs tabular-nums">{{ note.timestamp }}</span> </div> <p class="text-foreground/90 text-xs leading-relaxed">{{ note.content }}</p> </div> </div> </div> <!-- Inline Note Composer --> <div class="flex flex-col items-stretch gap-2 pt-2 sm:flex-row sm:items-center"> <div class="relative flex-1"> <input v-model="newNoteDraft" type="text" placeholder="Append architecture note or observation..." class="border-input bg-background text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/40 h-8 w-full rounded-md border px-3 py-1 text-xs shadow-xs outline-none focus-visible:ring-2" @keydown.enter="addNote" /> </div> <div class="flex items-center gap-1.5"> <select v-model="newNoteTag" class="border-input bg-background text-foreground focus-visible:border-ring focus-visible:ring-ring/40 h-8 rounded-md border px-2 text-xs shadow-xs outline-none focus-visible:ring-2" > <option value="#architecture">#architecture</option> <option value="#pipeline">#pipeline</option> <option value="#decision">#decision</option> <option value="#action">#action</option> </select> <Button size="sm" variant="secondary" class="h-8 gap-1 text-xs shadow-xs" :disabled="!newNoteDraft.trim()" @click="addNote" > <Plus class="size-3.5" /> Post </Button> </div> </div> </div> </CardContent> </Card> </div> <!-- Right Sidebar: Action Items, Decisions, & Meta (4-5 cols) --> <div class="space-y-6 lg:col-span-5 xl:col-span-4"> <!-- Action Items Checklist Card --> <Card class="border-border bg-card shadow-xs"> <CardHeader class="px-5 pt-5 pb-3"> <div class="flex items-center justify-between gap-2"> <div class="flex items-center gap-2"> <div class="bg-success/10 text-success flex size-7 items-center justify-center rounded-md"> <UserCheck class="size-4" /> </div> <div> <CardTitle class="text-base font-semibold">Action Items</CardTitle> <CardDescription class="text-xs"> Assigned deliverables & deadlines </CardDescription> </div> </div> <!-- Completion Counter Badge --> <Badge variant="secondary" class="font-mono text-xs tabular-nums"> {{ completedTasksCount }}/{{ totalTasksCount }} Done ({{ completionPercentage }}%) </Badge> </div> <!-- Progress bar --> <div class="bg-muted mt-3 h-1.5 w-full overflow-hidden rounded-full"> <div class="bg-success h-full rounded-full transition-[width] duration-300" :style="{ width: `${completionPercentage}%` }" /> </div> </CardHeader> <CardContent class="space-y-4 p-5 pt-2"> <!-- Checklist items --> <div class="space-y-2.5"> <div v-for="task in actionItems" :key="task.id" :class=" cn( 'group flex items-start gap-3 rounded-lg border p-3 transition-colors', task.completed ? 'border-border/40 bg-muted/20 opacity-75' : 'border-border/80 bg-card hover:border-border hover:bg-muted/10', ) " > <!-- Checkbox --> <div class="pt-0.5"> <Checkbox :id="task.id" :model-value="task.completed" @update:model-value="(val) => toggleTask(task.id, Boolean(val))" /> </div> <!-- Task content --> <div class="flex-1 space-y-1.5"> <label :for="task.id" :class=" cn( 'block cursor-pointer text-xs leading-relaxed font-medium transition-colors select-none', task.completed ? 'text-muted-foreground line-through' : 'text-foreground', ) " > {{ task.title }} </label> <div class="text-muted-foreground flex flex-wrap items-center justify-between gap-1.5 text-xs"> <!-- Assignee --> <div class="flex items-center gap-1.5"> <Avatar size="xs" class="size-4 text-xs"> <AvatarFallback :class="cn('text-xs', task.assigneeColor)"> {{ task.assigneeInitials }} </AvatarFallback> </Avatar> <span class="text-foreground/80 text-xs font-medium"> {{ task.assignee }} </span> </div> <!-- Priority & Date --> <div class="flex items-center gap-1.5"> <Badge :variant=" task.priority === 'Urgent' || task.priority === 'High' ? 'destructive' : task.priority === 'Medium' ? 'warning' : 'secondary' " class="h-4.5 px-1.5 text-xs font-semibold uppercase" > {{ task.priority }} </Badge> <span class="text-muted-foreground font-mono text-xs tabular-nums"> {{ task.dueDate }} </span> </div> </div> </div> </div> </div> <!-- Quick Add Action Item --> <div class="border-border/80 bg-muted/20 space-y-2 rounded-lg border border-dashed p-3"> <input v-model="newTaskTitle" type="text" placeholder="New action item description..." class="border-input bg-background text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring h-7 w-full rounded border px-2.5 text-xs shadow-xs outline-none focus-visible:ring-1" @keydown.enter="addTask" /> <div class="flex items-center justify-between gap-2"> <select v-model="newTaskAssignee" class="border-input bg-background text-foreground h-7 rounded border px-2 text-xs shadow-xs outline-none" > <option v-for="att in attendees" :key="att.id" :value="att.name"> {{ att.name }} </option> </select> <select v-model="newTaskPriority" class="border-input bg-background text-foreground h-7 rounded border px-2 text-xs shadow-xs outline-none" > <option value="Urgent">Urgent</option> <option value="High">High</option> <option value="Medium">Medium</option> <option value="Low">Low</option> </select> <Button size="xs" variant="default" class="h-7 gap-1 text-xs" :disabled="!newTaskTitle.trim()" @click="addTask" > <Plus class="size-3" /> Add </Button> </div> </div> </CardContent> </Card> <!-- Key Decisions Log Card --> <Card class="border-border bg-card shadow-xs"> <CardHeader class="px-5 pt-5 pb-3"> <div class="flex items-center justify-between gap-2"> <div class="flex items-center gap-2"> <div class="bg-primary/10 text-primary flex size-7 items-center justify-center rounded-md"> <CheckCircle2 class="size-4" /> </div> <div> <CardTitle class="text-base font-semibold">Key Decisions Log</CardTitle> <CardDescription class="text-xs"> Recorded architectural consensus </CardDescription> </div> </div> <Badge variant="outline" class="text-muted-foreground font-mono text-xs tabular-nums"> {{ keyDecisions.length }} Recorded </Badge> </div> </CardHeader> <CardContent class="space-y-3 p-5 pt-2"> <div v-for="decision in keyDecisions" :key="decision.id" class="border-border/80 bg-card space-y-2 rounded-lg border p-3.5 shadow-xs" > <div class="flex items-start justify-between gap-2"> <div class="flex items-center gap-1.5"> <span class="text-muted-foreground font-mono text-xs font-bold"> D-0{{ decision.number }} </span> <Badge :variant="decision.status === 'Adopted' ? 'success' : 'warning'" class="h-4.5 px-1.5 text-xs font-semibold uppercase" > {{ decision.status }} </Badge> </div> <span class="text-muted-foreground font-mono text-xs tabular-nums"> {{ decision.time }} </span> </div> <h4 class="text-foreground text-xs leading-snug font-semibold"> {{ decision.title }} </h4> <p class="text-muted-foreground text-xs leading-relaxed"> {{ decision.context }} </p> <div class="text-muted-foreground border-border/40 flex items-center gap-1 border-t pt-1 text-xs"> <span>Decided by:</span> <span class="text-foreground font-medium">{{ decision.decidedBy }}</span> </div> </div> </CardContent> </Card> <!-- Meeting Metadata & Shared Resources Card --> <Card class="border-border bg-card shadow-xs"> <CardHeader class="px-5 pt-4 pb-2"> <CardTitle class="text-muted-foreground text-xs font-bold tracking-wider uppercase"> Session Resources & Security </CardTitle> </CardHeader> <CardContent class="space-y-3 p-5 pt-1"> <div class="space-y-2 text-xs"> <div class="text-muted-foreground flex items-center justify-between"> <span class="flex items-center gap-1.5"> <Lock class="text-foreground/70 size-3.5" /> Access Level </span> <span class="text-foreground font-medium">Internal (SSO Auth)</span> </div> <div class="text-muted-foreground flex items-center justify-between"> <span class="flex items-center gap-1.5"> <Calendar class="text-foreground/70 size-3.5" /> Next Sync </span> <span class="text-foreground font-mono font-medium tabular-nums">Aug 28 · 14:00 PST</span> </div> </div> <Separator class="bg-border/60" /> <!-- Linked Resources --> <div class="space-y-1.5"> <span class="text-muted-foreground text-xs font-semibold">Attached Artifacts</span> <div class="space-y-1"> <a href="#artifacts" class="text-foreground hover:bg-muted group flex items-center justify-between rounded-md p-1.5 text-xs transition-colors" > <span class="flex items-center gap-2"> <FileSpreadsheet class="text-success size-3.5" /> <span>OKLCH Token Audit Matrix.xlsx</span> </span> <ExternalLink class="text-muted-foreground group-hover:text-foreground size-3 transition-colors" /> </a> <a href="#artifacts" class="text-foreground hover:bg-muted group flex items-center justify-between rounded-md p-1.5 text-xs transition-colors" > <span class="flex items-center gap-2"> <GitPullRequest class="text-chart-2 size-3.5" /> <span>PR #412: Flat Dependency Resolution</span> </span> <ExternalLink class="text-muted-foreground group-hover:text-foreground size-3 transition-colors" /> </a> </div> </div> </CardContent> </Card> </div> </div> </div> </template>
Raw manifest:https://uipkge.dev/r/vue/meeting-agenda-notes.json