import { html, css, type TemplateResult } from '@design.estate/dees-element'; import '@design.estate/dees-catalog/ts_web/elements/00group-utility/dees-icon/dees-icon.js'; export type TWorkspaceView = | 'inbox' | 'compose' | 'sign' | 'audit' | 'developers' | 'templates' | 'team' | 'settings'; export type TWorkspaceTheme = 'dark' | 'light'; export type TDensity = 'compact' | 'comfortable'; export interface IDocumentRow { id: string; title: string; status: 'awaiting' | 'signed' | 'draft' | 'declined'; recipients: Array<{ name: string; initials: string; signed: boolean }>; updated: string; sender: string; pages: number; deadline?: string; } export interface IRecipient { id: number; name: string; email: string; color: string; order: number; } export interface IFieldPlacement { id: string; type: 'signature' | 'date' | 'text' | 'initials' | 'check'; x: number; y: number; w: number; h: number; page: number; recipient: number; label: string; } export const demoDocuments: IDocumentRow[] = [ { id: 'doc_8mK3pL', title: 'Master Services Agreement - Acme Corp', status: 'awaiting', recipients: [{ name: 'Sarah Chen', initials: 'SC', signed: true }, { name: 'David Park', initials: 'DP', signed: false }, { name: 'You', initials: 'PK', signed: true }], updated: '2 min ago', sender: 'You', pages: 14, deadline: 'May 5' }, { id: 'doc_2nQ7vR', title: 'NDA - Helio Robotics', status: 'signed', recipients: [{ name: 'Marcus Tan', initials: 'MT', signed: true }, { name: 'You', initials: 'PK', signed: true }], updated: '1h ago', sender: 'You', pages: 3 }, { id: 'doc_5tH1zM', title: 'Series B Term Sheet (Lead) v3', status: 'awaiting', recipients: [{ name: 'Anna Lindqvist', initials: 'AL', signed: false }, { name: 'Roy Banerjee', initials: 'RB', signed: true }, { name: 'You', initials: 'PK', signed: false }], updated: '3h ago', sender: 'Sequoia Counsel', pages: 22, deadline: 'May 3' }, { id: 'doc_9wB4cX', title: 'Employment Offer - Mira Abebe', status: 'declined', recipients: [{ name: 'Mira Abebe', initials: 'MA', signed: false }, { name: 'You', initials: 'PK', signed: true }], updated: 'yesterday', sender: 'You', pages: 6 }, { id: 'doc_1jF6kY', title: 'Lease - Berlin office Q3', status: 'draft', recipients: [{ name: 'You', initials: 'PK', signed: false }], updated: 'yesterday', sender: 'You', pages: 11 }, { id: 'doc_4dN8sP', title: 'API Reseller Agreement - Northwind', status: 'signed', recipients: [{ name: 'Lila Brooks', initials: 'LB', signed: true }, { name: 'You', initials: 'PK', signed: true }], updated: '2 days ago', sender: 'You', pages: 8 }, ]; export const demoRecipients: IRecipient[] = [ { id: 0, name: 'Sarah Chen', email: 'sarah@acme.com', color: '#60a5fa', order: 1 }, { id: 1, name: 'David Park', email: 'd.park@acme.com', color: '#fbbf24', order: 2 }, { id: 2, name: 'Philipp K.', email: 'philipp@lossless.com', color: '#3b82f6', order: 3 }, ]; export const demoFields: IFieldPlacement[] = [ { id: 'f1', type: 'signature', x: 60, y: 580, w: 200, h: 50, page: 1, recipient: 0, label: 'Signature' }, { id: 'f2', type: 'date', x: 320, y: 580, w: 120, h: 30, page: 1, recipient: 0, label: 'Date' }, { id: 'f3', type: 'text', x: 60, y: 460, w: 280, h: 30, page: 1, recipient: 1, label: 'Full legal name' }, { id: 'f4', type: 'signature', x: 60, y: 700, w: 200, h: 50, page: 1, recipient: 1, label: 'Counter-signature' }, ]; export const workspaceBaseStyles = css` :host { display: flex; flex-direction: column; height: 100%; min-height: 0; color: var(--text); background: var(--bg); font-family: Geist, Inter, Roboto, -apple-system, BlinkMacSystemFont, sans-serif; font-feature-settings: 'cv11', 'tnum', 'cv05' 1; } * { box-sizing: border-box; } button, input, textarea { font: inherit; } button { border: 0; cursor: pointer; } dees-icon { flex-shrink: 0; } .mono { font-family: 'Intel One Mono', ui-monospace, SFMono-Regular, Menlo, monospace; font-variant-numeric: tabular-nums; } .topbar { height: 56px; flex-shrink: 0; padding: 0 24px; display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid var(--border-subtle); background: var(--bg); gap: 12px; } .breadcrumb { font-size: 11px; color: var(--text-muted); display: flex; align-items: center; gap: 5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .top-title { display: flex; align-items: center; gap: 10px; min-width: 0; } .top-title > span:first-child { font-family: 'Plus Jakarta Sans', Inter, sans-serif; font-size: 18px; font-weight: 600; letter-spacing: -0.02em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; } .btn { height: 34px; padding: 0 14px; border-radius: 6px; font-size: 13px; font-weight: 500; letter-spacing: -0.01em; display: inline-flex; align-items: center; justify-content: center; gap: 6px; white-space: nowrap; transition: all 0.12s ease; } .btn.small { height: 28px; padding: 0 10px; font-size: 12px; } .btn.primary { background: var(--accent); color: white; border: 1px solid var(--accent); } .btn.outline { background: transparent; color: var(--text); border: 1px solid var(--border); } .btn.ghost { background: transparent; color: var(--text); border: 1px solid transparent; } .btn:hover { background-color: var(--hover); } .pill { display: inline-flex; align-items: center; gap: 5px; padding: 2px 8px; border-radius: 999px; background: var(--bg-el); color: var(--text-sec); font-size: 11px; font-weight: 500; white-space: nowrap; } .pill::before { content: ''; width: 5px; height: 5px; display: none; border-radius: 50%; background: currentColor; } .pill.dot::before { display: block; } .pill.success { background: rgba(34,197,94,0.12); color: #4ade80; } .pill.warning { background: rgba(245,158,11,0.12); color: #fbbf24; } .pill.error { background: rgba(239,68,68,0.12); color: #f87171; } .pill.info { background: rgba(59,130,246,0.12); color: #60a5fa; } .content-scroll { flex: 1; overflow: auto; padding: 24px; } .card { background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; overflow: hidden; } .label-upper { font-size: 10px; font-weight: 600; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 10px; } .avatar { width: 26px; height: 26px; border-radius: 50%; background: var(--accent); color: white; font-size: 11px; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; } .document-page { position: relative; width: 600px; min-height: 800px; background: white; border-radius: 4px; box-shadow: 0 8px 32px rgba(0,0,0,0.35), 0 0 0 1px rgba(255,255,255,0.05); color: hsl(0 0% 20%); } .fake-document { padding: 48px 56px; font-size: 11px; line-height: 1.7; } .fake-title { font-family: 'Plus Jakarta Sans', Inter, sans-serif; font-size: 18px; font-weight: 700; margin-bottom: 4px; color: hsl(0 0% 10%); } .fake-line { height: 6px; background: hsl(0 0% 82%); margin-bottom: 7px; border-radius: 1px; } .fake-line.heavy { background: hsl(0 0% 65%); } .fake-line.short { width: 70%; } .field-box { position: absolute; left: var(--x); top: var(--y); width: var(--w); height: var(--h); background: color-mix(in srgb, var(--field-color) 13%, transparent); border: 1.5px dashed var(--field-color); border-radius: 3px; cursor: pointer; display: flex; align-items: center; gap: 6px; padding: 0 8px; font-size: 10px; font-weight: 500; color: var(--field-color); } .field-box.selected { border-style: solid; box-shadow: 0 0 0 4px color-mix(in srgb, var(--field-color) 18%, transparent); } .recipient-line { display: flex; align-items: center; gap: 8px; padding: 8px 10px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 6px; font-size: 12px; color: var(--text-sec); margin-bottom: 6px; } .recipient-line.active { background: var(--hover); border-color: var(--border-strong); } .progress-track { height: 4px; background: var(--bg-el); flex-shrink: 0; } .progress-fill { height: 100%; background: var(--accent); transition: width 0.4s ease; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } } @media (max-width: 920px) { .topbar { padding: 0 16px; } .actions { display: none; } .content-scroll { padding: 16px; } } `; export function icon(name: string, size = 14): TemplateResult { const iconMap: Record = { inbox: 'lucide:Inbox', plus: 'lucide:Plus', folder: 'lucide:Folder', shield: 'lucide:Shield', code: 'lucide:Code2', user: 'lucide:User', settings: 'lucide:Settings', upload: 'lucide:Upload', file: 'lucide:FileText', sign: 'lucide:PenTool', clock: 'lucide:Clock', search: 'lucide:Search', more: 'lucide:MoreHorizontal', send: 'lucide:Send', check: 'lucide:Check', eye: 'lucide:Eye', calendar: 'lucide:Calendar', type: 'lucide:Type', download: 'lucide:Download', hash: 'lucide:Hash', github: 'lucide:GitBranch', git: 'lucide:GitBranch', server: 'lucide:Server', star: 'lucide:Star', sparkle: 'lucide:Sparkles', chevronRight: 'lucide:ChevronRight', chevronDown: 'lucide:ChevronDown', x: 'lucide:X', activity: 'lucide:Activity', }; return html``; } export function pill(label: string, tone: 'default' | 'success' | 'warning' | 'error' | 'info' = 'default', dot = false): TemplateResult { return html`${label}`; } export function actionButton(label: string, variant: 'primary' | 'outline' | 'ghost' = 'outline', iconName?: string, onClick?: () => void): TemplateResult { return html``; } export function topBar(config: { breadcrumb: string[]; title: string; subtitle?: TemplateResult; actions?: TemplateResult }): TemplateResult { return html`
${config.title}${config.subtitle || ''}
${config.actions || ''}
`; } export function workspaceDemoFrame(content: TemplateResult, theme: TWorkspaceTheme = 'dark'): TemplateResult { const darkVars = ` --accent: #3b82f6; --bg: hsl(0 0% 3.9%); --bg-el: hsl(0 0% 6%); --bg-card: hsl(0 0% 7%); --bg-input: hsl(0 0% 9%); --border: hsl(0 0% 14.9%); --border-subtle: hsl(0 0% 11%); --border-strong: hsl(0 0% 20%); --text: hsl(0 0% 98%); --text-sec: hsl(0 0% 63.9%); --text-muted: hsl(0 0% 48%); --text-dim: hsl(0 0% 32%); --hover: rgba(255,255,255,0.06); --hover-subtle: rgba(255,255,255,0.03); --row-hover: rgba(255,255,255,0.025); --success: #22c55e; --warning: #f59e0b; --error: #ef4444; `; const lightVars = ` --accent: #3b82f6; --bg: hsl(0 0% 99%); --bg-el: hsl(0 0% 97%); --bg-card: hsl(0 0% 100%); --bg-input: hsl(0 0% 98%); --border: hsl(0 0% 90%); --border-subtle: hsl(0 0% 93%); --border-strong: hsl(0 0% 80%); --text: hsl(0 0% 9%); --text-sec: hsl(0 0% 32%); --text-muted: hsl(0 0% 45%); --text-dim: hsl(0 0% 62%); --hover: rgba(0,0,0,0.04); --hover-subtle: rgba(0,0,0,0.02); --row-hover: rgba(0,0,0,0.02); --success: #16a34a; --warning: #d97706; --error: #dc2626; `; return html`
${content}
`; } export function fakeDocument(): TemplateResult { return html`
Master Services Agreement
Effective: May 2, 2026 · Acme Corp ↔ Lossless GmbH
${Array.from({ length: 18 }).map((_, index) => html`
`)}
${Array.from({ length: 8 }).map((_, index) => html`
`)}
SIGNED ON BEHALF OF ACME CORP
SIGNED ON BEHALF OF LOSSLESS GMBH
`; } export function requestWorkspaceView(element: HTMLElement, view: TWorkspaceView) { element.dispatchEvent(new CustomEvent('workspace-view-request', { detail: { view }, bubbles: true, composed: true, })); }