mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-07-12 21:02:17 +02:00
style(x): unify tab headers and clean up Brain/Home UI
- Shared header treatment across Apps, Background tasks, Workspace, Meetings, Brain: 24px/650 heading, no leading icons, no divider line, centered 1120px column with fixed 34px/30px padding - Apps-style page background on BG tasks, Workspace, Meetings - Brain files view: monochrome then icon-free rows, inline note-count meta line instead of pill chips, semibold item names, uniform row heights, breadcrumb-only navigation, ghost quick actions - Bases toolbar flush with table edge - Meetings: full-width Coming up section - Home: drop Connections/Ask-anything icon tiles, real Slack logo - Sidebar: Apps above Background agents
This commit is contained in:
parent
248bb0d1a1
commit
602889e340
9 changed files with 86 additions and 132 deletions
|
|
@ -58,8 +58,8 @@ const CARD_CSS = `
|
||||||
--ma-pat-opacity:0.05; --ma-glow-opacity:0.10; --ma-glow-hover-opacity:0.16;
|
--ma-pat-opacity:0.05; --ma-glow-opacity:0.10; --ma-glow-hover-opacity:0.16;
|
||||||
--ma-badge-mix:15%; --ma-pill-mix:13%; --ma-tint:20%; --ma-tint-hover:26%;
|
--ma-badge-mix:15%; --ma-pill-mix:13%; --ma-tint:20%; --ma-tint-hover:26%;
|
||||||
}
|
}
|
||||||
.ma-inner { max-width:1120px; margin:0 auto; padding:clamp(20px,3.5cqw,34px) clamp(16px,3cqw,30px) 48px; }
|
.ma-inner { max-width:1120px; margin:0 auto; padding:34px 30px 48px; }
|
||||||
.ma-h1 { font-size:clamp(19px,2.6cqw,24px); font-weight:650; letter-spacing:-0.02em; color:var(--ma-h1); margin:0 0 4px; }
|
.ma-h1 { font-size:24px; font-weight:650; letter-spacing:-0.02em; color:var(--ma-h1); margin:0 0 4px; }
|
||||||
.ma-sub { font-size:clamp(13px,1.5cqw,14px); color:var(--ma-sub); margin:0 0 clamp(14px,2cqw,20px); }
|
.ma-sub { font-size:clamp(13px,1.5cqw,14px); color:var(--ma-sub); margin:0 0 clamp(14px,2cqw,20px); }
|
||||||
.ma-tabs { display:flex; gap:6px; margin-bottom:clamp(14px,2cqw,22px); }
|
.ma-tabs { display:flex; gap:6px; margin-bottom:clamp(14px,2cqw,22px); }
|
||||||
.ma-tab { border:1px solid var(--ma-border); background:transparent; color:var(--ma-sub); border-radius:999px; padding:5px 14px; font-size:13px; font-weight:600; cursor:pointer; }
|
.ma-tab { border:1px solid var(--ma-border); background:transparent; color:var(--ma-sub); border-radius:999px; padding:5px 14px; font-size:13px; font-weight:600; cursor:pointer; }
|
||||||
|
|
|
||||||
|
|
@ -466,7 +466,7 @@ export function BasesView({ tree, onSelectNote, config, onConfigChange, isDefaul
|
||||||
return (
|
return (
|
||||||
<div className="flex-1 flex flex-col overflow-hidden">
|
<div className="flex-1 flex flex-col overflow-hidden">
|
||||||
{/* Toolbar */}
|
{/* Toolbar */}
|
||||||
<div className="shrink-0 border-b border-border px-4 py-2 flex items-center gap-3">
|
<div className="shrink-0 border-b border-border pr-4 py-2 flex items-center gap-3">
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<button className="inline-flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground">
|
<button className="inline-flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground">
|
||||||
|
|
|
||||||
|
|
@ -1733,22 +1733,20 @@ export function BgTasksView({ onCreateWithCopilot, onEditWithCopilot, initialSlu
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full flex-col overflow-hidden">
|
<div className="flex h-full flex-col overflow-hidden bg-[#f8f8f9] dark:bg-[#0b0b0d]">
|
||||||
<div className="shrink-0 border-b border-border px-6 py-5">
|
<div className="mx-auto w-full max-w-[1120px] shrink-0 px-[30px] pt-[34px] pb-5">
|
||||||
<div className="flex items-center justify-between gap-4">
|
<div className="flex items-center justify-between gap-4">
|
||||||
<div className="flex items-center gap-2">
|
<h2 className="text-[24px] font-[650] tracking-[-0.02em] text-[#0d0e11] dark:text-[#f4f5f7]">Background tasks</h2>
|
||||||
<ListChecks className="size-5 text-primary" />
|
|
||||||
<h2 className="text-base font-semibold text-foreground">Background tasks</h2>
|
|
||||||
</div>
|
|
||||||
<Button size="sm" onClick={() => setShowNewDialog(true)}>
|
<Button size="sm" onClick={() => setShowNewDialog(true)}>
|
||||||
New task
|
New task
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-1 text-xs text-muted-foreground">
|
<p className="mt-1 text-[14px] text-black/50 dark:text-white/[0.52]">
|
||||||
Persistent agents that fire on a schedule or in response to events. Toggle a task inactive to pause it.
|
Persistent agents that fire on a schedule or in response to events. Toggle a task inactive to pause it.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 overflow-auto p-6">
|
<div className="flex-1 overflow-auto">
|
||||||
|
<div className="mx-auto h-full w-full max-w-[1120px] px-[30px] pb-12">
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="flex h-full items-center justify-center">
|
<div className="flex h-full items-center justify-center">
|
||||||
<Loader2 className="size-5 animate-spin text-muted-foreground" />
|
<Loader2 className="size-5 animate-spin text-muted-foreground" />
|
||||||
|
|
@ -1885,6 +1883,7 @@ export function BgTasksView({ onCreateWithCopilot, onEditWithCopilot, initialSlu
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<NewTaskDialog
|
<NewTaskDialog
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
import { ArrowRight, Bot, Calendar, Clock, ExternalLink, FileText, Mail, MessageSquare, Mic, Plus, Video } from 'lucide-react'
|
import { ArrowRight, Bot, Calendar, Clock, ExternalLink, FileText, Mail, MessageSquare, Mic, Plus, Video } from 'lucide-react'
|
||||||
import { extractConferenceLink } from '@/lib/calendar-event'
|
import { extractConferenceLink } from '@/lib/calendar-event'
|
||||||
import { ToolConnectionsCard } from '@/components/tool-connections-card'
|
import { ToolConnectionsCard } from '@/components/tool-connections-card'
|
||||||
|
import { SlackIcon } from '@/components/onboarding/provider-icons'
|
||||||
|
|
||||||
interface TreeNode {
|
interface TreeNode {
|
||||||
path: string
|
path: string
|
||||||
|
|
@ -432,7 +433,7 @@ export function HomeView({
|
||||||
{slackEnabled && (
|
{slackEnabled && (
|
||||||
<div className={CARD}>
|
<div className={CARD}>
|
||||||
<div className="mb-3 flex items-center gap-2">
|
<div className="mb-3 flex items-center gap-2">
|
||||||
<MessageSquare className="size-[15px]" />
|
<SlackIcon className="size-[15px]" />
|
||||||
<span className="text-sm font-medium">Slack</span>
|
<span className="text-sm font-medium">Slack</span>
|
||||||
<span className="flex-1" />
|
<span className="flex-1" />
|
||||||
<span className="text-xs text-muted-foreground">Latest messages</span>
|
<span className="text-xs text-muted-foreground">Latest messages</span>
|
||||||
|
|
@ -548,9 +549,6 @@ export function HomeView({
|
||||||
onClick={onOpenChat}
|
onClick={onOpenChat}
|
||||||
className="flex items-center gap-3.5 rounded-xl border border-border bg-card p-4 text-left transition-colors hover:bg-accent"
|
className="flex items-center gap-3.5 rounded-xl border border-border bg-card p-4 text-left transition-colors hover:bg-accent"
|
||||||
>
|
>
|
||||||
<div className="flex size-9 shrink-0 items-center justify-center rounded-lg border border-border bg-card text-muted-foreground">
|
|
||||||
<MessageSquare className="size-[15px]" />
|
|
||||||
</div>
|
|
||||||
<div className="min-w-0 flex-1 text-[13.5px] leading-snug">
|
<div className="min-w-0 flex-1 text-[13.5px] leading-snug">
|
||||||
<span className="font-medium">Ask anything</span>
|
<span className="font-medium">Ask anything</span>
|
||||||
<span className="text-muted-foreground"> — create presentations, do research, collaborate on docs.</span>
|
<span className="text-muted-foreground"> — create presentations, do research, collaborate on docs.</span>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'
|
import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'
|
||||||
import {
|
import {
|
||||||
ArrowLeft,
|
|
||||||
ChevronRight,
|
ChevronRight,
|
||||||
Copy,
|
Copy,
|
||||||
ExternalLink,
|
ExternalLink,
|
||||||
|
|
@ -70,20 +69,6 @@ const HIDDEN_PATHS = new Set(['knowledge/Meetings', 'knowledge/Workspace'])
|
||||||
|
|
||||||
// Theme-aware accent palette for folder avatars — colored letter on a faint
|
// Theme-aware accent palette for folder avatars — colored letter on a faint
|
||||||
// tint of the same hue. Mirrors the design's six-colour rotation.
|
// tint of the same hue. Mirrors the design's six-colour rotation.
|
||||||
const AVATAR_PALETTE = [
|
|
||||||
'bg-indigo-500/10 text-indigo-600 dark:text-indigo-400',
|
|
||||||
'bg-violet-500/10 text-violet-600 dark:text-violet-400',
|
|
||||||
'bg-amber-500/10 text-amber-600 dark:text-amber-400',
|
|
||||||
'bg-rose-500/10 text-rose-600 dark:text-rose-400',
|
|
||||||
'bg-emerald-500/10 text-emerald-600 dark:text-emerald-400',
|
|
||||||
'bg-sky-500/10 text-sky-600 dark:text-sky-400',
|
|
||||||
] as const
|
|
||||||
|
|
||||||
function avatarClass(name: string): string {
|
|
||||||
let hash = 0
|
|
||||||
for (let i = 0; i < name.length; i++) hash = (hash * 31 + name.charCodeAt(i)) >>> 0
|
|
||||||
return AVATAR_PALETTE[hash % AVATAR_PALETTE.length]
|
|
||||||
}
|
|
||||||
|
|
||||||
function isMarkdown(node: TreeNode): boolean {
|
function isMarkdown(node: TreeNode): boolean {
|
||||||
return node.kind === 'file' && node.name.toLowerCase().endsWith('.md')
|
return node.kind === 'file' && node.name.toLowerCase().endsWith('.md')
|
||||||
|
|
@ -204,10 +189,10 @@ export function KnowledgeView({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full flex-col overflow-hidden">
|
<div className="flex h-full flex-col overflow-hidden">
|
||||||
<div className="shrink-0 flex items-start justify-between gap-4 border-b border-border px-8 py-6">
|
<div className="mx-auto w-full max-w-[1120px] shrink-0 flex items-start justify-between gap-4 px-[30px] pt-[34px] pb-5">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<h1 className="text-2xl font-bold tracking-tight">Brain</h1>
|
<h1 className="text-[24px] font-[650] tracking-[-0.02em] text-[#0d0e11] dark:text-[#f4f5f7]">Brain</h1>
|
||||||
<p className="mt-1 text-sm text-muted-foreground">
|
<p className="mt-1 text-[14px] text-black/50 dark:text-white/[0.52]">
|
||||||
{totalNotes} {totalNotes === 1 ? 'note' : 'notes'} across {folders.length}{' '}
|
{totalNotes} {totalNotes === 1 ? 'note' : 'notes'} across {folders.length}{' '}
|
||||||
{folders.length === 1 ? 'folder' : 'folders'}
|
{folders.length === 1 ? 'folder' : 'folders'}
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -242,12 +227,12 @@ export function KnowledgeView({
|
||||||
{graphContent}
|
{graphContent}
|
||||||
</div>
|
</div>
|
||||||
) : mode === 'basis' ? (
|
) : mode === 'basis' ? (
|
||||||
<div className="flex-1 min-h-0 overflow-hidden">
|
<div className="mx-auto flex w-full max-w-[1120px] flex-1 min-h-0 flex-col overflow-hidden px-[30px] pb-6">
|
||||||
{basisContent}
|
{basisContent}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex-1 overflow-y-auto">
|
<div className="flex-1 overflow-y-auto">
|
||||||
<div className="mx-auto w-full max-w-3xl px-8 py-6">
|
<div className="mx-auto w-full max-w-[1120px] px-[30px] py-6">
|
||||||
{currentFolder ? (
|
{currentFolder ? (
|
||||||
<FolderDetail
|
<FolderDetail
|
||||||
folder={currentFolder}
|
folder={currentFolder}
|
||||||
|
|
@ -261,7 +246,7 @@ export function KnowledgeView({
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<SectionHeader label={`Folders · ${folders.length}`} aside="Sorted by name" />
|
<SectionHeader label={`Folders · ${folders.length}`} />
|
||||||
{folders.length === 0 ? (
|
{folders.length === 0 ? (
|
||||||
<EmptyState text="No folders yet." />
|
<EmptyState text="No folders yet." />
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -398,9 +383,9 @@ function QuickAction({
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
className="inline-flex items-center gap-2 rounded-lg border border-border bg-background px-3 py-2 text-sm text-foreground transition-colors hover:bg-accent"
|
className="inline-flex items-center gap-2 rounded-md px-2.5 py-1.5 text-sm text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
|
||||||
>
|
>
|
||||||
<Icon className="size-4 text-muted-foreground" />
|
<Icon className="size-4" />
|
||||||
<span>{label}</span>
|
<span>{label}</span>
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
|
|
@ -425,20 +410,6 @@ function EmptyState({ text }: { text: string }) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function FolderAvatar({ name, className }: { name: string; className?: string }) {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={cn(
|
|
||||||
'flex size-8 shrink-0 items-center justify-center rounded-md text-[13px] font-bold',
|
|
||||||
avatarClass(name),
|
|
||||||
className,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{name.charAt(0).toUpperCase() || '?'}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function FolderCard({
|
function FolderCard({
|
||||||
node,
|
node,
|
||||||
actions,
|
actions,
|
||||||
|
|
@ -472,9 +443,8 @@ function FolderCard({
|
||||||
onOpenFolder(node.path)
|
onOpenFolder(node.path)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className="group flex w-full cursor-pointer items-start gap-3 px-4 py-3 text-left transition-colors hover:bg-accent/50"
|
className="group flex w-full cursor-pointer items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-accent/50"
|
||||||
>
|
>
|
||||||
<FolderAvatar name={node.name} className="mt-0.5" />
|
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
{renameActive ? (
|
{renameActive ? (
|
||||||
<RenameField
|
<RenameField
|
||||||
|
|
@ -489,28 +459,32 @@ function FolderCard({
|
||||||
{node.name}
|
{node.name}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<div className="mt-0.5 text-xs text-muted-foreground">
|
<div className="mt-0.5 flex min-w-0 items-baseline gap-1.5 text-xs text-muted-foreground">
|
||||||
{count} {count === 1 ? 'note' : 'notes'}
|
<span className="shrink-0">
|
||||||
|
{count} {count === 1 ? 'note' : 'notes'}
|
||||||
|
</span>
|
||||||
|
{peek.length > 0 && (
|
||||||
|
<span className="truncate text-muted-foreground/70">
|
||||||
|
{peek.map((n) => (
|
||||||
|
<span key={n.path}>
|
||||||
|
<span className="text-muted-foreground/40">{' · '}</span>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
onOpenNote(n.path)
|
||||||
|
}}
|
||||||
|
className="transition-colors hover:text-foreground hover:underline"
|
||||||
|
>
|
||||||
|
{displayName(n)}
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{peek.length > 0 && (
|
|
||||||
<div className="mt-2 flex flex-wrap gap-1.5">
|
|
||||||
{peek.map((n) => (
|
|
||||||
<button
|
|
||||||
key={n.path}
|
|
||||||
type="button"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation()
|
|
||||||
onOpenNote(n.path)
|
|
||||||
}}
|
|
||||||
className="max-w-[200px] truncate rounded-full border border-border/60 bg-muted px-2.5 py-0.5 text-xs text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
|
|
||||||
>
|
|
||||||
{displayName(n)}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex shrink-0 items-center gap-2 pt-1">
|
<div className="flex shrink-0 items-center gap-2">
|
||||||
<span className="text-xs text-muted-foreground tabular-nums whitespace-nowrap">
|
<span className="text-xs text-muted-foreground tabular-nums whitespace-nowrap">
|
||||||
{modified}
|
{modified}
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -565,17 +539,6 @@ function FolderDetail({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="mb-4 flex min-w-0 items-center gap-1.5 text-sm">
|
<div className="mb-4 flex min-w-0 items-center gap-1.5 text-sm">
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => {
|
|
||||||
const parent = crumbs.length >= 2 ? crumbs[crumbs.length - 2].path : null
|
|
||||||
onNavigate(parent)
|
|
||||||
}}
|
|
||||||
className="inline-flex items-center gap-1 rounded-md px-1.5 py-1 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
|
|
||||||
aria-label="Back"
|
|
||||||
>
|
|
||||||
<ArrowLeft className="size-4" />
|
|
||||||
</button>
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => onNavigate(null)}
|
onClick={() => onNavigate(null)}
|
||||||
|
|
@ -665,13 +628,6 @@ function ItemRow({
|
||||||
}}
|
}}
|
||||||
className="group flex w-full cursor-pointer items-center gap-3 px-4 py-2.5 text-left transition-colors hover:bg-accent/50"
|
className="group flex w-full cursor-pointer items-center gap-3 px-4 py-2.5 text-left transition-colors hover:bg-accent/50"
|
||||||
>
|
>
|
||||||
{isDir ? (
|
|
||||||
<FolderAvatar name={node.name} />
|
|
||||||
) : (
|
|
||||||
<div className="flex size-8 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground">
|
|
||||||
<FileText className="size-4" />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
{renameActive ? (
|
{renameActive ? (
|
||||||
<RenameField
|
<RenameField
|
||||||
|
|
@ -682,16 +638,21 @@ function ItemRow({
|
||||||
onDone={onClearRename}
|
onDone={onClearRename}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<span className="block truncate text-sm text-foreground">{displayName(node)}</span>
|
<span className="block truncate text-sm font-semibold text-foreground">
|
||||||
)}
|
{displayName(node)}
|
||||||
{isDir && (
|
</span>
|
||||||
<div className="mt-0.5 text-xs text-muted-foreground">
|
|
||||||
{count} {count === 1 ? 'note' : 'notes'}
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex shrink-0 items-center gap-2">
|
<div className="flex shrink-0 items-center gap-2 text-xs text-muted-foreground">
|
||||||
<span className="text-xs text-muted-foreground tabular-nums whitespace-nowrap">
|
{isDir && (
|
||||||
|
<>
|
||||||
|
<span className="whitespace-nowrap">
|
||||||
|
{count} {count === 1 ? 'note' : 'notes'}
|
||||||
|
</span>
|
||||||
|
<span className="text-muted-foreground/40">·</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<span className="tabular-nums whitespace-nowrap">
|
||||||
{modified}
|
{modified}
|
||||||
</span>
|
</span>
|
||||||
{isDir && (
|
{isDir && (
|
||||||
|
|
|
||||||
|
|
@ -711,8 +711,8 @@ function UpcomingEvents({ onOpenNote }: { onOpenNote: (path: string) => void })
|
||||||
const todayKey = localDateKey(now)
|
const todayKey = localDateKey(now)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="border-b border-border/60 px-6 pb-6 pt-5">
|
<section className="border-b border-border/60 pb-6 pt-5">
|
||||||
<div className="mx-auto w-full max-w-[760px]">
|
<div className="w-full">
|
||||||
<div className="mb-3 flex items-baseline justify-between">
|
<div className="mb-3 flex items-baseline justify-between">
|
||||||
<h3 className="text-sm font-semibold text-foreground flex items-center gap-2">
|
<h3 className="text-sm font-semibold text-foreground flex items-center gap-2">
|
||||||
<Calendar className="size-4 text-muted-foreground" />
|
<Calendar className="size-4 text-muted-foreground" />
|
||||||
|
|
@ -1243,13 +1243,10 @@ export function MeetingsView({ onOpenNote, onTakeMeetingNotes, meetingState, mee
|
||||||
const isRecording = meetingState === 'recording'
|
const isRecording = meetingState === 'recording'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full flex-col overflow-hidden">
|
<div className="flex h-full flex-col overflow-hidden bg-[#f8f8f9] dark:bg-[#0b0b0d]">
|
||||||
<div className="shrink-0 border-b border-border px-6 py-5">
|
<div className="mx-auto w-full max-w-[1120px] shrink-0 px-[30px] pt-[34px] pb-5">
|
||||||
<div className="flex items-center justify-between gap-4">
|
<div className="flex items-center justify-between gap-4">
|
||||||
<div className="flex items-center gap-2">
|
<h2 className="text-[24px] font-[650] tracking-[-0.02em] text-[#0d0e11] dark:text-[#f4f5f7]">Meetings</h2>
|
||||||
<Mic className="size-5 text-primary" />
|
|
||||||
<h2 className="text-base font-semibold text-foreground">Meetings</h2>
|
|
||||||
</div>
|
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
@ -1267,13 +1264,14 @@ export function MeetingsView({ onOpenNote, onTakeMeetingNotes, meetingState, mee
|
||||||
{meetingSummarizing ? 'Generating notes...' : getMeetingButtonLabel(meetingState)}
|
{meetingSummarizing ? 'Generating notes...' : getMeetingButtonLabel(meetingState)}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-1 text-xs text-muted-foreground">
|
<p className="mt-1 text-[14px] text-black/50 dark:text-white/[0.52]">
|
||||||
Upcoming events and meeting notes.
|
Upcoming events and meeting notes.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 overflow-auto">
|
<div className="flex-1 overflow-auto">
|
||||||
|
<div className="mx-auto w-full max-w-[1120px] px-[30px] pb-12">
|
||||||
<UpcomingEvents onOpenNote={onOpenNote} />
|
<UpcomingEvents onOpenNote={onOpenNote} />
|
||||||
<div className="p-6">
|
<div className="pt-6">
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="flex items-center justify-center py-10">
|
<div className="flex items-center justify-center py-10">
|
||||||
<Loader2 className="size-5 animate-spin text-muted-foreground" />
|
<Loader2 className="size-5 animate-spin text-muted-foreground" />
|
||||||
|
|
@ -1329,6 +1327,7 @@ export function MeetingsView({ onOpenNote, onTakeMeetingNotes, meetingState, mee
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -890,6 +890,16 @@ export function SidebarContentPanel({
|
||||||
<div className="mx-3 my-2 border-t border-sidebar-border" />
|
<div className="mx-3 my-2 border-t border-sidebar-border" />
|
||||||
|
|
||||||
<SidebarMenu>
|
<SidebarMenu>
|
||||||
|
<SidebarMenuItem>
|
||||||
|
<SidebarMenuButton
|
||||||
|
data-tour-id="nav-apps"
|
||||||
|
isActive={activeNav === 'apps'}
|
||||||
|
onClick={onOpenApps}
|
||||||
|
>
|
||||||
|
<LayoutGrid className="size-4 shrink-0 text-muted-foreground" />
|
||||||
|
<span className="flex-1 truncate text-muted-foreground">Apps</span>
|
||||||
|
</SidebarMenuButton>
|
||||||
|
</SidebarMenuItem>
|
||||||
<SidebarMenuItem>
|
<SidebarMenuItem>
|
||||||
<SidebarMenuButton
|
<SidebarMenuButton
|
||||||
data-tour-id="nav-agents"
|
data-tour-id="nav-agents"
|
||||||
|
|
@ -911,16 +921,6 @@ export function SidebarContentPanel({
|
||||||
</div>
|
</div>
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
||||||
<SidebarMenuItem>
|
|
||||||
<SidebarMenuButton
|
|
||||||
data-tour-id="nav-apps"
|
|
||||||
isActive={activeNav === 'apps'}
|
|
||||||
onClick={onOpenApps}
|
|
||||||
>
|
|
||||||
<LayoutGrid className="size-4 shrink-0 text-muted-foreground" />
|
|
||||||
<span className="flex-1 truncate text-muted-foreground">Apps</span>
|
|
||||||
</SidebarMenuButton>
|
|
||||||
</SidebarMenuItem>
|
|
||||||
<SidebarMenuItem>
|
<SidebarMenuItem>
|
||||||
<SidebarMenuButton
|
<SidebarMenuButton
|
||||||
data-tour-id="nav-workspaces"
|
data-tour-id="nav-workspaces"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { useCallback, useEffect, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
import { ArrowRight, Plug } from 'lucide-react'
|
import { ArrowRight } from 'lucide-react'
|
||||||
|
|
||||||
import { SettingsDialog } from '@/components/settings-dialog'
|
import { SettingsDialog } from '@/components/settings-dialog'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
@ -101,9 +101,6 @@ export function ToolConnectionsCard({ className }: { className?: string }) {
|
||||||
<>
|
<>
|
||||||
<div className={cn('rounded-xl border border-border bg-card p-4', className)}>
|
<div className={cn('rounded-xl border border-border bg-card p-4', className)}>
|
||||||
<div className="flex items-start gap-3">
|
<div className="flex items-start gap-3">
|
||||||
<div className="flex size-8 shrink-0 items-center justify-center rounded-lg border border-border bg-muted text-muted-foreground">
|
|
||||||
<Plug className="size-[14px]" />
|
|
||||||
</div>
|
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<div className="text-[13.5px] leading-snug">
|
<div className="text-[13.5px] leading-snug">
|
||||||
<span className="text-muted-foreground">Bring context from and take action in the apps you already use.</span>
|
<span className="text-muted-foreground">Bring context from and take action in the apps you already use.</span>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import {
|
||||||
Folder as FolderIcon,
|
Folder as FolderIcon,
|
||||||
FolderOpen,
|
FolderOpen,
|
||||||
FolderPlus,
|
FolderPlus,
|
||||||
Home,
|
|
||||||
Loader2,
|
Loader2,
|
||||||
MessageSquare,
|
MessageSquare,
|
||||||
Pencil,
|
Pencil,
|
||||||
|
|
@ -365,19 +364,18 @@ export function WorkspaceView({ tree, initialPath, actions, onNavigate, onOpenNo
|
||||||
}, [newName, onCreateWorkspace, resetAddDialog])
|
}, [newName, onCreateWorkspace, resetAddDialog])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full flex-col overflow-hidden">
|
<div className="flex h-full flex-col overflow-hidden bg-[#f8f8f9] dark:bg-[#0b0b0d]">
|
||||||
<div className="flex shrink-0 items-center justify-between gap-3 border-b border-border px-6 py-4">
|
<div className="mx-auto flex w-full max-w-[1120px] shrink-0 items-center justify-between gap-3 pl-[22px] pr-[30px] pt-[30px] pb-4">
|
||||||
<div className="flex min-w-0 items-center gap-1 text-sm">
|
<div className="flex min-w-0 items-center gap-1 text-sm">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => onNavigate(WORKSPACE_ROOT)}
|
onClick={() => onNavigate(WORKSPACE_ROOT)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex items-center gap-1.5 rounded-md px-2 py-1 transition-colors',
|
'inline-flex items-center rounded-md px-2 py-1 transition-colors',
|
||||||
isRoot ? 'text-foreground' : 'text-muted-foreground hover:text-foreground hover:bg-accent',
|
isRoot ? 'text-[#0d0e11] dark:text-[#f4f5f7]' : 'text-muted-foreground hover:text-foreground hover:bg-accent',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Home className="size-4" />
|
<span className="text-[24px] font-[650] tracking-[-0.02em]">Workspace</span>
|
||||||
<span className="font-medium">Workspace</span>
|
|
||||||
</button>
|
</button>
|
||||||
{breadcrumbs.map((crumb, idx) => {
|
{breadcrumbs.map((crumb, idx) => {
|
||||||
const isLast = idx === breadcrumbs.length - 1
|
const isLast = idx === breadcrumbs.length - 1
|
||||||
|
|
@ -482,12 +480,13 @@ export function WorkspaceView({ tree, initialPath, actions, onNavigate, onOpenNo
|
||||||
|
|
||||||
<div className="flex flex-1 overflow-hidden">
|
<div className="flex flex-1 overflow-hidden">
|
||||||
<div
|
<div
|
||||||
className="relative flex-1 overflow-y-auto px-6 py-6"
|
className="relative flex-1 overflow-y-auto"
|
||||||
onDragEnter={handleDragEnter}
|
onDragEnter={handleDragEnter}
|
||||||
onDragOver={handleDragOver}
|
onDragOver={handleDragOver}
|
||||||
onDragLeave={handleDragLeave}
|
onDragLeave={handleDragLeave}
|
||||||
onDrop={handleDrop}
|
onDrop={handleDrop}
|
||||||
>
|
>
|
||||||
|
<div className="mx-auto h-full w-full max-w-[1120px] px-[30px] py-6">
|
||||||
{items.length === 0 ? (
|
{items.length === 0 ? (
|
||||||
<div className="flex h-full flex-col items-center justify-center gap-3 text-center text-muted-foreground">
|
<div className="flex h-full flex-col items-center justify-center gap-3 text-center text-muted-foreground">
|
||||||
<FolderIcon className="size-10 opacity-50" />
|
<FolderIcon className="size-10 opacity-50" />
|
||||||
|
|
@ -594,6 +593,7 @@ export function WorkspaceView({ tree, initialPath, actions, onNavigate, onOpenNo
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{dropEnabled && isDraggingOver && (
|
{dropEnabled && isDraggingOver && (
|
||||||
<div className="pointer-events-none absolute inset-3 z-10 flex flex-col items-center justify-center gap-2 rounded-xl border-2 border-dashed border-primary/60 bg-primary/5 text-primary">
|
<div className="pointer-events-none absolute inset-3 z-10 flex flex-col items-center justify-center gap-2 rounded-xl border-2 border-dashed border-primary/60 bg-primary/5 text-primary">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue