indas-ui 0.1.10 → 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/chat/multimodal-input.js +1 -1
- package/dist/cjs/components/dashboard/FilterBar.js +5 -3
- package/dist/cjs/components/datagrid/DataGrid.js +3 -3
- package/dist/cjs/components/datagrid/rows/FilterRow.js +1 -1
- package/dist/cjs/components/draft/DraftModal.js +1 -1
- package/dist/cjs/components/forms/date-picker/DateTimePicker.js +1 -1
- package/dist/cjs/components/forms/dropdown/Dropdown.js +1 -1
- package/dist/cjs/components/forms/file-attachment/FileAttachment.js +1 -1
- package/dist/cjs/components/forms/remark-input/RemarkInput.js +3 -3
- package/dist/cjs/components/layout/mobile-menu-sheet.js +1 -1
- package/dist/cjs/components/layout/top-header.js +1 -1
- package/dist/cjs/components/messaging/conversation-list.js +1 -1
- package/dist/cjs/components/messaging/create-conversation-modal.js +1 -1
- package/dist/cjs/components/messaging/message-input.js +1 -1
- package/dist/cjs/components/modals/ImageModal.js +1 -1
- package/dist/cjs/components/modals/Modal.js +1 -1
- package/dist/cjs/components/ui/buttons/button.js +1 -1
- package/dist/cjs/components/ui/form-toggle.js +1 -1
- package/dist/cjs/components/ui/forms/input.js +4 -4
- package/dist/cjs/components/ui/navigation/tabs.js +2 -2
- package/dist/cjs/styles/tokens.css +3 -0
- package/dist/components/chat/multimodal-input.js +1 -1
- package/dist/components/dashboard/FilterBar.js +5 -3
- package/dist/components/datagrid/DataGrid.js +3 -3
- package/dist/components/datagrid/rows/FilterRow.js +1 -1
- package/dist/components/draft/DraftModal.js +1 -1
- package/dist/components/forms/date-picker/DateTimePicker.js +1 -1
- package/dist/components/forms/dropdown/Dropdown.d.ts +1 -1
- package/dist/components/forms/dropdown/Dropdown.js +1 -1
- package/dist/components/forms/file-attachment/FileAttachment.js +1 -1
- package/dist/components/forms/remark-input/RemarkInput.js +3 -3
- package/dist/components/layout/mobile-menu-sheet.js +1 -1
- package/dist/components/layout/top-header.js +1 -1
- package/dist/components/messaging/conversation-list.js +1 -1
- package/dist/components/messaging/create-conversation-modal.js +1 -1
- package/dist/components/messaging/message-input.js +1 -1
- package/dist/components/modals/ImageModal.js +1 -1
- package/dist/components/modals/Modal.js +1 -1
- package/dist/components/ui/buttons/button.js +1 -1
- package/dist/components/ui/form-toggle.js +1 -1
- package/dist/components/ui/forms/input.js +4 -4
- package/dist/components/ui/navigation/tabs.js +2 -2
- package/dist/styles/tokens.css +3 -0
- package/package.json +1 -1
|
@@ -22,6 +22,9 @@
|
|
|
22
22
|
|
|
23
23
|
/* Primary Color System (Main brand/accent) - Default #003366 */
|
|
24
24
|
--color-primary: 0 51 102; /* Primary brand color #003366 */
|
|
25
|
+
/* What a focused field or button is outlined in. The brand colour unless the app says
|
|
26
|
+
otherwise: an app that keeps its brand colour for primary actions sets a neutral here. */
|
|
27
|
+
--color-focus: var(--color-primary);
|
|
25
28
|
--color-primary-hover: 0 40 82; /* Primary hover state - darker #003366 */
|
|
26
29
|
--color-primary-subtle: 250 251 252; /* Very light primary backgrounds (0.02 opacity equivalent) */
|
|
27
30
|
--color-primary-muted: 102 153 204; /* Muted primary */
|
|
@@ -110,7 +110,7 @@ export function MultimodalInput({ onSubmit, onStop, isLoading = false, placehold
|
|
|
110
110
|
const removeFile = (index) => {
|
|
111
111
|
setFiles(prev => prev.filter((_, i) => i !== index));
|
|
112
112
|
};
|
|
113
|
-
return (_jsx("div", { className: cn("bg-[rgb(var(--bg-surface))] shrink-0", compact ? "px-1 py-1" : "border-t border-[rgb(var(--bd-default))] px-4 py-2.5"), children: _jsxs("div", { className: "max-w-3xl mx-auto", children: [disabled && disabledReason && (_jsxs("div", { className: "mb-2 px-3 py-2 rounded-lg bg-amber-500/10 border border-amber-500/30 text-xs text-amber-700 dark:text-amber-400 flex items-center gap-2", children: [_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "shrink-0", children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" }), _jsx("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })] }), _jsx("span", { children: disabledReason })] })), files.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-2 mb-3", children: files.map((file, index) => (_jsxs("div", { className: "flex items-center gap-2 px-3 py-2 bg-[rgb(var(--bg-app))] border border-[rgb(var(--bd-default))] rounded-lg text-sm", children: [file.type.startsWith('image/') ? (_jsx(ImageIcon, { className: "w-4 h-4 text-[rgb(var(--fg-muted))]" })) : /\.(xlsx|xls|csv)$/i.test(file.name) ? (_jsx(FileSpreadsheet, { className: "w-4 h-4 text-[rgb(var(--fg-muted))]" })) : (_jsx(FileIcon, { className: "w-4 h-4 text-[rgb(var(--fg-muted))]" })), _jsx("span", { className: "text-[rgb(var(--fg-default))] truncate max-w-[150px]", children: file.name }), _jsx("button", { type: "button", onClick: () => removeFile(index), "aria-label": `Remove ${file.name}`, className: "text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] transition-colors", children: _jsx(X, { className: "w-3 h-3" }) })] }, index))) })), _jsxs("div", { className: cn("relative flex items-center gap-1 bg-[rgb(var(--bg-app))]/60 backdrop-blur-xl border border-[rgb(var(--bd-default))] shadow-lg transition-all duration-250 focus-within:border-[rgb(var(--color-
|
|
113
|
+
return (_jsx("div", { className: cn("bg-[rgb(var(--bg-surface))] shrink-0", compact ? "px-1 py-1" : "border-t border-[rgb(var(--bd-default))] px-4 py-2.5"), children: _jsxs("div", { className: "max-w-3xl mx-auto", children: [disabled && disabledReason && (_jsxs("div", { className: "mb-2 px-3 py-2 rounded-lg bg-amber-500/10 border border-amber-500/30 text-xs text-amber-700 dark:text-amber-400 flex items-center gap-2", children: [_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "shrink-0", children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" }), _jsx("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })] }), _jsx("span", { children: disabledReason })] })), files.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-2 mb-3", children: files.map((file, index) => (_jsxs("div", { className: "flex items-center gap-2 px-3 py-2 bg-[rgb(var(--bg-app))] border border-[rgb(var(--bd-default))] rounded-lg text-sm", children: [file.type.startsWith('image/') ? (_jsx(ImageIcon, { className: "w-4 h-4 text-[rgb(var(--fg-muted))]" })) : /\.(xlsx|xls|csv)$/i.test(file.name) ? (_jsx(FileSpreadsheet, { className: "w-4 h-4 text-[rgb(var(--fg-muted))]" })) : (_jsx(FileIcon, { className: "w-4 h-4 text-[rgb(var(--fg-muted))]" })), _jsx("span", { className: "text-[rgb(var(--fg-default))] truncate max-w-[150px]", children: file.name }), _jsx("button", { type: "button", onClick: () => removeFile(index), "aria-label": `Remove ${file.name}`, className: "text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] transition-colors", children: _jsx(X, { className: "w-3 h-3" }) })] }, index))) })), _jsxs("div", { className: cn("relative flex items-center gap-1 bg-[rgb(var(--bg-app))]/60 backdrop-blur-xl border border-[rgb(var(--bd-default))] shadow-lg transition-all duration-250 focus-within:border-[rgb(var(--color-focus))] focus-within:shadow-[0_0_0_4px_rgb(var(--color-focus)/0.12),0_20px_25px_-5px_rgba(0,0,0,0.15)] focus-within:-translate-y-px", compact ? "rounded-xl p-1.5" : "rounded-2xl p-2.5"), children: [allowFileUpload && (_jsxs(_Fragment, { children: [_jsx("input", { ref: fileInputRef, type: "file", multiple: multiple, accept: accept, onChange: handleFileSelect, className: "hidden" }), _jsx("button", { onClick: () => fileInputRef.current?.click(), className: "shrink-0 !min-h-0 w-9 h-9 rounded-lg flex items-center justify-center transition-colors text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))]", "aria-label": attachLabel, title: attachLabel, children: attachIcon ?? _jsx(Paperclip, { className: "w-4 h-4" }) })] })), _jsx("textarea", { ref: textareaRef, "data-chat-input": true, value: input, onChange: (e) => setInput(e.target.value), onKeyDown: handleKeyDown, placeholder: disabled ? t('Conversation closed — start a new chat')
|
|
114
114
|
: isListening ? t('Listening...')
|
|
115
115
|
: placeholder, disabled: isListening || disabled, autoFocus: !disabled, rows: 1, className: cn('flex-1 bg-transparent text-[rgb(var(--fg-default))] placeholder:text-[rgb(var(--fg-muted))]', 'resize-none outline-none text-sm', compact ? 'px-2 py-1.5 max-h-[120px]' : 'px-3 py-2.5 max-h-[200px]', 'overflow-y-auto', disabled && 'cursor-not-allowed') }), speechSupported && (_jsx("button", { onClick: handleVoiceInput, className: cn('shrink-0 !min-h-0 w-9 h-9 rounded-lg flex items-center justify-center transition-colors', isListening
|
|
116
116
|
? 'text-red-500 bg-red-500/10 animate-pulse'
|
|
@@ -267,7 +267,7 @@ function Stepper({ value, min, max, onChange }) {
|
|
|
267
267
|
onChange(clamped);
|
|
268
268
|
};
|
|
269
269
|
const buttonClasses = cn('w-7 h-7 rounded-md flex items-center justify-center transition-colors shrink-0', 'border border-[rgb(var(--bd-default))] text-[rgb(var(--fg-muted))]', 'hover:bg-[rgb(var(--bg-subtle))] disabled:opacity-40 disabled:pointer-events-none');
|
|
270
|
-
return (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("button", { onClick: () => onChange(value - 1), disabled: value <= min, className: buttonClasses, children: _jsx(Minus, { className: "w-3.5 h-3.5" }) }), _jsx("input", { value: text, onChange: (e) => setText(e.target.value.replace(/\D/g, '')), onBlur: commit, onKeyDown: (e) => e.key === 'Enter' && e.target.blur(), inputMode: "numeric", className: cn('flex-1 h-7 w-full min-w-0 rounded-md border border-[rgb(var(--bd-default))] bg-transparent', 'text-center text-xs font-semibold text-[rgb(var(--fg-default))]', 'focus:outline-none focus:border-[rgb(var(--color-
|
|
270
|
+
return (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("button", { onClick: () => onChange(value - 1), disabled: value <= min, className: buttonClasses, children: _jsx(Minus, { className: "w-3.5 h-3.5" }) }), _jsx("input", { value: text, onChange: (e) => setText(e.target.value.replace(/\D/g, '')), onBlur: commit, onKeyDown: (e) => e.key === 'Enter' && e.target.blur(), inputMode: "numeric", className: cn('flex-1 h-7 w-full min-w-0 rounded-md border border-[rgb(var(--bd-default))] bg-transparent', 'text-center text-xs font-semibold text-[rgb(var(--fg-default))]', 'focus:outline-none focus:border-[rgb(var(--color-focus))]') }), _jsx("button", { onClick: () => onChange(value + 1), disabled: value >= max, className: buttonClasses, children: _jsx(Plus, { className: "w-3.5 h-3.5" }) })] }));
|
|
271
271
|
}
|
|
272
272
|
function OverflowMenu({ showInsights, insightsActive, onInsightsClick, reports, onReportSelect, onShare, onExport }) {
|
|
273
273
|
const { t } = useLanguage();
|
|
@@ -411,7 +411,9 @@ export function FilterBar({ title, contextLabel, description, secondaryToggle, t
|
|
|
411
411
|
} }))] }), _jsxs("div", { className: "flex-1 text-center", children: [_jsx("h1", { className: "text-sm font-semibold text-[rgb(var(--fg-default))]", children: title }), contextLabel && (_jsx("span", { className: "text-xs text-[rgb(var(--fg-muted))]", children: contextLabel })), description && _jsx("p", { className: "mt-0.5 text-xs text-[rgb(var(--fg-muted))]", children: description })] }), _jsxs("div", { className: "flex items-center gap-3", children: [!hideFilterButton && (_jsxs("div", { className: "relative", children: [_jsxs("button", { ref: buttonRef, onClick: () => setPopoverOpen(!popoverOpen), className: cn('w-8 h-8 rounded-md flex items-center justify-center transition-colors relative', 'border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))]', 'text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-subtle))] hover:border-[rgb(var(--color-primary))] hover:text-[rgb(var(--color-primary))]', popoverOpen && 'bg-[rgb(var(--color-primary))] text-white border-[rgb(var(--color-primary))] hover:bg-[rgb(var(--color-primary))]'), title: "Filters", children: [_jsx(ListFilter, { className: "w-4 h-4" }), hasActiveFilters && !popoverOpen && (_jsx("span", { className: "absolute -top-1 -right-1 w-2 h-2 bg-[rgb(var(--color-primary))] rounded-full" }))] }), popoverOpen && (_jsxs("div", { ref: popoverRef, className: cn('absolute top-full right-0 mt-2 z-50', 'w-[95vw] sm:w-auto', 'bg-[rgb(var(--bg-surface))] rounded-xl shadow-xl border border-[rgb(var(--bd-default))]', 'overflow-hidden'), children: [_jsxs("div", { className: "px-3 py-2 border-b border-[rgb(var(--bd-default))] flex items-center justify-between", children: [_jsx("span", { className: "text-xs font-semibold text-[rgb(var(--fg-default))]", children: "Filters" }), _jsx("button", { onClick: () => setPopoverOpen(false), className: "w-5 h-5 rounded flex items-center justify-center hover:bg-[rgb(var(--bg-subtle))] transition-colors", children: _jsx(X, { className: "w-3 h-3 text-[rgb(var(--fg-muted))]" }) })] }), _jsxs("div", { className: "p-3 space-y-3", children: [filters.length > 0 && (_jsx("div", { className: "grid gap-3", style: { gridTemplateColumns: `repeat(${filters.length}, minmax(140px, 1fr))` }, children: filters.map((filter) => (_jsxs("div", { children: [_jsx("label", { className: "text-[10px] font-semibold text-[rgb(var(--fg-muted))] uppercase tracking-wider mb-1 block", children: filter.label }), _jsx(Dropdown, { options: filter.options, multiSelect: filter.type === 'multiselect', value: filterValues[filter.id] ?? (filter.type === 'multiselect' ? [] : ''), onValueChange: (value) => onFilterChange?.(filter.id, value), placeholder: filter.placeholder || `All ${filter.label}s`, searchable: true, className: "w-full" })] }, filter.id))) })), children, !hideDateRange && (_jsx(DatePicker, { mode: "range", value: dateRangeValue, onChange: handleDateRangeChange, inline: true }))] })] }))] })), forecast && onForecastChange && (_jsx(ForecastControl, { forecast: forecast, onForecastChange: onForecastChange, timeFilter: timeFilter, onTimeFilterChange: onTimeFilterChange })), showApplyButton && (_jsx("button", { onClick: onApply, className: cn('h-8 px-4 rounded-md flex items-center gap-1.5', 'bg-[rgb(var(--color-primary))] text-white', 'text-xs font-semibold', 'shadow-sm hover:shadow-md transition-all', 'hover:brightness-110'), children: "Apply" })), (reports.length > 0 || onShare || onExport) && (_jsx(OverflowMenu, { reports: reports, onReportSelect: onReportSelect, onShare: onShare, onExport: onExport }))] })] }) }) }));
|
|
412
412
|
}
|
|
413
413
|
// Default layout: Title centered, controls on right
|
|
414
|
-
return (_jsxs("header", { className: cn('bg-[rgb(var(--bg-surface))] border-b border-[rgb(var(--bd-default))]', 'px-4 py-3 lg:px-6', className), children: [_jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2", children: [_jsxs("div", { className: "flex-auto min-w-0 flex items-center gap-2.5", children: [_jsx("h1", { className: "text-base sm:text-xl font-bold text-[rgb(var(--fg-default))] leading-tight truncate", children: title }), contextLabel && (
|
|
414
|
+
return (_jsxs("header", { className: cn('bg-[rgb(var(--bg-surface))] border-b border-[rgb(var(--bd-default))]', 'px-4 py-3 lg:px-6', className), children: [_jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2", children: [_jsxs("div", { className: "flex-auto min-w-0 flex items-center gap-2.5", children: [_jsx("h1", { className: "text-base sm:text-xl font-bold text-[rgb(var(--fg-default))] leading-tight truncate", children: title }), contextLabel && (
|
|
415
|
+
/* Beside the title at every width: on a phone it sat on a line of its own under the title. */
|
|
416
|
+
_jsxs("span", { className: "inline-flex items-center gap-1.5 shrink-0 h-6 px-2.5 rounded-full border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-subtle))] text-xs font-medium text-[rgb(var(--fg-muted))]", children: [_jsx(CalendarDays, { className: "w-3.5 h-3.5" }), contextLabel] }))] }), _jsxs("div", { className: "ml-auto flex flex-wrap items-center justify-end gap-x-3 gap-y-2", children: [secondaryToggle && (_jsxs(_Fragment, { children: [_jsx("div", { ref: toggleRef, className: "hidden sm:block", children: _jsx(Tabs, { tabs: secondaryToggle.options.map(opt => ({ id: opt.value, label: opt.label })), activeTab: secondaryToggle.value, onTabChange: secondaryToggle.onChange, size: "sm" }) }), _jsx("div", { className: cn('hidden h-4 w-px bg-[rgb(var(--bd-default))] self-center', !tabsWrapped && 'sm:block') })] })), !hideTimeFilter && (_jsx("div", { ref: timeTabsRef, className: "hidden sm:block", children: _jsx(Tabs, { tabs: timeOptions.map(opt => ({ id: opt.value, label: opt.label, dropdownOptions: opt.dropdownOptions, quickOptions: opt.quickOptions })), activeTab: timeFilter, onTabChange: (tabId) => onTimeFilterChange?.(tabId), variant: "rounded", size: "sm", dropdownValues: {
|
|
415
417
|
Day: timeFilterSelection?.days || [],
|
|
416
418
|
Week: timeFilterSelection?.weeks || [],
|
|
417
419
|
Month: timeFilterSelection?.months || [],
|
|
@@ -430,7 +432,7 @@ export function FilterBar({ title, contextLabel, description, secondaryToggle, t
|
|
|
430
432
|
onTimeFilterSelectionChange?.(newSelection);
|
|
431
433
|
} }) })), _jsxs("div", { className: "flex items-center gap-0.5 rounded-lg border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))] p-0.5", children: [!hideFilterButton && (_jsxs("div", { className: "relative", children: [_jsxs("button", { ref: buttonRef, onClick: () => setPopoverOpen(!popoverOpen), className: cn('w-7 h-7 rounded-md flex items-center justify-center transition-colors relative', popoverOpen
|
|
432
434
|
? 'bg-[rgb(var(--color-primary))] text-white shadow-sm'
|
|
433
|
-
: 'text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))]'), title: "Filters", children: [_jsx(ListFilter, { className: "w-4 h-4" }), hasActiveFilters && !popoverOpen && (_jsx("span", { className: "absolute -top-1 -right-1 w-2 h-2 bg-[rgb(var(--color-primary))] rounded-full" }))] }), popoverOpen && (_jsxs("div", { ref: popoverRef, className: cn('absolute top-full right-0 mt-2 z-50', 'w-[95vw] sm:w-auto', 'bg-[rgb(var(--bg-surface))] rounded-xl shadow-xl border border-[rgb(var(--bd-default))]', 'overflow-hidden'), children: [_jsxs("div", { className: "px-3 py-2 border-b border-[rgb(var(--bd-default))] flex items-center justify-between", children: [_jsx("span", { className: "text-xs font-semibold text-[rgb(var(--fg-default))]", children: "Filters" }), _jsx("button", { onClick: () => setPopoverOpen(false), className: "w-5 h-5 rounded flex items-center justify-center hover:bg-[rgb(var(--bg-subtle))] transition-colors", children: _jsx(X, { className: "w-3 h-3 text-[rgb(var(--fg-muted))]" }) })] }), _jsxs("div", { className: "p-3 space-y-3", children: [filters.length > 0 && (_jsx("div", { className: "grid gap-3", style: { gridTemplateColumns: `repeat(${Math.min(filters.length, 3)}, minmax(140px, 1fr))` }, children: filters.map((filter) => (_jsxs("div", { children: [_jsx("label", { className: "text-[10px] font-semibold text-[rgb(var(--fg-muted))] uppercase tracking-wider mb-1 block", children: filter.label }), _jsx(Dropdown, { options: filter.options, multiSelect: filter.type === 'multiselect', value: filterValues[filter.id] ?? (filter.type === 'multiselect' ? [] : ''), onValueChange: (value) => onFilterChange?.(filter.id, value), placeholder: filter.placeholder || `All ${filter.label}s`, searchable: true, className: "w-full" })] }, filter.id))) })), children, !hideDateRange && (_jsx(DatePicker, { mode: "range", value: dateRangeValue, onChange: handleDateRangeChange, inline: true }))] })] }))] })), forecast && onForecastChange && (_jsx(ForecastControl, { forecast: forecast, onForecastChange: onForecastChange, timeFilter: timeFilter, onTimeFilterChange: onTimeFilterChange, bare: true })), (showInsights || reports.length > 0 || onShare || onExport) && (_jsx(OverflowMenu, { showInsights: showInsights, insightsActive: insightsActive, onInsightsClick: onInsightsClick, reports: reports, onReportSelect: onReportSelect, onShare: onShare, onExport: onExport }))] }), showApplyButton && (_jsx("button", { onClick: onApply, className: cn('h-8 px-4 rounded-md flex items-center gap-1.5', 'bg-[rgb(var(--color-primary))] text-white', 'text-xs font-semibold', 'shadow-sm hover:shadow-md transition-all', 'hover:brightness-110'), children: "Apply" }))] })] }),
|
|
435
|
+
: 'text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))]'), title: "Filters", children: [_jsx(ListFilter, { className: "w-4 h-4" }), hasActiveFilters && !popoverOpen && (_jsx("span", { className: "absolute -top-1 -right-1 w-2 h-2 bg-[rgb(var(--color-primary))] rounded-full" }))] }), popoverOpen && (_jsxs("div", { ref: popoverRef, className: cn('absolute top-full right-0 mt-2 z-50', 'w-[95vw] sm:w-auto', 'bg-[rgb(var(--bg-surface))] rounded-xl shadow-xl border border-[rgb(var(--bd-default))]', 'overflow-hidden'), children: [_jsxs("div", { className: "px-3 py-2 border-b border-[rgb(var(--bd-default))] flex items-center justify-between", children: [_jsx("span", { className: "text-xs font-semibold text-[rgb(var(--fg-default))]", children: "Filters" }), _jsx("button", { onClick: () => setPopoverOpen(false), className: "w-5 h-5 rounded flex items-center justify-center hover:bg-[rgb(var(--bg-subtle))] transition-colors", children: _jsx(X, { className: "w-3 h-3 text-[rgb(var(--fg-muted))]" }) })] }), _jsxs("div", { className: "p-3 space-y-3", children: [filters.length > 0 && (_jsx("div", { className: "grid gap-3", style: { gridTemplateColumns: `repeat(${Math.min(filters.length, 3)}, minmax(140px, 1fr))` }, children: filters.map((filter) => (_jsxs("div", { children: [_jsx("label", { className: "text-[10px] font-semibold text-[rgb(var(--fg-muted))] uppercase tracking-wider mb-1 block", children: filter.label }), _jsx(Dropdown, { options: filter.options, multiSelect: filter.type === 'multiselect', value: filterValues[filter.id] ?? (filter.type === 'multiselect' ? [] : ''), onValueChange: (value) => onFilterChange?.(filter.id, value), placeholder: filter.placeholder || `All ${filter.label}s`, searchable: true, className: "w-full" })] }, filter.id))) })), children, !hideDateRange && (_jsx(DatePicker, { mode: "range", value: dateRangeValue, onChange: handleDateRangeChange, inline: true }))] })] }))] })), forecast && onForecastChange && (_jsx(ForecastControl, { forecast: forecast, onForecastChange: onForecastChange, timeFilter: timeFilter, onTimeFilterChange: onTimeFilterChange, bare: true })), (showInsights || reports.length > 0 || onShare || onExport) && (_jsx(OverflowMenu, { showInsights: showInsights, insightsActive: insightsActive, onInsightsClick: onInsightsClick, reports: reports, onReportSelect: onReportSelect, onShare: onShare, onExport: onExport }))] }), showApplyButton && (_jsx("button", { onClick: onApply, className: cn('h-8 px-4 rounded-md flex items-center gap-1.5', 'bg-[rgb(var(--color-primary))] text-white', 'text-xs font-semibold', 'shadow-sm hover:shadow-md transition-all', 'hover:brightness-110'), children: "Apply" }))] })] }), (!hideTimeFilter || secondaryToggle) && (_jsxs("div", { className: "sm:hidden mt-2 -mx-1 flex items-center gap-2 overflow-x-auto px-1 pb-0.5 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden [&>*]:shrink-0", children: [secondaryToggle && (_jsx(Tabs, { tabs: secondaryToggle.options.map(opt => ({ id: opt.value, label: opt.label })), activeTab: secondaryToggle.value, onTabChange: secondaryToggle.onChange, size: "sm" })), !hideTimeFilter && (_jsx(Tabs, { tabs: timeOptions.map(opt => ({ id: opt.value, label: opt.label, dropdownOptions: opt.dropdownOptions, quickOptions: opt.quickOptions })), activeTab: timeFilter, onTabChange: (tabId) => onTimeFilterChange?.(tabId), variant: "rounded", size: "sm", dropdownValues: {
|
|
434
436
|
Day: timeFilterSelection?.days || [],
|
|
435
437
|
Week: timeFilterSelection?.weeks || [],
|
|
436
438
|
Month: timeFilterSelection?.months || [],
|
|
@@ -1316,7 +1316,7 @@ enableFilterRow = false, initialColumnFilters, }) {
|
|
|
1316
1316
|
}
|
|
1317
1317
|
}, className: `px-2 sm:px-4 py-1 sm:py-1.5 text-[10px] sm:text-xs font-medium rounded-full transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-primary/50 whitespace-nowrap ${viewMode === 'selected'
|
|
1318
1318
|
? 'bg-primary text-white shadow-sm'
|
|
1319
|
-
: 'text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-hover))] hover:text-[rgb(var(--fg-default))]'}`, "aria-label": `View selected items (${safeSelectedCount} selected)`, children: [_jsx("span", { className: "hidden sm:inline", children: "Selected " }), "(", safeSelectedCount, ")"] })] }, "view-toggle")), preDateActions, enableSearch && (_jsxs("div", { className: "flex items-center gap-2 flex-1 min-w-0", children: [_jsx("div", { className: "min-w-0 flex-1", children: effectiveSearchType === 'advanced' ? (_jsxs(_Fragment, { children: [_jsx(TooltipProvider, { delayDuration: 100, children: _jsxs("div", { className: "flex items-center h-8 rounded-full border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))] px-3 focus-within:border-[rgb(var(--color-
|
|
1319
|
+
: 'text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-hover))] hover:text-[rgb(var(--fg-default))]'}`, "aria-label": `View selected items (${safeSelectedCount} selected)`, children: [_jsx("span", { className: "hidden sm:inline", children: "Selected " }), "(", safeSelectedCount, ")"] })] }, "view-toggle")), preDateActions, enableSearch && (_jsxs("div", { className: "flex items-center gap-2 flex-1 min-w-0", children: [_jsx("div", { className: "min-w-0 flex-1", children: effectiveSearchType === 'advanced' ? (_jsxs(_Fragment, { children: [_jsx(TooltipProvider, { delayDuration: 100, children: _jsxs("div", { className: "flex items-center h-8 rounded-full border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))] px-3 focus-within:border-[rgb(var(--color-focus))] focus-within:ring-1 focus-within:ring-[rgb(var(--color-focus)/0.2)] transition-all", children: [_jsxs("div", { className: "flex items-center gap-1.5 flex-1 min-w-0", children: [speechSupported && (_jsx("button", { type: "button", onClick: handleVoiceSearch, className: `flex-shrink-0 transition-colors ${isListening ? 'text-[rgb(var(--color-error))] animate-pulse' : 'text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))]'}`, title: isListening ? 'Stop listening' : 'Voice search', children: isListening ? _jsx(MicOff, { className: "h-3.5 w-3.5" }) : _jsx(Mic, { className: "h-3.5 w-3.5" }) })), _jsx("input", { ref: searchInputRef, placeholder: speechSupported ? 'Type or speak to search...' : 'Search...', value: searchValue, onChange: (e) => handleGlobalSearchChange(e.target.value), className: "flex-1 min-w-0 w-full bg-transparent border-none outline-none text-xs text-[rgb(var(--fg-default))] placeholder:text-[rgb(var(--fg-muted))]" })] }), _jsxs("div", { className: "flex items-center gap-2 flex-shrink-0 ml-2", children: [_jsx("div", { className: "w-px h-4 bg-[rgb(var(--bd-default))]" }), enableDateFilter && (_jsx(DatePicker, { mode: "range", value: { from: dateFrom || undefined, to: dateTo || undefined }, onChange: (range) => {
|
|
1320
1320
|
if (range && typeof range === 'object' && 'from' in range) {
|
|
1321
1321
|
onDateFromChange?.(range.from || null);
|
|
1322
1322
|
onDateToChange?.(range.to || null);
|
|
@@ -1342,7 +1342,7 @@ enableFilterRow = false, initialColumnFilters, }) {
|
|
|
1342
1342
|
}, "aria-label": "Auto-size all columns to fit content", children: "Auto-size" })] })] }) }), enableColumnFreezing && frozenColumns.length > 0 && (_jsx("div", { className: "px-2 py-1", children: _jsx("div", { className: "bg-[rgb(var(--color-primary-subtle))] rounded-md p-1 space-y-0.5", children: frozenColumns.map((column) => (_jsxs("div", { className: "flex items-center justify-between px-2 py-1.5 hover:bg-[rgb(var(--bg-selected))]/50 rounded group cursor-pointer", children: [_jsxs("div", { className: "flex items-center space-x-2 flex-1", children: [_jsx("input", { type: "checkbox", checked: column.getIsVisible(), onChange: (e) => {
|
|
1343
1343
|
e.stopPropagation();
|
|
1344
1344
|
column.toggleVisibility(e.target.checked);
|
|
1345
|
-
}, className: "w-3 h-3 rounded border-[rgb(var(--bd-default))] text-[rgb(var(--color-primary))] focus:ring-[rgb(var(--color-
|
|
1345
|
+
}, className: "w-3 h-3 rounded border-[rgb(var(--bd-default))] text-[rgb(var(--color-primary))] focus:ring-[rgb(var(--color-focus))] cursor-pointer" }), _jsx("span", { className: "text-sm font-medium text-[rgb(var(--fg-default))] capitalize truncate", children: column.id })] }), _jsx(Button, { variant: "ghost", size: "sm", className: "h-7 w-7 p-0 text-[rgb(var(--color-primary))] hover:text-[rgb(var(--color-primary-hover))] hover:bg-[rgb(var(--bg-selected))] opacity-70 group-hover:opacity-100 transition-opacity cursor-pointer", onClick: (e) => {
|
|
1346
1346
|
e.stopPropagation();
|
|
1347
1347
|
const newFrozenColumns = new Set(frozenColumnsState);
|
|
1348
1348
|
newFrozenColumns.delete(column.id);
|
|
@@ -1352,7 +1352,7 @@ enableFilterRow = false, initialColumnFilters, }) {
|
|
|
1352
1352
|
return (_jsxs("div", { className: "flex items-center justify-between px-2 py-1.5 hover:bg-[rgb(var(--bg-subtle))] rounded group cursor-pointer", children: [_jsxs("div", { className: "flex items-center space-x-2 flex-1", children: [_jsx("input", { type: "checkbox", checked: column.getIsVisible(), onChange: (e) => {
|
|
1353
1353
|
e.stopPropagation();
|
|
1354
1354
|
column.toggleVisibility(e.target.checked);
|
|
1355
|
-
}, className: "w-3 h-3 rounded border-[rgb(var(--bd-default))] text-[rgb(var(--color-primary))] focus:ring-[rgb(var(--color-
|
|
1355
|
+
}, className: "w-3 h-3 rounded border-[rgb(var(--bd-default))] text-[rgb(var(--color-primary))] focus:ring-[rgb(var(--color-focus))] cursor-pointer" }), _jsx("span", { className: "text-sm text-[rgb(var(--fg-default))] capitalize truncate", children: column.id })] }), enableColumnFreezing && !isSelectColumn && (_jsx(Button, { variant: "ghost", size: "sm", className: "h-7 w-7 p-0 text-[rgb(var(--color-icon))] hover:text-[rgb(var(--color-icon-hover))] hover:bg-[rgb(var(--bg-hover))] opacity-0 group-hover:opacity-100 transition-opacity cursor-pointer", onClick: (e) => {
|
|
1356
1356
|
e.stopPropagation();
|
|
1357
1357
|
const newFrozenColumns = new Set(frozenColumnsState);
|
|
1358
1358
|
newFrozenColumns.add(column.id);
|
|
@@ -133,7 +133,7 @@ function FilterCell({ header, isFrozen, isPinnedRight, leftPosition, rightPositi
|
|
|
133
133
|
})
|
|
134
134
|
}, className: cn('px-1 text-left align-middle', 'bg-[color-mix(in_srgb,rgb(var(--color-primary))_5%,white)]', 'dark:bg-[color-mix(in_srgb,rgb(var(--color-primary))_5%,rgb(var(--bg-surface)))]'), children: skipFilter ? (
|
|
135
135
|
// Empty cell for select/action columns
|
|
136
|
-
_jsx("div", { className: "h-full" })) : (_jsxs("div", { className: "relative flex items-center h-full", children: [_jsx("div", { className: "absolute left-1.5 top-1/2 -translate-y-1/2 pointer-events-none opacity-50", children: isDate ? (_jsx(Calendar, { className: "h-3 w-3 text-[rgb(var(--color-icon))]" })) : (_jsx(Search, { className: "h-3 w-3 text-[rgb(var(--color-icon))]" })) }), _jsx("input", { ref: inputRef, type: isNumber ? 'number' : 'text', value: localValue, onChange: handleChange, placeholder: "", className: cn('w-full h-6 pl-6 pr-5 text-xs', 'bg-[rgb(var(--bg-surface))] rounded', 'focus:outline-none focus:ring-1 focus:ring-[rgb(var(--color-
|
|
136
|
+
_jsx("div", { className: "h-full" })) : (_jsxs("div", { className: "relative flex items-center h-full", children: [_jsx("div", { className: "absolute left-1.5 top-1/2 -translate-y-1/2 pointer-events-none opacity-50", children: isDate ? (_jsx(Calendar, { className: "h-3 w-3 text-[rgb(var(--color-icon))]" })) : (_jsx(Search, { className: "h-3 w-3 text-[rgb(var(--color-icon))]" })) }), _jsx("input", { ref: inputRef, type: isNumber ? 'number' : 'text', value: localValue, onChange: handleChange, placeholder: "", className: cn('w-full h-6 pl-6 pr-5 text-xs', 'bg-[rgb(var(--bg-surface))] rounded', 'focus:outline-none focus:ring-1 focus:ring-[rgb(var(--color-focus))] focus:border-[rgb(var(--color-focus))]', 'placeholder:text-[rgb(var(--fg-muted))]', 'text-[rgb(var(--fg-default))]',
|
|
137
137
|
// Highlight active filter
|
|
138
138
|
localValue
|
|
139
139
|
? 'border-2 border-[rgb(var(--color-primary))] bg-[color-mix(in_srgb,rgb(var(--color-primary))_5%,rgb(var(--bg-surface)))]'
|
|
@@ -156,7 +156,7 @@ export function DraftModal({ open, onClose, drafts, onLoad, onDelete, isLoading
|
|
|
156
156
|
// Early return after all hooks to comply with Rules of Hooks
|
|
157
157
|
if (!open)
|
|
158
158
|
return null;
|
|
159
|
-
return (_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm", children: _jsxs("div", { className: "bg-[rgb(var(--bg-surface))] rounded-lg shadow-2xl w-full max-w-4xl max-h-[85vh] flex flex-col", children: [_jsxs("div", { className: "px-6 py-3 border-b border-[rgb(var(--bd-default))] flex items-center gap-4", children: [_jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [_jsx(FileText, { className: "w-5 h-5 text-[rgb(var(--color-primary))]" }), _jsx("h2", { className: "text-base font-semibold text-[rgb(var(--fg-default))]", children: "Saved Drafts" }), _jsxs("span", { className: "text-xs text-[rgb(var(--fg-muted))]", children: ["(", drafts.length, ")"] })] }), _jsxs("div", { className: "relative flex-1", children: [_jsx(Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-[rgb(var(--fg-muted))]" }), _jsx("input", { type: "text", placeholder: "Search...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), className: "\n w-full pl-9 pr-3 py-1.5 rounded-lg text-sm\n bg-[rgb(var(--bg-default))]\n border border-[rgb(var(--bd-default))]\n text-[rgb(var(--fg-default))]\n placeholder:text-[rgb(var(--fg-muted))]\n focus:outline-none focus:ring-2 focus:ring-[rgb(var(--color-
|
|
159
|
+
return (_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm", children: _jsxs("div", { className: "bg-[rgb(var(--bg-surface))] rounded-lg shadow-2xl w-full max-w-4xl max-h-[85vh] flex flex-col", children: [_jsxs("div", { className: "px-6 py-3 border-b border-[rgb(var(--bd-default))] flex items-center gap-4", children: [_jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [_jsx(FileText, { className: "w-5 h-5 text-[rgb(var(--color-primary))]" }), _jsx("h2", { className: "text-base font-semibold text-[rgb(var(--fg-default))]", children: "Saved Drafts" }), _jsxs("span", { className: "text-xs text-[rgb(var(--fg-muted))]", children: ["(", drafts.length, ")"] })] }), _jsxs("div", { className: "relative flex-1", children: [_jsx(Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-[rgb(var(--fg-muted))]" }), _jsx("input", { type: "text", placeholder: "Search...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), className: "\n w-full pl-9 pr-3 py-1.5 rounded-lg text-sm\n bg-[rgb(var(--bg-default))]\n border border-[rgb(var(--bd-default))]\n text-[rgb(var(--fg-default))]\n placeholder:text-[rgb(var(--fg-muted))]\n focus:outline-none focus:ring-2 focus:ring-[rgb(var(--color-focus))]\n " })] }), _jsx("div", { className: "flex-shrink-0 w-36", children: _jsx(Dropdown, { options: SORT_OPTIONS, value: sortBy, onValueChange: (val) => setSortBy(val), size: "sm", autoWidth: true }) }), _jsx("button", { onClick: onClose, className: "p-1.5 rounded-lg hover:bg-[rgb(var(--bg-muted))] text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] transition-colors flex-shrink-0", children: _jsx(X, { className: "w-5 h-5" }) })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-6 py-4", children: isLoading ? (_jsx("div", { className: "flex items-center justify-center py-16", children: _jsxs("div", { className: "text-center", children: [_jsx("div", { className: "w-12 h-12 rounded-full border-4 border-[rgb(var(--color-primary)_/_0.2)] border-t-[rgb(var(--color-primary))] animate-spin mx-auto mb-3" }), _jsx("p", { className: "text-[rgb(var(--fg-muted))]", children: "Loading drafts..." })] }) })) : filteredAndSortedDrafts.length === 0 ? (_jsxs("div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [_jsx(FileText, { className: "w-16 h-16 text-[rgb(var(--fg-muted))] mb-4 opacity-50" }), _jsx("p", { className: "text-lg font-medium text-[rgb(var(--fg-default))] mb-1", children: searchQuery ? 'No matching drafts' : 'No drafts saved yet' }), _jsx("p", { className: "text-sm text-[rgb(var(--fg-muted))]", children: searchQuery ? 'Try a different search term' : 'Start by clicking "Save Draft" button' })] })) : (_jsx("div", { className: "space-y-3", children: paginatedDrafts.map((draft) => {
|
|
160
160
|
const progress = calculateProgress(draft);
|
|
161
161
|
const preview = draft.previewData || {};
|
|
162
162
|
return (_jsx("div", { className: "\n group relative p-3 rounded-lg\n bg-[rgb(var(--bg-default))]\n border border-[rgb(var(--bd-default))]\n hover:border-[rgb(var(--color-primary))]\n hover:shadow-lg\n transition-all duration-200\n ", children: _jsx("div", { className: "flex items-start gap-4", children: _jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("h3", { className: "font-semibold text-[rgb(var(--fg-default))] truncate text-base", children: draft.draftName || 'Untitled Draft' }), _jsxs("div", { className: "flex items-center gap-2 mt-1 text-xs text-[rgb(var(--fg-muted))]", children: [_jsx("span", { children: formatRelativeTime(draft.lastSaved) }), _jsxs("span", { className: "hidden group-hover:inline", children: ["\u2022 ", formatFullDate(draft.lastSaved)] }), draft.isAutoSave && (_jsx("span", { className: "text-[10px] px-2 py-0.5 rounded-full bg-[rgb(var(--color-primary)_/_0.1)] text-[rgb(var(--color-primary))] font-medium", children: "AUTO-SAVE" }))] })] }), _jsxs("div", { className: "flex items-center gap-2 opacity-0 group-hover:opacity-100 transition-opacity", children: [_jsxs("button", { onClick: () => handleLoad(draft.draftId), className: "\n px-4 py-2 rounded-lg text-sm font-medium\n bg-[rgb(var(--color-primary))]\n text-white\n hover:opacity-90\n transition-opacity\n flex items-center gap-2\n ", children: [_jsx(Download, { className: "w-4 h-4" }), "Load"] }), _jsx("button", { onClick: () => handleDelete(draft.draftId), disabled: deletingId === draft.draftId, className: "\n p-2 rounded-lg\n text-[rgb(var(--fg-muted))]\n hover:text-red-600\n hover:bg-red-50\n transition-colors\n disabled:opacity-50\n ", title: "Delete draft", children: deletingId === draft.draftId ? (_jsx("div", { className: "w-4 h-4 rounded-full border-2 border-red-200 border-t-red-600 animate-spin" })) : (_jsx(Trash2, { className: "w-4 h-4" })) })] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-x-6 gap-y-1 mt-2 text-sm", children: [preview.jobName && (_jsx("div", { className: "text-[rgb(var(--fg-muted))] truncate", children: preview.jobName }, "job")), preview.clientName && (_jsx("div", { className: "text-[rgb(var(--fg-muted))] truncate", children: preview.clientName }, "client")), preview.category && (_jsx("div", { className: "text-[rgb(var(--fg-muted))] truncate", children: preview.category }, "category")), preview.totalCost !== undefined && preview.totalCost > 0 && (_jsxs("div", { className: "font-medium text-[rgb(var(--color-primary))]", children: [currencySymbol, preview.totalCost.toLocaleString('en-IN')] }, "cost"))] }), progress > 0 && (_jsxs("div", { className: "mt-2", children: [_jsxs("div", { className: "flex items-center justify-between text-xs text-[rgb(var(--fg-muted))] mb-1", children: [_jsx("span", { children: "Progress" }), _jsxs("span", { className: "font-medium", children: [progress, "%"] })] }), _jsx("div", { className: "h-1.5 bg-[rgb(var(--bg-muted))] rounded-full overflow-hidden", children: _jsx("div", { className: "h-full bg-[rgb(var(--color-primary))] transition-all duration-500 rounded-full", style: { width: `${progress}%` } }) })] }))] }) }) }, draft.draftId));
|
|
@@ -129,7 +129,7 @@ export function DateTimePicker({ value, onChange, placeholder = 'Select date & t
|
|
|
129
129
|
e.preventDefault();
|
|
130
130
|
onChange(value === 0 ? max : value - 1);
|
|
131
131
|
}
|
|
132
|
-
}, className: "w-14 text-center text-lg font-semibold border border-[rgb(var(--bd-default))] rounded-lg px-2 py-1 focus:outline-none focus:ring-2 focus:ring-[rgb(var(--color-
|
|
132
|
+
}, className: "w-14 text-center text-lg font-semibold border border-[rgb(var(--bd-default))] rounded-lg px-2 py-1 focus:outline-none focus:ring-2 focus:ring-[rgb(var(--color-focus))] focus:border-transparent transition-all hover:border-[rgb(var(--color-primary))]", "aria-label": label }), _jsx("span", { className: "text-[10px] text-[rgb(var(--fg-muted))] mt-0.5", children: label })] }), _jsx("button", { onClick: () => onChange(value === 0 ? max : value - 1), className: "h-6 w-full flex items-center justify-center text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--color-primary))] hover:bg-[rgb(var(--bg-hover))] rounded transition-colors active:scale-95", "aria-label": `Decrease ${label}`, children: _jsx(ChevronLeft, { className: "h-4 w-4 -rotate-90" }) })] }));
|
|
133
133
|
return (_jsxs("div", { className: cn('relative w-full', className), children: [label && (_jsx("label", { className: "block text-sm font-medium text-[rgb(var(--fg-default))] mb-2", children: label })), _jsxs(Popover.Root, { open: isOpen, onOpenChange: setIsOpen, children: [_jsx(Popover.Trigger, { asChild: true, children: _jsx("div", { className: "relative", children: _jsx(Input, { value: inputValue, onChange: (e) => setInputValue(e.target.value), placeholder: placeholder, disabled: disabled, error: error, className: cn('pl-2 pr-9 text-xs w-full', error && 'border-red-300'), onFocus: () => !disabled && setIsOpen(true), rightIcon: Calendar, onRightIconClick: () => !disabled && setIsOpen(!isOpen), readOnly: true }) }) }), _jsx(Popover.Portal, { container: typeof document !== 'undefined' ? document.body : undefined, children: _jsxs(Popover.Content, { className: cn('z-[300] bg-white rounded-xl shadow-2xl border border-gray-200/50 backdrop-blur-sm', 'data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95', 'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95', 'w-[95vw] sm:w-[380px] max-w-[calc(100vw-2rem)] p-3 sm:p-4'), side: "bottom", align: "start", sideOffset: 8, avoidCollisions: true, collisionPadding: 16, onOpenAutoFocus: (e) => e.preventDefault(), children: [_jsxs("div", { className: "flex items-center justify-between mb-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Calendar, { className: "h-4 w-4 text-[rgb(var(--color-primary))]" }), _jsx("span", { className: "text-sm font-semibold text-[rgb(var(--fg-default))]", children: "Select Date & Time" })] }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => setIsOpen(false), className: "h-6 w-6 p-0 hover:bg-red-50 hover:text-red-600 transition-all duration-200", children: _jsx(X, { className: "h-3 w-3" }) })] }), _jsx(CalendarView, { currentMonth: selectedDate || new Date(), selectedDate: selectedDate, onDateClick: handleDateClick, onMonthChange: handleMonthChange, minDate: minDate, maxDate: maxDate, showNavigation: true }), _jsxs("div", { className: "border-t border-[rgb(var(--bd-default))] pt-4", children: [_jsxs("div", { className: "flex items-center gap-2 mb-3", children: [_jsx(Clock, { className: "h-4 w-4 text-[rgb(var(--color-primary))]" }), _jsx("span", { className: "text-sm font-semibold text-[rgb(var(--fg-default))]", children: "Time" })] }), _jsxs("div", { className: "flex items-center justify-center gap-2", children: [renderTimeInput(hours, setHours, timeFormat === '12h' ? 12 : 23, 'Hours'), _jsx("span", { className: "text-2xl font-bold text-[rgb(var(--fg-muted))] mb-5", children: ":" }), renderTimeInput(minutes, setMinutes, 59, 'Mins'), timeFormat === '12h' && (_jsxs(_Fragment, { children: [_jsx("div", { className: "w-px h-16 bg-[rgb(var(--bd-default))] mx-2" }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("button", { onClick: () => setPeriod('AM'), className: cn('px-3 py-1.5 text-sm font-semibold rounded-lg transition-all duration-200', period === 'AM'
|
|
134
134
|
? 'bg-[rgb(var(--color-primary))] text-white shadow-md'
|
|
135
135
|
: 'bg-[rgb(var(--bg-subtle))] text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-hover))]'), children: "AM" }), _jsx("button", { onClick: () => setPeriod('PM'), className: cn('px-3 py-1.5 text-sm font-semibold rounded-lg transition-all duration-200', period === 'PM'
|
|
@@ -38,7 +38,7 @@ export declare function ClearButton({ onClear, disabled, className }: ClearButto
|
|
|
38
38
|
export declare const dropdownSharedStyles: {
|
|
39
39
|
readonly trigger: {
|
|
40
40
|
readonly base: "flex items-center justify-between rounded-md border bg-bg-surface cursor-pointer transition-all duration-200";
|
|
41
|
-
readonly focus: "focus-within:outline-none focus-within:border-[rgb(var(--color-
|
|
41
|
+
readonly focus: "focus-within:outline-none focus-within:border-[rgb(var(--color-focus))]";
|
|
42
42
|
readonly error: "border-[rgb(var(--color-error))] focus-within:border-[rgb(var(--color-error))]";
|
|
43
43
|
readonly normal: "border-[rgb(var(--bd-default))] hover:border-[rgb(var(--bd-hover))]";
|
|
44
44
|
readonly disabled: "cursor-not-allowed opacity-50";
|
|
@@ -110,7 +110,7 @@ export const dropdownSharedStyles = {
|
|
|
110
110
|
// Trigger (button) styles
|
|
111
111
|
trigger: {
|
|
112
112
|
base: "flex items-center justify-between rounded-md border bg-bg-surface cursor-pointer transition-all duration-200",
|
|
113
|
-
focus: "focus-within:outline-none focus-within:border-[rgb(var(--color-
|
|
113
|
+
focus: "focus-within:outline-none focus-within:border-[rgb(var(--color-focus))]",
|
|
114
114
|
error: "border-[rgb(var(--color-error))] focus-within:border-[rgb(var(--color-error))]",
|
|
115
115
|
normal: "border-[rgb(var(--bd-default))] hover:border-[rgb(var(--bd-hover))]",
|
|
116
116
|
disabled: "cursor-not-allowed opacity-50",
|
|
@@ -872,7 +872,7 @@ acceptedFileTypes = [], label = "File Attachment", className, disabled = false,
|
|
|
872
872
|
setSelectedEmail(null);
|
|
873
873
|
setEmailSearchQuery('');
|
|
874
874
|
}
|
|
875
|
-
}, children: _jsxs(ModalContent, { size: "lg", hideCloseButton: true, disableOutsideClick: true, className: "p-0 flex flex-col overflow-hidden max-w-2xl w-[90vw] h-[75vh] max-h-[650px]", children: [_jsx(ModalHeader, { className: "px-5 py-3 border-b border-[rgb(var(--bd-default))] flex-shrink-0 bg-[rgb(var(--bg-surface))]", children: _jsxs("div", { className: "flex items-center justify-between w-full gap-3", children: [_jsxs("div", { className: "flex items-center gap-3 flex-shrink-0", children: [_jsx("div", { className: "w-9 h-9 rounded-lg bg-[rgba(var(--color-primary),0.1)] flex items-center justify-center", children: _jsx(Mail, { className: "h-4.5 w-4.5 text-[rgb(var(--color-primary))]" }) }), _jsxs("div", { children: [_jsx(ModalTitle, { className: "text-sm", children: "Import from Email" }), emailState.emails.length > 0 && (_jsxs("p", { className: "text-xs text-[rgb(var(--fg-muted))] mt-0.5", children: [emailState.emails.length, " emails"] }))] })] }), _jsxs("div", { className: "flex-1 min-w-0 relative", children: [_jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-[rgb(var(--fg-muted))]" }), _jsx("input", { type: "text", placeholder: "Search by subject, sender, or content...", value: emailSearchQuery, onChange: (e) => setEmailSearchQuery(e.target.value), className: "w-full pl-9 pr-8 py-1.5 rounded-md border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-default))] text-xs text-[rgb(var(--fg-default))] placeholder:text-[rgb(var(--fg-muted))] focus:outline-none focus:ring-2 focus:ring-[rgb(var(--color-
|
|
875
|
+
}, children: _jsxs(ModalContent, { size: "lg", hideCloseButton: true, disableOutsideClick: true, className: "p-0 flex flex-col overflow-hidden max-w-2xl w-[90vw] h-[75vh] max-h-[650px]", children: [_jsx(ModalHeader, { className: "px-5 py-3 border-b border-[rgb(var(--bd-default))] flex-shrink-0 bg-[rgb(var(--bg-surface))]", children: _jsxs("div", { className: "flex items-center justify-between w-full gap-3", children: [_jsxs("div", { className: "flex items-center gap-3 flex-shrink-0", children: [_jsx("div", { className: "w-9 h-9 rounded-lg bg-[rgba(var(--color-primary),0.1)] flex items-center justify-center", children: _jsx(Mail, { className: "h-4.5 w-4.5 text-[rgb(var(--color-primary))]" }) }), _jsxs("div", { children: [_jsx(ModalTitle, { className: "text-sm", children: "Import from Email" }), emailState.emails.length > 0 && (_jsxs("p", { className: "text-xs text-[rgb(var(--fg-muted))] mt-0.5", children: [emailState.emails.length, " emails"] }))] })] }), _jsxs("div", { className: "flex-1 min-w-0 relative", children: [_jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-[rgb(var(--fg-muted))]" }), _jsx("input", { type: "text", placeholder: "Search by subject, sender, or content...", value: emailSearchQuery, onChange: (e) => setEmailSearchQuery(e.target.value), className: "w-full pl-9 pr-8 py-1.5 rounded-md border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-default))] text-xs text-[rgb(var(--fg-default))] placeholder:text-[rgb(var(--fg-muted))] focus:outline-none focus:ring-2 focus:ring-[rgb(var(--color-focus))] focus:border-transparent" }), emailSearchQuery && (_jsx("button", { onClick: () => setEmailSearchQuery(''), className: "absolute right-2.5 top-1/2 -translate-y-1/2 p-0.5 rounded hover:bg-[rgb(var(--bg-hover))]", children: _jsx(X, { className: "h-3.5 w-3.5 text-[rgb(var(--fg-muted))]" }) }))] }), _jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [_jsx("button", { onClick: () => emailActions?.fetchEmails?.(), disabled: emailState.loading, className: "p-1.5 rounded-md hover:bg-[rgb(var(--bg-hover))] text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] transition-colors disabled:opacity-50", "aria-label": "Refresh emails", children: _jsx(RefreshCw, { className: cn("h-4 w-4", emailState.loading && "animate-spin") }) }), _jsx("button", { onClick: () => {
|
|
876
876
|
setShowEmailImportModal(false);
|
|
877
877
|
setSelectedEmail(null);
|
|
878
878
|
setEmailSearchQuery('');
|
|
@@ -138,11 +138,11 @@ export function RemarkTrail({ remarks, onAdd, canAdd = true, loading = false, on
|
|
|
138
138
|
e.preventDefault();
|
|
139
139
|
commitEdit();
|
|
140
140
|
} if (e.key === 'Escape')
|
|
141
|
-
setEditingSeq(null); }, autoFocus: true, className: "flex-1 text-xs rounded border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))] px-2 py-1 text-[rgb(var(--fg-default))] focus:outline-none focus:ring-1 focus:ring-[rgb(var(--color-
|
|
141
|
+
setEditingSeq(null); }, autoFocus: true, className: "flex-1 text-xs rounded border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))] px-2 py-1 text-[rgb(var(--fg-default))] focus:outline-none focus:ring-1 focus:ring-[rgb(var(--color-focus))]" }), _jsx("button", { type: "button", onClick: commitEdit, title: t('Save'), className: "p-1 rounded bg-[rgb(var(--color-primary))] text-white hover:opacity-90", children: _jsx(Check, { className: "h-3 w-3" }) }), _jsx("button", { type: "button", onClick: () => setEditingSeq(null), title: t('Cancel'), className: "p-1 rounded text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-hover))]", children: _jsx(X, { className: "h-3 w-3" }) })] })) : (r.text && _jsx("p", { className: "mt-0.5 text-[rgb(var(--fg-default))] whitespace-pre-wrap break-words leading-snug", children: r.text })), !isEditing && r.files && r.files.length > 0 && (_jsx("div", { className: "mt-1 flex flex-wrap gap-1.5", children: r.files.map((f, i) => (_jsxs("a", { href: f.url, target: "_blank", rel: "noopener noreferrer", title: f.name, className: "inline-flex items-center gap-1 max-w-[12rem] rounded-md border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-subtle))] px-1.5 py-0.5 text-[10px] text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--color-primary))] hover:border-[rgb(var(--color-primary))]/40 transition-colors", children: [_jsx(FileText, { className: "h-3 w-3 shrink-0" }), _jsx("span", { className: "truncate", children: f.name })] }, i))) }))] }, r.seq));
|
|
142
142
|
}) })) }), onAdd && (_jsxs("div", { className: "border-t border-[rgb(var(--bd-subtle))] px-2 py-1.5 space-y-1.5", children: [pendingFiles.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-1.5", children: pendingFiles.map((f, i) => (_jsxs("span", { className: "inline-flex items-center gap-1 max-w-[12rem] rounded-md border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-subtle))] pl-1.5 pr-1 py-0.5 text-[10px] text-[rgb(var(--fg-muted))]", children: [_jsx(FileText, { className: "h-3 w-3 shrink-0" }), _jsx("span", { className: "truncate", children: f.name }), _jsx("button", { type: "button", onClick: () => setPendingFiles(prev => prev.filter((_, idx) => idx !== i)), title: t('Remove'), className: "p-0.5 rounded-full hover:text-[rgb(var(--color-error))]", children: _jsx(X, { className: "h-2.5 w-2.5" }) })] }, i))) })), _jsxs("div", { className: "flex items-center gap-1.5", children: [onUploadFiles && (_jsxs(_Fragment, { children: [_jsx("input", { ref: fileInputRef, type: "file", multiple: true, className: "hidden", onChange: handlePickFiles }), _jsx("button", { type: "button", onClick: () => fileInputRef.current?.click(), disabled: !canAdd || saving || uploading, title: t('Attach files'), className: "p-1.5 rounded border border-[rgb(var(--bd-default))] text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--color-primary))] hover:border-[rgb(var(--color-primary))]/50 disabled:opacity-50 transition-colors shrink-0", children: uploading ? _jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin" }) : _jsx(Paperclip, { className: "h-3.5 w-3.5" }) })] })), _jsx("input", { value: text, onChange: (e) => setText(e.target.value), onKeyDown: (e) => { if (e.key === 'Enter' && !e.shiftKey) {
|
|
143
143
|
e.preventDefault();
|
|
144
144
|
handleAdd();
|
|
145
|
-
} }, disabled: !canAdd || saving, placeholder: t('Add a note...'), className: "flex-1 text-xs rounded border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))] px-2 py-1 text-[rgb(var(--fg-default))] focus:outline-none focus:ring-1 focus:ring-[rgb(var(--color-
|
|
145
|
+
} }, disabled: !canAdd || saving, placeholder: t('Add a note...'), className: "flex-1 text-xs rounded border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))] px-2 py-1 text-[rgb(var(--fg-default))] focus:outline-none focus:ring-1 focus:ring-[rgb(var(--color-focus))] disabled:opacity-60" }), _jsx("button", { onClick: handleAdd, disabled: !canAdd || saving || uploading || (!text.trim() && pendingFiles.length === 0), title: t('Add'), className: "p-1.5 rounded bg-[rgb(var(--color-primary))] text-white disabled:opacity-50 hover:opacity-90 transition-opacity shrink-0", children: _jsx(Send, { className: "h-3.5 w-3.5" }) })] })] }))] }));
|
|
146
146
|
}
|
|
147
147
|
export function RemarkInput({ value, onChange, module, documentId, documentName, documentNo, actionUrl, stage = 'General', session, label, placeholder, rows = 1, showTrail = false, onUploadFiles, disabled = false, className, inputClassName, error = false, required = false, }) {
|
|
148
148
|
const { t } = useLanguage();
|
|
@@ -254,5 +254,5 @@ export function RemarkInput({ value, onChange, module, documentId, documentName,
|
|
|
254
254
|
userResized.current = true;
|
|
255
255
|
}, placeholder: placeholder ?? t('Add remarks or notes...'), rows: rows, disabled: disabled, className: cn('w-full text-sm rounded-md border bg-[rgb(var(--bg-surface))] px-3 py-2 pr-9 text-[rgb(var(--fg-default))]', error
|
|
256
256
|
? 'border-[rgb(var(--color-error))] placeholder:text-[rgb(var(--fg-subtle))]'
|
|
257
|
-
: 'border-[rgb(var(--bd-default))] placeholder:text-[rgb(var(--fg-subtle))]', 'transition-[height,box-shadow,border-color] duration-150 ease-out', 'focus:outline-none focus:border-[rgb(var(--color-
|
|
257
|
+
: 'border-[rgb(var(--bd-default))] placeholder:text-[rgb(var(--fg-subtle))]', 'transition-[height,box-shadow,border-color] duration-150 ease-out', 'focus:outline-none focus:border-[rgb(var(--color-focus))] focus:ring-2 focus:ring-[rgb(var(--color-focus))]/30', 'resize-y overflow-auto min-h-[2.25rem] disabled:opacity-60', inputClassName) }), hasDoc && showTrail && !label && (_jsxs("button", { type: "button", onClick: openTrail, title: t('View remark trail'), className: "absolute top-1.5 right-1.5 inline-flex h-5 w-5 items-center justify-center rounded-full border border-[rgb(var(--bd-default))] text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--color-primary))] hover:border-[rgb(var(--color-primary))]/50 hover:bg-[rgb(var(--color-primary-subtle))] transition-colors", children: [_jsx(Info, { className: "h-3 w-3" }), count > 0 && _jsx("span", { className: "absolute -top-1 -right-1 h-2 w-2 rounded-full bg-[rgb(var(--color-primary))]" })] }))] }), _jsx(Modal, { open: trailOpen, onOpenChange: setTrailOpen, children: _jsxs(ModalContent, { size: "md", hideCloseButton: true, className: "p-0 overflow-hidden max-h-[80vh]", children: [_jsx(ModalTitle, { className: "sr-only", children: t('Remarks') }), _jsx(RemarkTrail, { remarks: displayRemarks, loading: loading, onAdd: hasDoc ? handleAdd : undefined, onClose: () => setTrailOpen(false), documentNo: documentNo, currentUserId: currentUserId, onEdit: hasDoc ? handleEdit : undefined, onDelete: hasDoc ? handleDelete : undefined, onUploadFiles: onUploadFiles, className: "max-h-[80vh] border-0 rounded-none" })] }) })] }));
|
|
258
258
|
}
|
|
@@ -143,7 +143,7 @@ export function MobileMenuSheet({ open, onClose }) {
|
|
|
143
143
|
const getInitials = (name) => {
|
|
144
144
|
return name.split(' ').map(n => n[0]).join('').toUpperCase().slice(0, 2);
|
|
145
145
|
};
|
|
146
|
-
return (_jsxs(_Fragment, { children: [_jsx("div", { className: cn('fixed inset-0 z-[60] bg-black/50 transition-opacity duration-300 lg:hidden', open ? 'opacity-100' : 'opacity-0 pointer-events-none'), onClick: onClose }), _jsxs("div", { className: cn('fixed inset-x-0 bottom-0 z-[61] lg:hidden', 'bg-[rgb(var(--bg-surface))] rounded-t-2xl shadow-2xl', 'transform transition-transform duration-300 ease-out', 'max-h-[85vh] flex flex-col', open ? 'translate-y-0' : 'translate-y-full'), children: [_jsx("div", { className: "flex justify-center pt-2.5 pb-1", children: _jsx("div", { className: "w-9 h-1 rounded-full bg-[rgb(var(--bd-default))]" }) }), _jsxs("div", { className: "flex items-center gap-3 px-4 py-2.5 border-b border-[rgb(var(--bd-default))]", children: [_jsx("div", { className: "w-8 h-8 rounded-full bg-[rgb(var(--bg-subtle))] border border-[rgb(var(--bd-default))] flex items-center justify-center flex-shrink-0", children: _jsx("span", { className: "text-xs font-semibold text-[rgb(var(--fg-muted))]", children: getInitials(userName) }) }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("p", { className: "text-sm font-semibold text-[rgb(var(--fg-default))] truncate leading-tight", children: userName }), userRole && (_jsx("p", { className: "text-[0.65rem] text-[rgb(var(--fg-muted))] truncate", children: userRole }))] }), _jsx("button", { onClick: onClose, className: "p-2 -mr-1 rounded-lg text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-hover))] transition-colors", children: _jsx(X, { className: "h-4.5 w-4.5" }) })] }), _jsx("div", { className: "px-4 py-2.5", children: _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-[rgb(var(--fg-muted))]" }), _jsx("input", { ref: searchRef, type: "text", placeholder: t('Search modules...'), value: searchQuery, onChange: e => setSearchQuery(e.target.value), className: "w-full pl-9 pr-8 py-2 text-sm rounded-lg border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-subtle))] text-[rgb(var(--fg-default))] placeholder:text-[rgb(var(--fg-muted))] focus:outline-none focus:border-[rgb(var(--color-
|
|
146
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { className: cn('fixed inset-0 z-[60] bg-black/50 transition-opacity duration-300 lg:hidden', open ? 'opacity-100' : 'opacity-0 pointer-events-none'), onClick: onClose }), _jsxs("div", { className: cn('fixed inset-x-0 bottom-0 z-[61] lg:hidden', 'bg-[rgb(var(--bg-surface))] rounded-t-2xl shadow-2xl', 'transform transition-transform duration-300 ease-out', 'max-h-[85vh] flex flex-col', open ? 'translate-y-0' : 'translate-y-full'), children: [_jsx("div", { className: "flex justify-center pt-2.5 pb-1", children: _jsx("div", { className: "w-9 h-1 rounded-full bg-[rgb(var(--bd-default))]" }) }), _jsxs("div", { className: "flex items-center gap-3 px-4 py-2.5 border-b border-[rgb(var(--bd-default))]", children: [_jsx("div", { className: "w-8 h-8 rounded-full bg-[rgb(var(--bg-subtle))] border border-[rgb(var(--bd-default))] flex items-center justify-center flex-shrink-0", children: _jsx("span", { className: "text-xs font-semibold text-[rgb(var(--fg-muted))]", children: getInitials(userName) }) }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("p", { className: "text-sm font-semibold text-[rgb(var(--fg-default))] truncate leading-tight", children: userName }), userRole && (_jsx("p", { className: "text-[0.65rem] text-[rgb(var(--fg-muted))] truncate", children: userRole }))] }), _jsx("button", { onClick: onClose, className: "p-2 -mr-1 rounded-lg text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-hover))] transition-colors", children: _jsx(X, { className: "h-4.5 w-4.5" }) })] }), _jsx("div", { className: "px-4 py-2.5", children: _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-[rgb(var(--fg-muted))]" }), _jsx("input", { ref: searchRef, type: "text", placeholder: t('Search modules...'), value: searchQuery, onChange: e => setSearchQuery(e.target.value), className: "w-full pl-9 pr-8 py-2 text-sm rounded-lg border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-subtle))] text-[rgb(var(--fg-default))] placeholder:text-[rgb(var(--fg-muted))] focus:outline-none focus:border-[rgb(var(--color-focus))] transition-colors" }), searchQuery && (_jsx("button", { onClick: () => { setSearchQuery(''); searchRef.current?.focus(); }, className: "absolute right-2.5 top-1/2 -translate-y-1/2 p-0.5 rounded text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))]", children: _jsx(X, { className: "h-3.5 w-3.5" }) }))] }) }), _jsx("div", { className: "flex-1 overflow-y-auto px-2 pb-2", children: filteredGroups.length === 0 ? (_jsxs("div", { className: "py-12 text-center", children: [_jsx(Search, { className: "h-8 w-8 mx-auto mb-2 text-[rgb(var(--fg-muted))] opacity-30" }), _jsx("p", { className: "text-sm text-[rgb(var(--fg-muted))]", children: t('No modules found') })] })) : (filteredGroups.map(group => {
|
|
147
147
|
const GroupIcon = getGroupIcon(group.groupName);
|
|
148
148
|
const isExpanded = expandedGroups.includes(group.groupName);
|
|
149
149
|
return (_jsxs("div", { className: "mb-0.5", children: [_jsxs("button", { onClick: () => toggleGroup(group.groupName), className: "w-full flex items-center gap-2.5 px-3 py-2.5 rounded-lg text-left hover:bg-[rgb(var(--bg-hover))] transition-colors min-h-[2.75rem]", children: [_jsx(GroupIcon, { className: "h-4 w-4 text-[rgb(var(--fg-muted))] flex-shrink-0" }), _jsx("span", { className: "text-xs font-semibold text-[rgb(var(--fg-muted))] uppercase tracking-wide flex-1", children: t(group.groupName) }), _jsx(ChevronRight, { className: cn('h-3.5 w-3.5 text-[rgb(var(--fg-muted))]/50 transition-transform duration-200', isExpanded && 'rotate-90') })] }), isExpanded && (_jsx("div", { className: "ml-5 pl-3 border-l-2 border-[rgb(var(--bd-default))]/50 mb-1", children: group.modules.map(mod => {
|
|
@@ -185,7 +185,7 @@ export function TopHeader({ className, sidebarCollapsed = true, onToggleSidebar,
|
|
|
185
185
|
})(), showNotificationDropdown && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40", onClick: () => {
|
|
186
186
|
setShowNotificationDropdown(false);
|
|
187
187
|
setNotificationSearchQuery('');
|
|
188
|
-
} }), _jsxs("div", { className: cn("z-50 bg-[rgb(var(--bg-surface))] rounded-2xl shadow-2xl border border-[rgb(var(--bd-default))] overflow-hidden", "fixed top-14 left-2 right-2 sm:absolute sm:top-auto sm:left-auto sm:right-0 sm:mt-2 sm:w-[28rem]"), children: [_jsxs("div", { className: "px-5 pt-5 pb-0 bg-[rgb(var(--bg-surface))]", children: [_jsxs("div", { className: "flex items-center gap-3 mb-4", children: [_jsx("h3", { className: "text-lg font-bold text-[rgb(var(--fg-default))] flex-shrink-0", children: "Notifications" }), _jsxs("div", { className: "relative flex-1", children: [_jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-[rgb(var(--fg-muted))]" }), _jsx("input", { type: "text", placeholder: "Search...", value: notificationSearchQuery, onChange: (e) => setNotificationSearchQuery(e.target.value), className: "w-full pl-9 pr-3 py-1.5 text-sm rounded-lg border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-subtle))] text-[rgb(var(--fg-default))] placeholder:text-[rgb(var(--fg-muted))] focus:outline-none focus:border-[rgb(var(--color-
|
|
188
|
+
} }), _jsxs("div", { className: cn("z-50 bg-[rgb(var(--bg-surface))] rounded-2xl shadow-2xl border border-[rgb(var(--bd-default))] overflow-hidden", "fixed top-14 left-2 right-2 sm:absolute sm:top-auto sm:left-auto sm:right-0 sm:mt-2 sm:w-[28rem]"), children: [_jsxs("div", { className: "px-5 pt-5 pb-0 bg-[rgb(var(--bg-surface))]", children: [_jsxs("div", { className: "flex items-center gap-3 mb-4", children: [_jsx("h3", { className: "text-lg font-bold text-[rgb(var(--fg-default))] flex-shrink-0", children: "Notifications" }), _jsxs("div", { className: "relative flex-1", children: [_jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-[rgb(var(--fg-muted))]" }), _jsx("input", { type: "text", placeholder: "Search...", value: notificationSearchQuery, onChange: (e) => setNotificationSearchQuery(e.target.value), className: "w-full pl-9 pr-3 py-1.5 text-sm rounded-lg border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-subtle))] text-[rgb(var(--fg-default))] placeholder:text-[rgb(var(--fg-muted))] focus:outline-none focus:border-[rgb(var(--color-focus))] focus:bg-[rgb(var(--bg-surface))] transition-colors" })] }), _jsx("button", { onClick: (e) => {
|
|
189
189
|
e.stopPropagation();
|
|
190
190
|
setShowNotificationDropdown(false);
|
|
191
191
|
router.push('/settings?tab=notifications');
|
|
@@ -97,7 +97,7 @@ export function ConversationList({ currentUserId, onSelectRoom, onNewConversatio
|
|
|
97
97
|
const handleSelectRoom = useCallback((room) => {
|
|
98
98
|
onSelectRoom(room);
|
|
99
99
|
}, [onSelectRoom]);
|
|
100
|
-
return (_jsxs("div", { className: cn('flex flex-col h-full', className), children: [_jsxs("div", { className: "flex-shrink-0 px-3 pt-3 pb-2 space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h2", { className: "text-lg font-semibold text-[rgb(var(--fg-default))]", children: t('Messages') }), _jsx("button", { onClick: onNewConversation, className: "w-8 h-8 rounded-lg flex items-center justify-center hover:bg-[rgb(var(--bg-hover))] text-[rgb(var(--fg-muted))] transition-colors", title: t('New conversation'), children: _jsx(Plus, { className: "w-5 h-5" }) })] }), _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 w-4 h-4 text-[rgb(var(--fg-muted))]" }), _jsx("input", { type: "text", value: searchText, onChange: e => setSearchText(e.target.value), placeholder: t('Search conversations...'), className: "w-full h-8 pl-8 pr-8 rounded-lg bg-[rgb(var(--bg-subtle))] text-sm text-[rgb(var(--fg-default))] placeholder:text-[rgb(var(--fg-muted))] border border-[rgb(var(--bd-default))] focus:outline-none focus:ring-1 focus:ring-[rgb(var(--color-
|
|
100
|
+
return (_jsxs("div", { className: cn('flex flex-col h-full', className), children: [_jsxs("div", { className: "flex-shrink-0 px-3 pt-3 pb-2 space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h2", { className: "text-lg font-semibold text-[rgb(var(--fg-default))]", children: t('Messages') }), _jsx("button", { onClick: onNewConversation, className: "w-8 h-8 rounded-lg flex items-center justify-center hover:bg-[rgb(var(--bg-hover))] text-[rgb(var(--fg-muted))] transition-colors", title: t('New conversation'), children: _jsx(Plus, { className: "w-5 h-5" }) })] }), _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 w-4 h-4 text-[rgb(var(--fg-muted))]" }), _jsx("input", { type: "text", value: searchText, onChange: e => setSearchText(e.target.value), placeholder: t('Search conversations...'), className: "w-full h-8 pl-8 pr-8 rounded-lg bg-[rgb(var(--bg-subtle))] text-sm text-[rgb(var(--fg-default))] placeholder:text-[rgb(var(--fg-muted))] border border-[rgb(var(--bd-default))] focus:outline-none focus:ring-1 focus:ring-[rgb(var(--color-focus))]" }), searchText && (_jsx("button", { onClick: () => setSearchText(''), className: "absolute right-2 top-1/2 -translate-y-1/2 text-[rgb(var(--fg-muted))]", children: _jsx(X, { className: "w-3.5 h-3.5" }) }))] }), _jsx("div", { className: "flex gap-1", children: tabs.map(tab => (_jsx("button", { onClick: () => setFilter(tab.key), className: cn('flex-1 py-1 px-2 rounded-md text-xs font-medium transition-colors', filter === tab.key
|
|
101
101
|
? 'bg-[rgb(var(--color-primary))] text-white'
|
|
102
102
|
: 'text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-hover))]'), children: tab.label }, tab.key))) })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-1.5 py-1", children: state.loadingConversations ? (_jsx("div", { className: "space-y-2 px-2", children: [1, 2, 3, 4, 5].map(i => (_jsxs("div", { className: "flex items-center gap-3 py-2.5 animate-pulse", children: [_jsx("div", { className: "w-10 h-10 rounded-full bg-[rgb(var(--bg-subtle))]" }), _jsxs("div", { className: "flex-1 space-y-1.5", children: [_jsx("div", { className: "h-3.5 w-24 rounded bg-[rgb(var(--bg-subtle))]" }), _jsx("div", { className: "h-3 w-40 rounded bg-[rgb(var(--bg-subtle))]" })] })] }, i))) })) : filteredConversations.length === 0 ? (_jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-[rgb(var(--fg-muted))]", children: [_jsx(MessageSquare, { className: "w-10 h-10 mb-2 opacity-40" }), _jsx("p", { className: "text-sm", children: searchText ? t('No conversations found') : t('No conversations yet') }), !searchText && (_jsx("button", { onClick: onNewConversation, className: "mt-2 text-xs text-[rgb(var(--color-primary))] hover:underline", children: t('Start a conversation') }))] })) : (filteredConversations.map(room => (_jsx(ConversationListItem, { room: room, isActive: activeRoomId === room.RoomID, unreadCount: state.unreadCounts[room.RoomID] || 0, isOnline: room.Type === 'DM' ? actions.isUserOnline(room.RoomID) : undefined, currentUserId: currentUserId, onClick: () => handleSelectRoom(room) }, room.RoomID)))) })] }));
|
|
103
103
|
}
|
|
@@ -102,7 +102,7 @@ export function CreateConversationModal({ open, onClose, onCreated, currentUserI
|
|
|
102
102
|
: selectedUsers.length > 0 && name.trim();
|
|
103
103
|
return (_jsx(Modal, { open: open, onOpenChange: onClose, children: _jsxs(ModalContent, { size: "md", hideCloseButton: true, disableOutsideClick: true, className: "p-0 flex flex-col overflow-hidden max-h-[85vh]", children: [_jsx(ModalHeader, { className: "px-5 py-4 border-b border-[rgb(var(--bd-default))]", children: _jsx(ModalTitle, { children: t('New Conversation') }) }), _jsxs("div", { className: "flex-1 overflow-y-auto p-5 space-y-4", children: [_jsx("div", { className: "grid grid-cols-3 gap-2", children: typeOptions.map(opt => (_jsxs("button", { onClick: () => { setType(opt.key); setSelectedUsers([]); }, className: cn('flex flex-col items-center gap-1 p-3 rounded-lg border transition-colors', type === opt.key
|
|
104
104
|
? 'border-[rgb(var(--color-primary))] bg-[rgb(var(--color-primary)/0.05)]'
|
|
105
|
-
: 'border-[rgb(var(--bd-default))] hover:bg-[rgb(var(--bg-hover))]'), children: [_jsx(opt.icon, { className: cn('w-5 h-5', type === opt.key ? 'text-[rgb(var(--color-primary))]' : 'text-[rgb(var(--fg-muted))]') }), _jsx("span", { className: "text-xs font-medium", children: opt.label })] }, opt.key))) }), type !== 'DM' && (_jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-medium text-[rgb(var(--fg-muted))]", children: t('Name') }), _jsx("input", { value: name, onChange: e => setName(e.target.value), placeholder: type === 'Group' ? t('Group name') : t('Channel name'), className: "w-full h-9 px-3 rounded-lg bg-[rgb(var(--bg-subtle))] text-sm text-[rgb(var(--fg-default))] border border-[rgb(var(--bd-default))] focus:outline-none focus:ring-1 focus:ring-[rgb(var(--color-
|
|
105
|
+
: 'border-[rgb(var(--bd-default))] hover:bg-[rgb(var(--bg-hover))]'), children: [_jsx(opt.icon, { className: cn('w-5 h-5', type === opt.key ? 'text-[rgb(var(--color-primary))]' : 'text-[rgb(var(--fg-muted))]') }), _jsx("span", { className: "text-xs font-medium", children: opt.label })] }, opt.key))) }), type !== 'DM' && (_jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-medium text-[rgb(var(--fg-muted))]", children: t('Name') }), _jsx("input", { value: name, onChange: e => setName(e.target.value), placeholder: type === 'Group' ? t('Group name') : t('Channel name'), className: "w-full h-9 px-3 rounded-lg bg-[rgb(var(--bg-subtle))] text-sm text-[rgb(var(--fg-default))] border border-[rgb(var(--bd-default))] focus:outline-none focus:ring-1 focus:ring-[rgb(var(--color-focus))]" }), _jsx("input", { value: description, onChange: e => setDescription(e.target.value), placeholder: t('Description (optional)'), className: "w-full h-9 px-3 rounded-lg bg-[rgb(var(--bg-subtle))] text-sm text-[rgb(var(--fg-default))] border border-[rgb(var(--bd-default))] focus:outline-none focus:ring-1 focus:ring-[rgb(var(--color-focus))]" }), type === 'Channel' && (_jsxs("label", { className: "flex items-center gap-2 cursor-pointer", children: [_jsx("input", { type: "checkbox", checked: isPublic, onChange: e => setIsPublic(e.target.checked), className: "rounded" }), _jsx("span", { className: "text-sm text-[rgb(var(--fg-default))]", children: t('Public channel') })] }))] })), selectedUsers.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-1.5", children: selectedUsers.map(user => (_jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-1 rounded-full bg-[rgb(var(--color-primary)/0.1)] text-xs text-[rgb(var(--color-primary))]", children: [user.UserName, _jsx("button", { onClick: () => toggleUser(user), className: "hover:opacity-70", children: _jsx(X, { className: "w-3 h-3" }) })] }, user.UserID))) })), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-medium text-[rgb(var(--fg-muted))]", children: type === 'DM' ? t('Select person') : t('Add members') }), _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 w-4 h-4 text-[rgb(var(--fg-muted))]" }), _jsx("input", { value: searchText, onChange: e => setSearchText(e.target.value), placeholder: t('Search by name or email...'), autoComplete: "off", "data-1p-ignore": true, "data-lpignore": "true", className: "w-full h-9 pl-8 pr-3 rounded-lg bg-[rgb(var(--bg-subtle))] text-sm text-[rgb(var(--fg-default))] border border-[rgb(var(--bd-default))] focus:outline-none focus:ring-1 focus:ring-[rgb(var(--color-focus))]" })] })] }), _jsx("div", { className: "max-h-48 overflow-y-auto rounded-lg border border-[rgb(var(--bd-default))]", children: filteredContacts.length === 0 ? (_jsx("div", { className: "p-4 text-center text-sm text-[rgb(var(--fg-muted))]", children: t('No contacts found') })) : (filteredContacts.map(contact => {
|
|
106
106
|
const isSelected = selectedUsers.some(u => u.UserID === contact.UserID);
|
|
107
107
|
return (_jsxs("button", { onClick: () => toggleUser(contact), className: cn('w-full flex items-center gap-3 px-3 py-2 hover:bg-[rgb(var(--bg-hover))] transition-colors', isSelected && 'bg-[rgb(var(--color-primary)/0.05)]'), children: [_jsx("div", { className: cn('w-8 h-8 rounded-full flex items-center justify-center text-white text-xs font-medium flex-shrink-0', getAvatarColor(contact.UserID)), children: getInitials(contact.UserName) }), _jsxs("div", { className: "flex-1 min-w-0 text-left", children: [_jsx("p", { className: "text-sm font-medium text-[rgb(var(--fg-default))] truncate", children: contact.UserName }), contact.Designation && (_jsx("p", { className: "text-xs text-[rgb(var(--fg-muted))] truncate", children: contact.Designation }))] }), isSelected && (_jsx(Check, { className: "w-4 h-4 text-[rgb(var(--color-primary))] flex-shrink-0" }))] }, contact.UserID));
|
|
108
108
|
})) })] }), _jsxs("div", { className: "flex justify-end gap-2 px-5 py-3 border-t border-[rgb(var(--bd-default))]", children: [_jsx("button", { onClick: onClose, className: "px-4 h-9 rounded-lg text-sm font-medium text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-hover))] transition-colors", children: t('Cancel') }), _jsx("button", { onClick: handleCreate, disabled: !canCreate || creating, className: "px-4 h-9 rounded-lg text-sm font-medium bg-[rgb(var(--color-primary))] text-white hover:opacity-90 disabled:opacity-50 transition-colors", children: creating ? t('Creating...') : type === 'DM' ? t('Start Chat') : t('Create') })] })] }) }));
|
|
@@ -143,7 +143,7 @@ export function MessageInput({ onSend, onUploadFile, onTyping, replyTo, onCancel
|
|
|
143
143
|
return prev.filter((_, i) => i !== idx);
|
|
144
144
|
});
|
|
145
145
|
}, []);
|
|
146
|
-
return (_jsxs("div", { className: "flex-shrink-0 border-t border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))]", children: [replyTo && (_jsxs("div", { className: "flex items-center gap-2 px-4 py-2 bg-[rgb(var(--bg-subtle))] border-b border-[rgb(var(--bd-default))]", children: [_jsx(Reply, { className: "w-4 h-4 text-[rgb(var(--color-primary))] flex-shrink-0" }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("p", { className: "text-xs font-medium text-[rgb(var(--color-primary))]", children: t('Replying to message') }), _jsx("p", { className: "text-xs text-[rgb(var(--fg-muted))] truncate", children: replyTo.Content })] }), _jsx("button", { onClick: onCancelReply, className: "flex-shrink-0 text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))]", children: _jsx(X, { className: "w-4 h-4" }) })] })), pendingFiles.length > 0 && (_jsx("div", { className: "flex gap-2 px-4 py-2 overflow-x-auto", children: pendingFiles.map((f, i) => (_jsxs("div", { className: "relative flex-shrink-0", children: [f.preview ? (_jsx("img", { src: f.preview, alt: f.file.name, className: "w-16 h-16 rounded-lg object-cover border border-[rgb(var(--bd-default))]" })) : (_jsxs("div", { className: "w-16 h-16 rounded-lg border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-subtle))] flex flex-col items-center justify-center", children: [_jsx(FileIcon, { className: "w-5 h-5 text-[rgb(var(--fg-muted))]" }), _jsx("span", { className: "text-[0.5rem] text-[rgb(var(--fg-muted))] mt-0.5 truncate max-w-[3.5rem]", children: f.file.name.split('.').pop()?.toUpperCase() })] })), _jsx("button", { onClick: () => removeFile(i), className: "absolute -top-1.5 -right-1.5 w-5 h-5 rounded-full bg-red-500 text-white flex items-center justify-center", children: _jsx(X, { className: "w-3 h-3" }) })] }, i))) })), _jsxs("div", { className: "flex items-end gap-2 px-3 py-2", children: [_jsx("button", { onClick: () => fileInputRef.current?.click(), disabled: disabled || uploading, className: "flex-shrink-0 w-9 h-9 rounded-lg flex items-center justify-center text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-hover))] transition-colors disabled:opacity-50", children: _jsx(Paperclip, { className: "w-5 h-5" }) }), _jsx("input", { ref: fileInputRef, type: "file", multiple: true, className: "hidden", onChange: handleFileSelect, accept: "image/*,.pdf,.doc,.docx,.xls,.xlsx,.txt,.csv,.zip,.rar" }), _jsx("textarea", { ref: textareaRef, value: text, onChange: e => { setText(e.target.value); handleTyping(); }, onKeyDown: handleKeyDown, disabled: disabled || uploading || isListening, placeholder: isListening ? t('Listening...') : (placeholder || t('Type a message...')), rows: 1, className: "flex-1 min-h-[2.25rem] max-h-[7.5rem] px-3 py-2 rounded-xl bg-[rgb(var(--bg-subtle))] text-sm text-[rgb(var(--fg-default))] placeholder:text-[rgb(var(--fg-muted))] border border-[rgb(var(--bd-default))] resize-none focus:outline-none focus:ring-1 focus:ring-[rgb(var(--color-
|
|
146
|
+
return (_jsxs("div", { className: "flex-shrink-0 border-t border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))]", children: [replyTo && (_jsxs("div", { className: "flex items-center gap-2 px-4 py-2 bg-[rgb(var(--bg-subtle))] border-b border-[rgb(var(--bd-default))]", children: [_jsx(Reply, { className: "w-4 h-4 text-[rgb(var(--color-primary))] flex-shrink-0" }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("p", { className: "text-xs font-medium text-[rgb(var(--color-primary))]", children: t('Replying to message') }), _jsx("p", { className: "text-xs text-[rgb(var(--fg-muted))] truncate", children: replyTo.Content })] }), _jsx("button", { onClick: onCancelReply, className: "flex-shrink-0 text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))]", children: _jsx(X, { className: "w-4 h-4" }) })] })), pendingFiles.length > 0 && (_jsx("div", { className: "flex gap-2 px-4 py-2 overflow-x-auto", children: pendingFiles.map((f, i) => (_jsxs("div", { className: "relative flex-shrink-0", children: [f.preview ? (_jsx("img", { src: f.preview, alt: f.file.name, className: "w-16 h-16 rounded-lg object-cover border border-[rgb(var(--bd-default))]" })) : (_jsxs("div", { className: "w-16 h-16 rounded-lg border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-subtle))] flex flex-col items-center justify-center", children: [_jsx(FileIcon, { className: "w-5 h-5 text-[rgb(var(--fg-muted))]" }), _jsx("span", { className: "text-[0.5rem] text-[rgb(var(--fg-muted))] mt-0.5 truncate max-w-[3.5rem]", children: f.file.name.split('.').pop()?.toUpperCase() })] })), _jsx("button", { onClick: () => removeFile(i), className: "absolute -top-1.5 -right-1.5 w-5 h-5 rounded-full bg-red-500 text-white flex items-center justify-center", children: _jsx(X, { className: "w-3 h-3" }) })] }, i))) })), _jsxs("div", { className: "flex items-end gap-2 px-3 py-2", children: [_jsx("button", { onClick: () => fileInputRef.current?.click(), disabled: disabled || uploading, className: "flex-shrink-0 w-9 h-9 rounded-lg flex items-center justify-center text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-hover))] transition-colors disabled:opacity-50", children: _jsx(Paperclip, { className: "w-5 h-5" }) }), _jsx("input", { ref: fileInputRef, type: "file", multiple: true, className: "hidden", onChange: handleFileSelect, accept: "image/*,.pdf,.doc,.docx,.xls,.xlsx,.txt,.csv,.zip,.rar" }), _jsx("textarea", { ref: textareaRef, value: text, onChange: e => { setText(e.target.value); handleTyping(); }, onKeyDown: handleKeyDown, disabled: disabled || uploading || isListening, placeholder: isListening ? t('Listening...') : (placeholder || t('Type a message...')), rows: 1, className: "flex-1 min-h-[2.25rem] max-h-[7.5rem] px-3 py-2 rounded-xl bg-[rgb(var(--bg-subtle))] text-sm text-[rgb(var(--fg-default))] placeholder:text-[rgb(var(--fg-muted))] border border-[rgb(var(--bd-default))] resize-none focus:outline-none focus:ring-1 focus:ring-[rgb(var(--color-focus))] disabled:opacity-50" }), speechSupported && (_jsx("button", { onClick: handleVoiceInput, disabled: disabled || uploading, className: cn('flex-shrink-0 w-9 h-9 rounded-lg flex items-center justify-center transition-colors', isListening
|
|
147
147
|
? 'text-red-500 bg-red-500/10 animate-pulse'
|
|
148
148
|
: 'text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-hover))]', 'disabled:opacity-50'), children: isListening ? _jsx(MicOff, { className: "w-5 h-5" }) : _jsx(Mic, { className: "w-5 h-5" }) })), _jsx("button", { onClick: handleSubmit, disabled: disabled || uploading || isListening || (!text.trim() && pendingFiles.length === 0), className: cn('flex-shrink-0 w-9 h-9 rounded-lg flex items-center justify-center transition-colors', text.trim() || pendingFiles.length > 0
|
|
149
149
|
? 'bg-[rgb(var(--color-primary))] text-white hover:opacity-90'
|
|
@@ -526,7 +526,7 @@ export function ImageModal({ isOpen: controlledIsOpen, onClose: controlledOnClos
|
|
|
526
526
|
? 'h-[95vh] max-w-[92vw]'
|
|
527
527
|
: 'w-auto max-w-[95vw] max-h-[95vh]'}`, style: isZoomMode && computedModalWidth ? { width: `${computedModalWidth}px` } : undefined, hideCloseButton: true, children: [cleanMode ? (_jsx(DialogTitle, { className: "sr-only", children: title || 'Preview' })) : (_jsx(DialogHeader, { className: "px-4 md:px-6 py-2.5 border-b border-[rgb(var(--bd-default))] flex-shrink-0 bg-[rgb(var(--bg-surface))]", children: _jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx(DialogTitle, { className: "flex-shrink-0 mr-auto", children: title }), isZoomMode && (_jsxs("div", { className: "flex items-center gap-1 flex-shrink-0", children: [_jsx("button", { className: zoomBtn, onClick: zoomOut, disabled: zoomScale <= MIN_SCALE, title: t('Zoom Out'), children: _jsx(Minus, { className: "h-3.5 w-3.5" }) }), _jsxs("div", { className: "relative", ref: zoomPresetsRef, children: [_jsxs("button", { className: `${zoomBtnActive} min-w-[3.5rem] gap-1`, onClick: () => setShowZoomPresets(!showZoomPresets), title: t('Zoom Level'), children: [physicalPercent, "%"] }), showZoomPresets && (_jsx("div", { className: "absolute top-full left-1/2 -translate-x-1/2 mt-1 bg-[rgb(var(--bg-surface))] border border-[rgb(var(--bd-default))] rounded-md shadow-lg z-50 py-1 min-w-[5rem]", children: PHYSICAL_PRESETS.map((preset) => (_jsxs("button", { className: `w-full text-left px-3 py-1.5 text-xs hover:bg-[rgb(var(--bg-subtle))] transition-colors ${physicalPercent === preset
|
|
528
528
|
? 'text-[rgb(var(--color-primary))] font-medium'
|
|
529
|
-
: 'text-[rgb(var(--fg-default))]'}`, onClick: () => { setZoomLevel(preset / 100); setShowZoomPresets(false); }, children: [preset, "%"] }, preset))) }))] }), _jsx("button", { className: zoomBtn, onClick: zoomIn, disabled: zoomScale >= MAX_SCALE, title: t('Zoom In'), children: _jsx(Plus, { className: "h-3.5 w-3.5" }) }), _jsx("div", { className: "w-px h-4 bg-[rgb(var(--bd-default))] mx-1" }), _jsxs("button", { className: zoomBtn, onClick: fitToPage, title: t('Fit to Page'), children: [_jsx(Maximize, { className: "h-3.5 w-3.5" }), _jsx("span", { className: "ml-1 hidden sm:inline", children: t('Fit Page') })] }), _jsxs("button", { className: zoomBtn, onClick: toggleFullScreen, title: t('Full Screen'), children: [_jsx(Maximize2, { className: "h-3.5 w-3.5" }), _jsx("span", { className: "ml-1 hidden sm:inline", children: t('Full Screen') })] }), mmScale && (_jsxs(_Fragment, { children: [_jsx("div", { className: "w-px h-4 bg-[rgb(var(--bd-default))] mx-1" }), _jsxs("span", { className: "flex items-center h-7 text-[0.65rem] text-[rgb(var(--fg-muted))] select-none whitespace-nowrap", children: ["1mm = ", mmScale, "px"] })] }))] })), extraHeaderButtons && (_jsxs(_Fragment, { children: [isZoomMode && _jsx("div", { className: "w-px h-4 bg-[rgb(var(--bd-default))] mx-1" }), _jsx("div", { className: "flex items-center gap-1.5 flex-shrink-0", children: extraHeaderButtons })] })), _jsxs("button", { onClick: handleClose, className: "flex-shrink-0 rounded-sm opacity-70 ring-offset-[rgb(var(--bg-surface))] transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-[rgb(var(--color-
|
|
529
|
+
: 'text-[rgb(var(--fg-default))]'}`, onClick: () => { setZoomLevel(preset / 100); setShowZoomPresets(false); }, children: [preset, "%"] }, preset))) }))] }), _jsx("button", { className: zoomBtn, onClick: zoomIn, disabled: zoomScale >= MAX_SCALE, title: t('Zoom In'), children: _jsx(Plus, { className: "h-3.5 w-3.5" }) }), _jsx("div", { className: "w-px h-4 bg-[rgb(var(--bd-default))] mx-1" }), _jsxs("button", { className: zoomBtn, onClick: fitToPage, title: t('Fit to Page'), children: [_jsx(Maximize, { className: "h-3.5 w-3.5" }), _jsx("span", { className: "ml-1 hidden sm:inline", children: t('Fit Page') })] }), _jsxs("button", { className: zoomBtn, onClick: toggleFullScreen, title: t('Full Screen'), children: [_jsx(Maximize2, { className: "h-3.5 w-3.5" }), _jsx("span", { className: "ml-1 hidden sm:inline", children: t('Full Screen') })] }), mmScale && (_jsxs(_Fragment, { children: [_jsx("div", { className: "w-px h-4 bg-[rgb(var(--bd-default))] mx-1" }), _jsxs("span", { className: "flex items-center h-7 text-[0.65rem] text-[rgb(var(--fg-muted))] select-none whitespace-nowrap", children: ["1mm = ", mmScale, "px"] })] }))] })), extraHeaderButtons && (_jsxs(_Fragment, { children: [isZoomMode && _jsx("div", { className: "w-px h-4 bg-[rgb(var(--bd-default))] mx-1" }), _jsx("div", { className: "flex items-center gap-1.5 flex-shrink-0", children: extraHeaderButtons })] })), _jsxs("button", { onClick: handleClose, className: "flex-shrink-0 rounded-sm opacity-70 ring-offset-[rgb(var(--bg-surface))] transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-[rgb(var(--color-focus))] focus:ring-offset-2", children: [_jsx(X, { className: "h-4 w-4 text-[rgb(var(--color-icon))]" }), _jsx("span", { className: "sr-only", children: "Close" })] })] }) })), !cleanMode && details && details.length > 0 && (_jsx("div", { className: "px-6 py-2 bg-[rgb(var(--bg-subtle))] border-b border-[rgb(var(--bd-default))] flex-shrink-0", children: _jsx("div", { className: "flex flex-wrap items-center justify-center gap-x-5 gap-y-1 text-xs text-[rgb(var(--fg-default))]", children: details.map((detail, index) => (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsxs("span", { className: "font-medium text-[rgb(var(--fg-muted))]", children: [detail.label, ":"] }), _jsx("span", { className: "font-normal", children: detail.value })] }, index))) }) })), isPdfMode && pdfUrl ? (_jsx("div", { className: "flex-1 bg-[rgb(var(--bg-subtle))] overflow-hidden p-0", style: { minHeight: 0 }, children: _jsx("embed", { src: pdfUrl, type: "application/pdf", className: "w-full h-full", style: { border: 'none' } }) })) : isZoomMode ? (
|
|
530
530
|
// Zoomable SVG Mode - uses native overflow scroll + CSS scale for zoom
|
|
531
531
|
_jsx("div", { ref: scrollContainerRef, className: "flex-1 bg-[rgb(var(--bg-subtle))] overflow-auto relative", style: { minHeight: 0 }, children: _jsx("div", { style: {
|
|
532
532
|
width: zoomScale <= 1 ? '100%' : `${zoomScale * 100}%`,
|
|
@@ -269,7 +269,7 @@ const ModalContent = React.forwardRef(({ className, children, hideCloseButton, d
|
|
|
269
269
|
if (disableOutsideClick || (hasOpenChild && hasOpenChild.current > 0)) {
|
|
270
270
|
e.preventDefault();
|
|
271
271
|
}
|
|
272
|
-
}, onEscapeKeyDown: handleEscapeKeyDown, ...props, children: [children, !hideCloseButton && (_jsxs(DialogPrimitive.Close, { className: "absolute right-2 top-2 sm:right-4 sm:top-4 rounded-sm opacity-70 ring-offset-[rgb(var(--bg-surface))] transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-[rgb(var(--color-
|
|
272
|
+
}, onEscapeKeyDown: handleEscapeKeyDown, ...props, children: [children, !hideCloseButton && (_jsxs(DialogPrimitive.Close, { className: "absolute right-2 top-2 sm:right-4 sm:top-4 rounded-sm opacity-70 ring-offset-[rgb(var(--bg-surface))] transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-[rgb(var(--color-focus))] focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-[rgb(var(--bg-hover))] data-[state=open]:text-[rgb(var(--fg-muted))]", children: [_jsx(X, { className: "h-4 w-4 sm:h-5 sm:w-5 text-[rgb(var(--color-icon))]" }), _jsx("span", { className: "sr-only", children: "Close" })] }))] })] }));
|
|
273
273
|
});
|
|
274
274
|
ModalContent.displayName = DialogPrimitive.Content.displayName;
|
|
275
275
|
/**
|
|
@@ -139,7 +139,7 @@ const Button = React.forwardRef(({ className, variant = 'primary', size = 'md',
|
|
|
139
139
|
if (iconOnly) {
|
|
140
140
|
// For icon-only buttons, use ghost variant by default if not specified
|
|
141
141
|
const iconOnlyVariant = variant === 'primary' ? 'ghost' : variant;
|
|
142
|
-
return (_jsx("button", { ref: ref, type: "button", title: tooltip, disabled: isDisabled, className: cn('inline-flex items-center justify-center', 'rounded-full border-0', 'transition-colors duration-150 ease-in-out', 'focus:outline-none focus-visible:ring-2 focus-visible:ring-[rgb(var(--color-
|
|
142
|
+
return (_jsx("button", { ref: ref, type: "button", title: tooltip, disabled: isDisabled, className: cn('inline-flex items-center justify-center', 'rounded-full border-0', 'transition-colors duration-150 ease-in-out', 'focus:outline-none focus-visible:ring-2 focus-visible:ring-[rgb(var(--color-focus))] focus-visible:ring-offset-2', 'disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none', iconOnlyVariant === 'ghost' && [
|
|
143
143
|
'text-[rgb(var(--fg-muted))]',
|
|
144
144
|
'hover:bg-[rgb(var(--bg-hover))]',
|
|
145
145
|
'active:bg-[rgb(var(--bg-subtle))]'
|
|
@@ -40,5 +40,5 @@ export function FormToggle({ isExpanded, onToggle, title, createTitle = 'Create
|
|
|
40
40
|
else {
|
|
41
41
|
onToggle(false);
|
|
42
42
|
}
|
|
43
|
-
}, className: "rounded-sm opacity-70 ring-offset-[rgb(var(--bg-surface))] transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-[rgb(var(--color-
|
|
43
|
+
}, className: "rounded-sm opacity-70 ring-offset-[rgb(var(--bg-surface))] transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-[rgb(var(--color-focus))] focus:ring-offset-2", title: "Close form", children: [_jsx(X, { className: "h-5 w-5 text-[rgb(var(--color-icon))]" }), _jsx("span", { className: "sr-only", children: "Close" })] }))] })] }), isExpanded && (_jsx("div", { className: cn("px-6 pb-4 pt-2 space-y-4 animate-in slide-in-from-top duration-200", contentClassName), children: children }))] }));
|
|
44
44
|
}
|
|
@@ -48,7 +48,7 @@ const Input = React.forwardRef(({ className, type = "text", label, error, helper
|
|
|
48
48
|
};
|
|
49
49
|
// Compact mode - just return the input without wrapper
|
|
50
50
|
if (compact) {
|
|
51
|
-
return (_jsx("input", { id: inputId, name: inputName, type: type, className: cn("flex h-10 w-full border px-3 py-2 text-xs", "bg-[rgb(var(--bg-surface))] text-[rgb(var(--fg-default))] placeholder:text-[rgb(var(--fg-subtle))]", "focus:outline-none focus:ring-2 focus:ring-[rgb(var(--color-
|
|
51
|
+
return (_jsx("input", { id: inputId, name: inputName, type: type, className: cn("flex h-10 w-full border px-3 py-2 text-xs", "bg-[rgb(var(--bg-surface))] text-[rgb(var(--fg-default))] placeholder:text-[rgb(var(--fg-subtle))]", "focus:outline-none focus:ring-2 focus:ring-[rgb(var(--color-focus))]/10", "disabled:cursor-not-allowed disabled:opacity-50", "transition-all duration-200", type === "number" && "[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
|
|
52
52
|
// Joined group styling
|
|
53
53
|
position === 'first' && "rounded-l border-r-0", position === 'middle' && "border-r-0", position === 'last' && "rounded-r", position === 'only' && "rounded", !position && "rounded",
|
|
54
54
|
// Edited field highlighting
|
|
@@ -58,10 +58,10 @@ const Input = React.forwardRef(({ className, type = "text", label, error, helper
|
|
|
58
58
|
? "border-[rgb(var(--color-danger))] focus:border-[rgb(var(--color-danger))]"
|
|
59
59
|
: isEdited
|
|
60
60
|
? "border-[rgb(var(--color-warning))] focus:border-[rgb(var(--color-warning))] focus:ring-[rgb(var(--color-warning))]/20 focus:z-10"
|
|
61
|
-
: "border-[rgb(var(--bd-default))] focus:border-[rgb(var(--color-
|
|
61
|
+
: "border-[rgb(var(--bd-default))] focus:border-[rgb(var(--color-focus))] focus:z-10", className), ref: ref, onChange: handleChange, onKeyDown: handleKeyDown, onFocus: handleFocus, min: type === 'number' ? 0 : undefined, ...props }));
|
|
62
62
|
}
|
|
63
63
|
// Standard mode with wrapper
|
|
64
|
-
return (_jsxs("div", { className: "w-full", children: [label && (_jsx("label", { htmlFor: inputId, className: "block text-xs font-medium text-[rgb(var(--fg-default))] mb-1.5", suppressHydrationWarning: true, children: label })), _jsxs("div", { className: "relative", children: [LeftIcon && (_jsx("div", { className: "absolute left-3 top-1/2 transform -translate-y-1/2", children: _jsx(LeftIcon, { className: "h-4 w-4 text-[rgb(var(--fg-muted))]" }) })), _jsx("input", { id: inputId, name: inputName, type: type, className: cn("flex h-10 w-full rounded-md border px-3 py-2 text-xs", "bg-[rgb(var(--bg-surface))] text-[rgb(var(--fg-default))] placeholder:text-[rgb(var(--fg-subtle))]", "focus:outline-none focus:ring-2 focus:ring-[rgb(var(--color-
|
|
64
|
+
return (_jsxs("div", { className: "w-full", children: [label && (_jsx("label", { htmlFor: inputId, className: "block text-xs font-medium text-[rgb(var(--fg-default))] mb-1.5", suppressHydrationWarning: true, children: label })), _jsxs("div", { className: "relative", children: [LeftIcon && (_jsx("div", { className: "absolute left-3 top-1/2 transform -translate-y-1/2", children: _jsx(LeftIcon, { className: "h-4 w-4 text-[rgb(var(--fg-muted))]" }) })), _jsx("input", { id: inputId, name: inputName, type: type, className: cn("flex h-10 w-full rounded-md border px-3 py-2 text-xs", "bg-[rgb(var(--bg-surface))] text-[rgb(var(--fg-default))] placeholder:text-[rgb(var(--fg-subtle))]", "focus:outline-none focus:ring-2 focus:ring-[rgb(var(--color-focus))]/10", "disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-[rgb(var(--bg-subtle))]", "transition-all duration-200", type === "number" && "[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none", LeftIcon && "pl-10", RightIcon && "pr-10",
|
|
65
65
|
// Edited field highlighting
|
|
66
66
|
isEdited && !props.disabled && "bg-[rgb(var(--color-warning-subtle))] border-[rgb(var(--color-warning))]",
|
|
67
67
|
// Border color
|
|
@@ -69,7 +69,7 @@ const Input = React.forwardRef(({ className, type = "text", label, error, helper
|
|
|
69
69
|
? "border-[rgb(var(--color-danger))] focus:border-[rgb(var(--color-danger))]"
|
|
70
70
|
: isEdited
|
|
71
71
|
? "border-[rgb(var(--color-warning))] focus:border-[rgb(var(--color-warning))] focus:ring-[rgb(var(--color-warning))]/20"
|
|
72
|
-
: "border-[rgb(var(--bd-default))] focus:border-[rgb(var(--color-
|
|
72
|
+
: "border-[rgb(var(--bd-default))] focus:border-[rgb(var(--color-focus))]", className), ref: ref, suppressHydrationWarning: label ? true : false, onChange: handleChange, onKeyDown: handleKeyDown, onFocus: handleFocus, min: type === 'number' ? 0 : undefined, ...props }), RightIcon && (_jsx("div", { className: cn("absolute right-3 top-1/2 transform -translate-y-1/2", onRightIconClick && !props.disabled && "cursor-pointer", props.disabled && "opacity-50 cursor-not-allowed"), onClick: props.disabled ? undefined : onRightIconClick, children: _jsx(RightIcon, { className: "h-4 w-4 text-[rgb(var(--fg-muted))]" }) }))] }), error && typeof error === 'string' && (_jsx("p", { className: "mt-1 text-sm text-[rgb(var(--color-danger))]", children: error })), helper && !error && (_jsx("p", { className: "mt-1 text-sm text-[rgb(var(--fg-muted))]", children: helper }))] }));
|
|
73
73
|
});
|
|
74
74
|
Input.displayName = "Input";
|
|
75
75
|
export { Input };
|
|
@@ -10,9 +10,9 @@ import { Dropdown } from '../../forms/dropdown/index.js';
|
|
|
10
10
|
const TabsRoot = TabsPrimitive.Root;
|
|
11
11
|
const TabsList = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.List, { ref: ref, className: cn('inline-flex h-10 items-center justify-center rounded-md bg-[rgb(var(--bg-subtle))] p-1 text-[rgb(var(--fg-muted))]', className), ...props })));
|
|
12
12
|
TabsList.displayName = TabsPrimitive.List.displayName;
|
|
13
|
-
const TabsTrigger = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.Trigger, { ref: ref, className: cn('inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-[rgb(var(--bg-surface))] transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[rgb(var(--color-
|
|
13
|
+
const TabsTrigger = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.Trigger, { ref: ref, className: cn('inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-[rgb(var(--bg-surface))] transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[rgb(var(--color-focus))] focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-[rgb(var(--bg-surface))] data-[state=active]:text-[rgb(var(--fg-default))] data-[state=active]:shadow-sm', className), suppressHydrationWarning: true, ...props })));
|
|
14
14
|
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
|
|
15
|
-
const TabsContent = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.Content, { ref: ref, className: cn('mt-2 ring-offset-[rgb(var(--bg-surface))] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[rgb(var(--color-
|
|
15
|
+
const TabsContent = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.Content, { ref: ref, className: cn('mt-2 ring-offset-[rgb(var(--bg-surface))] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[rgb(var(--color-focus))] focus-visible:ring-offset-2', className), suppressHydrationWarning: true, ...props })));
|
|
16
16
|
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
|
17
17
|
export function Tabs({ tabs, activeTab, onTabChange, fullWidth = false, className = '', variant = 'pill', size = 'md', dropdownValues, onDropdownChange }) {
|
|
18
18
|
const containerClasses = cn('inline-flex items-center max-w-full overflow-x-auto scrollbar-hide [-webkit-overflow-scrolling:touch]', variant === 'pill' && 'bg-[rgb(var(--bg-subtle))] rounded-full border border-[rgb(var(--bd-default))] p-px gap-0.5', variant === 'rounded' && 'rounded-lg border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))] p-0.5', fullWidth && 'w-full', className);
|
package/dist/styles/tokens.css
CHANGED
|
@@ -22,6 +22,9 @@
|
|
|
22
22
|
|
|
23
23
|
/* Primary Color System (Main brand/accent) - Default #003366 */
|
|
24
24
|
--color-primary: 0 51 102; /* Primary brand color #003366 */
|
|
25
|
+
/* What a focused field or button is outlined in. The brand colour unless the app says
|
|
26
|
+
otherwise: an app that keeps its brand colour for primary actions sets a neutral here. */
|
|
27
|
+
--color-focus: var(--color-primary);
|
|
25
28
|
--color-primary-hover: 0 40 82; /* Primary hover state - darker #003366 */
|
|
26
29
|
--color-primary-subtle: 250 251 252; /* Very light primary backgrounds (0.02 opacity equivalent) */
|
|
27
30
|
--color-primary-muted: 102 153 204; /* Muted primary */
|