{#each members as member}
+ {@const profile = member.profiles}
@@ -616,16 +617,18 @@
- {(member.profiles.full_name ||
- member.profiles.email ||
+ {(profile?.full_name ||
+ profile?.email ||
"?")[0].toUpperCase()}
- {member.profiles.full_name || "No name"}
+ {profile?.full_name ||
+ profile?.email ||
+ "Unknown User"}
- {member.profiles.email}
+ {profile?.email || "No email"}
diff --git a/src/routes/layout.css b/src/routes/layout.css
index 2426da1..585f73c 100644
--- a/src/routes/layout.css
+++ b/src/routes/layout.css
@@ -1,32 +1,55 @@
+@import url('https://fonts.googleapis.com/css2?family=Tilt+Warp&family=Work+Sans:wght@400;500;600;700&display=swap');
@import 'tailwindcss';
@plugin '@tailwindcss/forms';
@plugin '@tailwindcss/typography';
@theme {
- /* Colors - Dark theme */
- --color-dark: #0a0a0f;
- --color-surface: #14141f;
- --color-light: #f0f0f5;
+ /* Colors - Figma Design System */
+ --color-background: #05090f;
+ --color-night: #0A121F;
+ --color-dark: #14243E;
+ --color-surface: #0A121F;
+ --color-light: #E5E6F0;
+ --color-text: #FFFFFF;
+ --color-text-muted: rgba(229, 230, 240, 0.5);
- /* Brand */
- --color-primary: #6366f1;
- --color-primary-hover: #4f46e5;
+ /* Brand - Primary */
+ --color-primary: #00A3E0;
+ --color-primary-hover: #33b5e6;
- /* Status */
- --color-success: #22c55e;
- --color-warning: #f59e0b;
- --color-error: #ef4444;
- --color-info: #3b82f6;
+ /* Status Colors */
+ --color-success: #33E000;
+ --color-warning: #FFAB00;
+ --color-error: #E03D00;
+ --color-info: #00A3E0;
- /* Font */
- --font-sans: 'Inter', system-ui, -apple-system, sans-serif;
+ /* Typography - Figma Fonts */
+ --font-heading: 'Tilt Warp', sans-serif;
+ --font-body: 'Work Sans', sans-serif;
+ --font-sans: 'Work Sans', system-ui, -apple-system, sans-serif;
+
+ /* Border Radius - Figma Design */
+ --radius-sm: 8px;
+ --radius-md: 16px;
+ --radius-lg: 24px;
+ --radius-xl: 32px;
+ --radius-pill: 32px;
+ --radius-circle: 128px;
}
/* Base styles */
-body {
- background-color: var(--color-dark);
+html, body {
+ background-color: var(--color-background);
color: var(--color-light);
- font-family: var(--font-sans);
+ font-family: var(--font-body);
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+/* Headings */
+h1, h2, h3, h4, h5, h6 {
+ font-family: var(--font-heading);
+ font-weight: 400;
}
/* Scrollbar styling */
@@ -36,14 +59,105 @@ body {
}
::-webkit-scrollbar-track {
- background: var(--color-dark);
+ background: transparent;
}
::-webkit-scrollbar-thumb {
- background: var(--color-light) / 0.2;
- border-radius: 4px;
+ background: var(--color-night);
+ border-radius: var(--radius-pill);
}
::-webkit-scrollbar-thumb:hover {
- background: var(--color-light) / 0.3;
+ background: var(--color-dark);
+}
+
+/* Focus styles */
+:focus-visible {
+ outline: 2px solid var(--color-primary);
+ outline-offset: 2px;
+}
+
+/* Selection */
+::selection {
+ background-color: rgba(0, 163, 224, 0.3);
+ color: var(--color-light);
+}
+
+/* Prose/Markdown styles */
+.prose {
+ line-height: 1.6;
+}
+
+.prose p {
+ margin: 0.5em 0;
+}
+
+.prose strong {
+ font-weight: 700;
+ color: var(--color-light);
+}
+
+.prose code {
+ background: var(--color-night);
+ padding: 0.15em 0.4em;
+ border-radius: 4px;
+ font-family: 'Consolas', 'Monaco', monospace;
+ font-size: 0.9em;
+ color: var(--color-primary);
+}
+
+.prose pre {
+ background: var(--color-night);
+ padding: 1em;
+ border-radius: var(--radius-sm);
+ overflow-x: auto;
+ margin: 0.5em 0;
+}
+
+.prose pre code {
+ background: none;
+ padding: 0;
+ color: var(--color-light);
+}
+
+.prose blockquote {
+ border-left: 3px solid var(--color-primary);
+ padding-left: 1em;
+ margin: 0.5em 0;
+ color: var(--color-text-muted);
+ font-style: italic;
+}
+
+.prose ul, .prose ol {
+ padding-left: 1.5em;
+ margin: 0.5em 0;
+}
+
+.prose ul {
+ list-style-type: disc;
+}
+
+.prose ol {
+ list-style-type: decimal;
+}
+
+.prose li {
+ margin: 0.25em 0;
+}
+
+.prose h1, .prose h2, .prose h3, .prose h4 {
+ color: var(--color-light);
+ margin: 0.75em 0 0.5em;
+ font-family: var(--font-heading);
+}
+
+.prose a {
+ color: var(--color-primary);
+ text-decoration: underline;
+}
+
+.prose hr {
+ border: none;
+ border-top: 1px solid var(--color-dark);
+ margin: 1em 0;
}
diff --git a/src/routes/style/+page.svelte b/src/routes/style/+page.svelte
index 9b8be56..cebdcee 100644
--- a/src/routes/style/+page.svelte
+++ b/src/routes/style/+page.svelte
@@ -9,19 +9,20 @@
Card,
Modal,
Spinner,
- Toggle
- } from '$lib/components/ui';
+ Toggle,
+ Toast,
+ } from "$lib/components/ui";
- let inputValue = $state('');
- let textareaValue = $state('');
- let selectValue = $state('');
+ let inputValue = $state("");
+ let textareaValue = $state("");
+ let selectValue = $state("");
let toggleChecked = $state(false);
let modalOpen = $state(false);
const selectOptions = [
- { value: 'option1', label: 'Option 1' },
- { value: 'option2', label: 'Option 2' },
- { value: 'option3', label: 'Option 3' }
+ { value: "option1", label: "Option 1" },
+ { value: "option2", label: "Option 2" },
+ { value: "option3", label: "Option 3" },
];
@@ -31,66 +32,95 @@
+
+
+
+ Back to Home
+
+
Root Style Guide
All UI components and their variants
-
+
- Colors
+
+ Colors
+
-
-
Dark
-
#0a0a0f
+
+
Background
+
#05090F
-
-
Surface
-
#14141f
+
+
Night
+
#0A121F
+
+
Light
-
#f0f0f5
+
#E5E6F0
-
+
Primary
-
#6366f1
+
#00A3E0
-
+
Success
-
#22c55e
+
#33E000
-
+
Warning
-
#f59e0b
+
#FFAB00
-
-
-
Info
-
#3b82f6
+
#E03D00
- Buttons
+
+ Buttons
+
-
Variants
+
+ Variants
+
@@ -101,9 +131,10 @@
-
Sizes
+
+ Sizes
+
-
@@ -111,7 +142,9 @@
-
States
+
+ States
+
@@ -120,7 +153,9 @@
-
Full Width
+
+ Full Width
+
@@ -130,45 +165,103 @@
- Textarea
+
+ Textarea
+
-
-
+
+
- Select
+
+ Select
+
-
-
+
+
- Avatars
+
+ Avatars
+
-
Sizes
+
+ Sizes
+
-
With Status
+
+ With Status
+
-
Different Names (Color Generation)
+
+ Different Names (Color Generation)
+
@@ -204,11 +305,17 @@
- Badges
+
+ Badges
+
-
Variants
+
+ Variants
+
Default
Primary
@@ -220,7 +327,9 @@
-
Sizes
+
+ Sizes
+
Small
Medium
@@ -232,31 +341,47 @@
- Cards
+
+ Cards
+
Default Card
- This is a default card with medium padding.
+
+ This is a default card with medium padding.
+
Elevated Card
- This card has a shadow for elevation.
+
+ This card has a shadow for elevation.
+
Outlined Card
- This card has a subtle border.
+
+ This card has a subtle border.
+
- Toggle
+
+ Toggle
+
-
Sizes
+
+ Sizes
+
@@ -274,7 +399,9 @@
-
States
+
+ States
+
@@ -295,11 +422,17 @@
- Spinners
+
+ Spinners
+
-
Sizes
+
+ Sizes
+
@@ -308,7 +441,9 @@
-
Colors
+
+ Colors
+
@@ -322,50 +457,112 @@
- Modal
+
+ Modal
+
-
(modalOpen = false)} title="Example Modal">
+ (modalOpen = false)}
+ title="Example Modal"
+ >
This is an example modal dialog. You can put any content here.
-
+
- Typography
+
+ Typography
+
-
Heading 1 (4xl bold)
-
Heading 2 (3xl bold)
-
Heading 3 (2xl semibold)
-
Heading 4 (xl semibold)
-
Heading 5 (lg medium)
-
Heading 6 (base medium)
+
+ Heading 1 (4xl bold)
+
+
+ Heading 2 (3xl bold)
+
+
+ Heading 3 (2xl semibold)
+
+
+ Heading 4 (xl semibold)
+
+
+ Heading 5 (lg medium)
+
+
+ Heading 6 (base medium)
+
- Body text (base, 80% opacity) - Lorem ipsum dolor sit amet, consectetur adipiscing elit.
- Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+ Body text (base, 80% opacity) - Lorem ipsum dolor sit amet,
+ consectetur adipiscing elit. Sed do eiusmod tempor
+ incididunt ut labore et dolore magna aliqua.
- Small text (sm, 60% opacity) - Used for secondary information and hints.
+ Small text (sm, 60% opacity) - Used for secondary
+ information and hints.
- Extra small text (xs, 40% opacity) - Used for metadata and timestamps.
+ Extra small text (xs, 40% opacity) - Used for metadata and
+ timestamps.
+
+
+
+ Toasts
+
+
+
+
+
+
+
+
+
diff --git a/supabase/migrations/007_org_theme.sql b/supabase/migrations/007_org_theme.sql
new file mode 100644
index 0000000..84c8223
--- /dev/null
+++ b/supabase/migrations/007_org_theme.sql
@@ -0,0 +1,3 @@
+-- Add theme color and icon to organizations
+ALTER TABLE organizations ADD COLUMN IF NOT EXISTS theme_color TEXT DEFAULT '#00a3e0';
+ALTER TABLE organizations ADD COLUMN IF NOT EXISTS icon_url TEXT;
diff --git a/supabase/migrations/008_kanban_enhancements.sql b/supabase/migrations/008_kanban_enhancements.sql
new file mode 100644
index 0000000..5e71642
--- /dev/null
+++ b/supabase/migrations/008_kanban_enhancements.sql
@@ -0,0 +1,42 @@
+-- Add assignee, due date, and checklist support to kanban cards
+
+-- Add assignee_id to kanban_cards (references profiles)
+ALTER TABLE kanban_cards ADD COLUMN IF NOT EXISTS assignee_id UUID REFERENCES profiles(id) ON DELETE SET NULL;
+
+-- Add due_date for SLA/deadline tracking
+ALTER TABLE kanban_cards ADD COLUMN IF NOT EXISTS due_date TIMESTAMPTZ;
+
+-- Add priority field
+ALTER TABLE kanban_cards ADD COLUMN IF NOT EXISTS priority TEXT CHECK (priority IN ('low', 'medium', 'high', 'urgent')) DEFAULT 'medium';
+
+-- Create checklist items table
+CREATE TABLE IF NOT EXISTS kanban_checklist_items (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ card_id UUID NOT NULL REFERENCES kanban_cards(id) ON DELETE CASCADE,
+ title TEXT NOT NULL,
+ completed BOOLEAN DEFAULT false,
+ position INTEGER DEFAULT 0,
+ created_at TIMESTAMPTZ DEFAULT now(),
+ updated_at TIMESTAMPTZ DEFAULT now()
+);
+
+-- Enable RLS on checklist items
+ALTER TABLE kanban_checklist_items ENABLE ROW LEVEL SECURITY;
+
+-- Checklist items inherit access from the card's board -> org
+CREATE POLICY "Checklist items inherit card access" ON kanban_checklist_items
+ FOR ALL USING (
+ EXISTS (
+ SELECT 1 FROM kanban_cards c
+ JOIN kanban_columns col ON c.column_id = col.id
+ JOIN kanban_boards b ON col.board_id = b.id
+ JOIN org_members m ON b.org_id = m.org_id
+ WHERE c.id = kanban_checklist_items.card_id
+ AND m.user_id = auth.uid()
+ )
+ );
+
+-- Create index for faster lookups
+CREATE INDEX IF NOT EXISTS idx_kanban_cards_assignee ON kanban_cards(assignee_id);
+CREATE INDEX IF NOT EXISTS idx_kanban_cards_due_date ON kanban_cards(due_date);
+CREATE INDEX IF NOT EXISTS idx_checklist_items_card ON kanban_checklist_items(card_id);
diff --git a/supabase/migrations/009_activity_tracking.sql b/supabase/migrations/009_activity_tracking.sql
new file mode 100644
index 0000000..dfb1730
--- /dev/null
+++ b/supabase/migrations/009_activity_tracking.sql
@@ -0,0 +1,57 @@
+-- Activity tracking for recent activity feed
+
+CREATE TABLE IF NOT EXISTS activity_log (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ org_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
+ user_id UUID NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
+ action TEXT NOT NULL, -- 'create', 'update', 'delete', 'move', 'assign', etc.
+ entity_type TEXT NOT NULL, -- 'document', 'kanban_card', 'kanban_board', 'member', etc.
+ entity_id UUID,
+ entity_name TEXT,
+ metadata JSONB DEFAULT '{}',
+ created_at TIMESTAMPTZ DEFAULT now()
+);
+
+-- Enable RLS
+ALTER TABLE activity_log ENABLE ROW LEVEL SECURITY;
+
+-- Users can view activity for orgs they belong to
+CREATE POLICY "Users can view org activity" ON activity_log
+ FOR SELECT USING (
+ EXISTS (
+ SELECT 1 FROM org_members m
+ WHERE m.org_id = activity_log.org_id
+ AND m.user_id = auth.uid()
+ )
+ );
+
+-- Users can insert their own activity
+CREATE POLICY "Users can insert own activity" ON activity_log
+ FOR INSERT WITH CHECK (user_id = auth.uid());
+
+-- Indexes for faster queries
+CREATE INDEX IF NOT EXISTS idx_activity_log_org ON activity_log(org_id);
+CREATE INDEX IF NOT EXISTS idx_activity_log_created ON activity_log(created_at DESC);
+CREATE INDEX IF NOT EXISTS idx_activity_log_entity ON activity_log(entity_type, entity_id);
+
+-- User preferences table for themes and settings
+CREATE TABLE IF NOT EXISTS user_preferences (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ user_id UUID NOT NULL REFERENCES profiles(id) ON DELETE CASCADE UNIQUE,
+ theme TEXT DEFAULT 'dark' CHECK (theme IN ('dark', 'light', 'system')),
+ accent_color TEXT DEFAULT '#00A3E0',
+ use_org_theme BOOLEAN DEFAULT true, -- Whether org theme overrides user theme
+ sidebar_collapsed BOOLEAN DEFAULT false,
+ created_at TIMESTAMPTZ DEFAULT now(),
+ updated_at TIMESTAMPTZ DEFAULT now()
+);
+
+-- Enable RLS
+ALTER TABLE user_preferences ENABLE ROW LEVEL SECURITY;
+
+-- Users can manage their own preferences
+CREATE POLICY "Users can manage own preferences" ON user_preferences
+ FOR ALL USING (user_id = auth.uid());
+
+-- Index
+CREATE INDEX IF NOT EXISTS idx_user_preferences_user ON user_preferences(user_id);