feat(ui): enhance frontend architecture and improve user experience
CI/CD Pipeline / Test (push) Successful in 21m56s
CI/CD Pipeline / Security Scan (push) Successful in 10m54s
CI/CD Pipeline / Build and Push Images (push) Failing after 2m12s

Refactor the frontend to use a more consistent design system and improve the overall user interface and experience.

- Implement a consistent use of `Card` components across various pages (Dashboard, Settings, Notes, etc.).
- Improve layout responsiveness and spacing in several modules.
- Enhance the Tasks page with drag-and-drop status updates and a Kanban-style view.
- Update the Calendar view with better color coding for task priorities and types.
- Refactor the Bookmarks page to use a grid layout with improved card previews.
- Update the Nginx configuration to handle SPA routing and health checks more effectively.
- Standardize import paths using `@/` aliases.
- Fix minor bugs in message sending and loading states.
- Update Docker configuration to build from source and use a specific backend port.
This commit is contained in:
Tomas Dvorak
2026-05-20 16:36:48 +02:00
parent 1e377a01b0
commit 67dc5cc737
18 changed files with 503 additions and 681 deletions
+5 -108
View File
@@ -9,7 +9,6 @@ import {
FileText as FileTextIcon,
Sparkles,
ChevronDown,
Settings,
Trash,
User
} from 'lucide-solid'
@@ -386,109 +385,8 @@ const Chat = () => {
}
return (
<div class="mt-4 pb-32 max-w-7xl mx-auto">
<div class="bg-background rounded-lg border shadow-sm">
{/* Header with Model Selection */}
<div class="p-6 border-b bg-card/95 backdrop-blur-sm">
<div class="flex items-center justify-between">
<div class="flex items-center gap-6">
<div class="flex items-center gap-3">
<div>
<h2 class="font-semibold text-lg">AI Assistant</h2>
<p class="text-sm text-muted-foreground">Your intelligent workspace companion</p>
</div>
</div>
<div class="flex items-center gap-1 p-1 bg-muted rounded-lg">
<button
onClick={() => setActiveView('chat')}
class={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
activeView() === 'chat'
? 'bg-background shadow-sm'
: 'text-muted-foreground hover:text-foreground'
}`}
>
Chat
</button>
<button
onClick={() => setActiveView('ai-tools')}
class={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
activeView() === 'ai-tools'
? 'bg-background shadow-sm'
: 'text-muted-foreground hover:text-foreground'
}`}
>
AI Tools
</button>
</div>
</div>
{/* Settings Button */}
<Button
variant="ghost"
size="sm"
onClick={() => setShowSettings(!showSettings())}
class="flex items-center gap-2 px-3 py-2 hover:bg-muted rounded-lg text-sm transition-colors"
>
<Settings class="h-4 w-4" />
Settings
</Button>
{/* Enhanced AI Model Picker */}
<div class="relative">
<button
onClick={() => setShowModelPicker(!showModelPicker())}
class="flex items-center gap-2 px-4 py-2 bg-primary text-primary-foreground hover:bg-primary/90 rounded-lg text-sm transition-colors"
>
<span>{getAIModels().find(m => m.id === selectedModel())?.name || 'Select Model'}</span>
<ChevronDown class={`h-4 w-4 transition-transform ${showModelPicker() ? 'rotate-180' : ''}`} />
</button>
<Show when={showModelPicker()}>
<div class="absolute right-0 mt-2 w-80 bg-background border rounded-lg shadow-lg z-50 p-2 max-h-96 overflow-y-auto">
<div class="p-2 border-b mb-2">
<h4 class="text-sm font-semibold text-foreground">Select AI Model</h4>
<p class="text-xs text-muted-foreground">Choose the best model for your needs</p>
</div>
<For each={getAIModels()}>
{model => (
<button
onClick={() => {
setSelectedModel(model.id)
setShowModelPicker(false)
}}
class={`w-full text-left p-3 rounded-lg transition-colors ${
selectedModel() === model.id
? 'bg-primary/10 border border-primary/20'
: 'hover:bg-muted'
}`}
>
<div class="flex items-center justify-between">
<div class="flex-1">
<div class="font-medium text-sm">{model.name}</div>
<div class="text-xs text-muted-foreground mt-1">{model.description}</div>
<div class="flex items-center gap-2 mt-2">
<span class="text-xs px-2 py-1 bg-primary/10 text-primary rounded-full">
{model.provider}
</span>
<span class="text-xs px-2 py-1 bg-muted text-muted-foreground rounded-full">
{model.category}
</span>
</div>
</div>
{selectedModel() === model.id && (
<div class="w-2 h-2 bg-primary rounded-full"></div>
)}
</div>
</button>
)}
</For>
</div>
</Show>
</div>
</div>
</div>
<div class="mt-4 pb-32 max-w-7xl mx-auto flex flex-col md:flex-row gap-4">
<div class="w-72 flex-shrink-0 bg-background rounded-lg border shadow-sm overflow-hidden flex flex-col">
<Show when={showSettings()}>
<div class="p-6 border-b bg-muted/30">
<div class="flex items-center justify-between mb-4">
@@ -741,7 +639,7 @@ const Chat = () => {
</div>
{/* Chat Area */}
<div class="flex-1 flex flex-col min-w-0 ml-80">
<div class="flex-1 flex flex-col min-w-0 bg-background rounded-lg border shadow-sm overflow-hidden">
<div class="hidden md:flex items-center justify-between p-6 border-b bg-card/95 backdrop-blur-sm">
<div class="flex items-center gap-6">
<div class="flex items-center gap-3">
@@ -811,9 +709,9 @@ const Chat = () => {
</div>
{/* Main Content Area */}
<div class="flex flex-col">
<div class="flex-1 flex flex-col min-h-0">
<Show when={activeView() === 'chat'}>
<div class="flex-1 overflow-y-auto h-[calc(100vh-320px)]">
<div class="flex-1 overflow-y-auto min-h-0">
<div class="space-y-6 max-w-5xl mx-auto p-6">
<For each={messages()}>
{message => (
@@ -1111,7 +1009,6 @@ const Chat = () => {
</div>
</Show>
</div>
<div class="clear-both"></div>
</div>
</div>
)
@@ -0,0 +1,935 @@
/* Full-screen shell aligned with the AI chat layout */
.messages-shell {
display: flex;
flex: 1;
min-height: 0;
background:
radial-gradient(circle at top left, hsl(var(--primary) / 0.08), transparent 28rem),
linear-gradient(180deg, hsl(var(--background)) 0%, hsl(var(--background)) 100%);
}
.messages-alert-wrap {
padding: 1rem 1rem 0;
background: hsl(var(--background));
}
.messages-spotlight-alert {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 1rem;
border-radius: 1rem;
border: 1px solid hsl(var(--border) / 0.8);
padding: 0.9rem 1rem;
box-shadow: 0 18px 50px -32px hsl(0 0% 0% / 0.85);
}
.messages-spotlight-copy {
min-width: 0;
}
.messages-spotlight-error {
background: linear-gradient(135deg, hsl(var(--destructive) / 0.14), hsl(var(--background)));
border-color: hsl(var(--destructive) / 0.3);
}
.messages-spotlight-warning {
background: linear-gradient(135deg, hsl(38 92% 50% / 0.16), hsl(var(--background)));
border-color: hsl(38 92% 50% / 0.25);
}
.messages-spotlight-info {
background: linear-gradient(135deg, hsl(var(--primary) / 0.16), hsl(var(--background)));
border-color: hsl(var(--primary) / 0.25);
}
.messages-sidebar {
width: 20rem;
max-width: 22rem;
border-right: 1px solid hsl(var(--border));
background: hsl(var(--card));
display: flex;
flex-direction: column;
min-height: 0;
flex-shrink: 0;
}
.messages-sidebar-header {
padding: 1rem 1rem 0.9rem;
border-bottom: 1px solid hsl(var(--border));
background: hsl(var(--card) / 0.95);
backdrop-filter: blur(10px);
}
.messages-title-row,
.messages-sidebar-actions,
.messages-status-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.75rem;
}
.messages-title-wrap {
display: inline-flex;
align-items: center;
gap: 0.75rem;
}
.messages-title {
font-size: 1.125rem;
font-weight: 600;
color: hsl(var(--foreground));
}
.messages-status-row {
font-size: 0.75rem;
color: hsl(var(--muted-foreground));
letter-spacing: 0.025em;
}
/* Modern conversation list */
.messages-sidebar-list {
flex: 1;
overflow-y: auto;
padding: 1rem;
display: grid;
gap: 0.5rem;
align-content: start;
}
.messages-list-empty {
border: 2px dashed hsl(var(--border));
border-radius: 1rem;
background: hsl(var(--muted) / 0.3);
padding: 2rem;
text-align: center;
font-size: 0.875rem;
color: hsl(var(--muted-foreground));
}
/* Modern conversation items */
.conversation-item {
border: 1px solid hsl(var(--border) / 0.55);
border-radius: 0.9rem;
padding: 0.95rem 1rem;
text-align: left;
display: flex;
align-items: center;
gap: 0.75rem;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
cursor: pointer;
}
.conversation-item:hover {
background: hsl(var(--muted) / 0.45);
border-color: hsl(var(--primary) / 0.18);
transform: translateY(-1px);
box-shadow: 0 16px 30px -26px hsl(0 0% 0% / 0.85);
}
.conversation-item-active {
background: linear-gradient(135deg, hsl(var(--primary) / 0.14), hsl(var(--background)));
border-color: hsl(var(--primary) / 0.3);
box-shadow: inset 0 0 0 1px hsl(var(--primary) / 0.08);
}
.conversation-item-main {
flex: 1;
min-width: 0;
}
.conversation-item-heading,
.conversation-item-footer {
display: flex;
align-items: center;
gap: 0.75rem;
justify-content: space-between;
}
.conversation-item-name {
font-size: 0.875rem;
font-weight: 600;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: hsl(var(--foreground));
}
.conversation-item-preview {
font-size: 0.75rem;
color: hsl(var(--muted-foreground));
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-top: 0.25rem;
flex: 1;
}
.conversation-item-unread {
min-width: 1.5rem;
height: 1.5rem;
border-radius: 999px;
background: hsl(var(--primary));
color: hsl(var(--primary-foreground));
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 0.75rem;
font-weight: 600;
padding: 0 0.5rem;
box-shadow: 0 2px 4px hsl(var(--primary) / 0.2);
}
.conversation-item-avatar {
width: 2.75rem;
height: 2.75rem;
border-radius: 1rem;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 0.8rem;
font-weight: 700;
letter-spacing: 0.04em;
flex-shrink: 0;
border: 1px solid hsl(var(--border) / 0.35);
color: hsl(var(--foreground));
}
.conversation-item-avatar-dm {
background: linear-gradient(135deg, hsl(var(--primary) / 0.18), hsl(var(--primary) / 0.08));
}
.conversation-item-avatar-group {
background: linear-gradient(135deg, hsl(216 92% 60% / 0.22), hsl(192 92% 55% / 0.12));
}
.conversation-item-avatar-team {
background: linear-gradient(135deg, hsl(158 75% 42% / 0.22), hsl(143 70% 52% / 0.12));
}
.conversation-item-avatar-global {
background: linear-gradient(135deg, hsl(38 92% 56% / 0.24), hsl(16 92% 60% / 0.12));
}
.conversation-item-avatar-self {
background: linear-gradient(135deg, hsl(280 70% 60% / 0.2), hsl(324 70% 60% / 0.12));
}
.conversation-item-avatar-vault {
background: linear-gradient(135deg, hsl(0 0% 100% / 0.08), hsl(0 0% 100% / 0.02));
}
.conversation-item-avatar-default {
background: linear-gradient(135deg, hsl(var(--muted)), hsl(var(--muted) / 0.7));
}
.conversation-item-time {
font-size: 0.7rem;
color: hsl(var(--muted-foreground));
flex-shrink: 0;
}
.conversation-item-badge {
border-radius: 999px;
padding: 0.2rem 0.55rem;
font-size: 0.62rem;
font-weight: 600;
background: hsl(var(--primary) / 0.1);
color: hsl(var(--primary));
flex-shrink: 0;
}
/* Modern main conversation area */
.messages-main {
flex: 1;
min-width: 0;
min-height: 0;
display: grid;
grid-template-rows: auto auto auto minmax(0, 1fr) auto;
background: hsl(var(--background));
}
.messages-main-header {
border-bottom: 1px solid hsl(var(--border));
padding: 1rem 1.25rem;
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
background: hsl(var(--card) / 0.95);
backdrop-filter: blur(10px);
}
.messages-header-main {
display: inline-flex;
align-items: center;
gap: 0.75rem;
min-width: 0;
}
.messages-back-button {
flex-shrink: 0;
}
.messages-header-meta {
min-width: 0;
}
.messages-header-title {
font-size: 1.125rem;
font-weight: 600;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: hsl(var(--foreground));
}
.messages-header-subtitle {
color: hsl(var(--muted-foreground));
font-size: 0.75rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-top: 0.25rem;
}
.messages-header-actions {
display: inline-flex;
align-items: center;
gap: 0.75rem;
}
.messages-main-empty {
display: grid;
place-items: center;
padding: 3rem;
}
.messages-main-empty-card {
width: min(28rem, 100%);
border: 1px solid hsl(var(--border) / 0.7);
border-radius: 1.5rem;
padding: 2rem;
text-align: center;
background:
radial-gradient(circle at top, hsl(var(--primary) / 0.12), transparent 65%),
hsl(var(--card) / 0.96);
box-shadow: 0 28px 80px -44px hsl(0 0% 0% / 0.7);
}
.messages-main-empty-orb {
width: 3.5rem;
height: 3.5rem;
border-radius: 1.2rem;
margin: 0 auto 1rem;
display: inline-flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, hsl(var(--primary) / 0.18), hsl(var(--primary) / 0.06));
border: 1px solid hsl(var(--primary) / 0.18);
}
.messages-main-empty-title {
font-size: 1.05rem;
font-weight: 600;
color: hsl(var(--foreground));
}
.messages-main-empty-copy {
margin: 0.65rem auto 1.25rem;
max-width: 22rem;
color: hsl(var(--muted-foreground));
font-size: 0.9rem;
line-height: 1.55;
}
/* Modern call and transcript strips */
.messages-call-strip,
.messages-transcript-preview {
padding: 0.85rem 1.25rem;
font-size: 0.75rem;
color: hsl(var(--muted-foreground));
border-bottom: 1px solid hsl(var(--border));
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
background: hsl(var(--muted) / 0.3);
}
/* Modern message timeline */
.messages-timeline {
padding: 1.5rem;
overflow-y: auto;
display: grid;
gap: 1.5rem;
background:
linear-gradient(180deg, hsl(var(--background)) 0%, hsl(var(--muted) / 0.14) 100%);
}
.message-row {
display: flex;
margin-bottom: 0.5rem;
}
.message-row-me {
justify-content: flex-end;
}
.message-row-them {
justify-content: flex-start;
}
/* Modern message bubbles */
.message-bubble {
max-width: min(76%, 600px);
border-radius: 1rem;
border: 1px solid hsl(var(--border));
padding: 1rem;
box-shadow: 0 2px 8px hsl(0 0% 0% / 0.06);
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.message-bubble:hover {
transform: translateY(-1px);
box-shadow: 0 8px 16px hsl(0 0% 0% / 0.08);
}
.message-bubble-me {
background: linear-gradient(135deg, hsl(var(--primary)) 0%, hsl(var(--primary) / 0.9) 100%);
border-color: hsl(var(--primary) / 0.3);
color: hsl(var(--primary-foreground));
}
.message-bubble-them {
background: linear-gradient(135deg, hsl(var(--muted)) 0%, hsl(var(--muted) / 0.9) 100%);
border-color: hsl(var(--border) / 0.5);
}
.message-meta {
display: flex;
align-items: center;
gap: 0.75rem;
font-size: 0.75rem;
color: hsl(var(--muted-foreground));
margin-bottom: 0.75rem;
}
.message-avatar {
width: 2rem;
height: 2rem;
border-radius: 999px;
overflow: hidden;
background: hsl(var(--muted));
color: hsl(var(--foreground));
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 0.75rem;
font-weight: 700;
border: 2px solid hsl(var(--primary) / 0.2);
}
.message-time {
margin-left: auto;
}
.message-edited {
font-size: 0.625rem;
opacity: 0.7;
}
.message-body {
white-space: pre-wrap;
word-break: break-word;
line-height: 1.5;
font-size: 0.875rem;
}
/* Modern attachments */
.message-attachments {
margin-top: 1rem;
display: grid;
gap: 0.5rem;
}
.message-attachment-link,
.message-voice-note {
border: 1px solid hsl(var(--border));
border-radius: 0.5rem;
padding: 0.75rem;
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.75rem;
text-decoration: none;
transition: all 0.2s ease;
}
.message-attachment-link:hover {
background: hsl(var(--muted) / 0.6);
transform: translateY(-1px);
}
.message-voice-note {
flex-direction: column;
align-items: flex-start;
}
/* Modern references */
.message-reference-wrap {
margin-top: 1rem;
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.message-reference-pill {
border-radius: 999px;
border: 1px solid hsl(var(--border));
padding: 0.25rem 0.75rem;
font-size: 0.625rem;
color: hsl(var(--muted-foreground));
text-decoration: none;
transition: all 0.2s ease;
background: hsl(var(--muted) / 0.5);
}
.message-reference-pill:hover {
background: hsl(var(--muted) / 0.8);
transform: translateY(-1px);
}
/* Modern suggestions */
.message-suggestions {
margin-top: 1rem;
display: grid;
gap: 0.75rem;
}
.message-suggestion-card {
border: 1px solid hsl(var(--border));
border-radius: 0.5rem;
padding: 1rem;
background: hsl(var(--muted) / 0.3);
transition: all 0.2s ease;
}
.message-suggestion-card:hover {
background: hsl(var(--muted) / 0.5);
transform: translateY(-1px);
}
.message-suggestion-title {
font-size: 0.75rem;
text-transform: capitalize;
margin-bottom: 0.75rem;
font-weight: 600;
}
.message-suggestion-actions {
display: flex;
gap: 0.5rem;
}
/* Modern reactions */
.message-reaction-panel {
margin-top: 1rem;
display: grid;
gap: 0.5rem;
}
.message-reaction-add-row {
display: inline-flex;
align-items: center;
gap: 0.25rem;
}
.reaction-add-btn {
width: 2rem;
height: 2rem;
border-radius: 0.5rem;
border: 1px solid transparent;
display: inline-flex;
align-items: center;
justify-content: center;
color: hsl(var(--muted-foreground));
transition: all 0.2s ease;
}
.reaction-add-btn:hover {
border-color: hsl(var(--border));
background: hsl(var(--muted) / 0.6);
color: hsl(var(--foreground));
transform: scale(1.1);
}
.message-reaction-summary {
display: inline-flex;
flex-wrap: wrap;
gap: 0.25rem;
}
.reaction-pill {
border-radius: 999px;
border: 1px solid hsl(var(--border));
padding: 0.25rem 0.75rem;
display: inline-flex;
align-items: center;
gap: 0.25rem;
font-size: 0.625rem;
background: hsl(var(--card));
transition: all 0.2s ease;
}
.reaction-pill:hover {
transform: scale(1.1);
}
.reaction-pill-me {
border-color: hsl(var(--primary) / 0.5);
background: hsl(var(--primary) / 0.1);
color: hsl(var(--primary));
}
/* Modern composer */
.messages-composer {
position: relative;
border-top: 1px solid hsl(var(--border));
padding: 1.5rem;
display: grid;
gap: 0.75rem;
background: hsl(var(--card) / 0.95);
backdrop-filter: blur(10px);
}
@media (max-width: 767px) {
.messages-shell {
display: flex;
flex-direction: column;
}
.messages-sidebar,
.messages-main {
width: 100%;
max-width: none;
height: 100%;
min-height: 0;
}
.messages-shell-list .messages-main {
display: none;
}
.messages-shell-conversation .messages-sidebar {
display: none;
}
.messages-composer {
padding: 0.75rem;
}
}
.messages-composer-drag {
background: hsl(var(--primary) / 0.08);
border-color: hsl(var(--primary) / 0.2);
}
.messages-typing-line {
display: inline-flex;
align-items: center;
gap: 0.75rem;
font-size: 0.75rem;
color: hsl(var(--muted-foreground));
padding: 0.5rem;
background: hsl(var(--muted) / 0.3);
border-radius: 0.5rem;
margin-bottom: 0.5rem;
}
.typing-dots {
display: inline-flex;
align-items: center;
gap: 0.25rem;
}
.typing-dots span {
width: 0.25rem;
height: 0.25rem;
border-radius: 999px;
background: hsl(var(--primary));
animation: typingBounce 1.1s infinite ease-in-out;
}
.typing-dots span:nth-child(2) {
animation-delay: 0.14s;
}
.typing-dots span:nth-child(3) {
animation-delay: 0.28s;
}
@keyframes typingBounce {
0%, 80%, 100% {
transform: translateY(0);
opacity: 0.4;
}
40% {
transform: translateY(-2px);
opacity: 1;
}
}
/* Modern composer elements */
.composer-chip-wrap {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.composer-chip {
border-radius: 999px;
border: 1px solid hsl(var(--border));
background: hsl(var(--muted) / 0.4);
padding: 0.25rem 0.5rem;
display: inline-flex;
align-items: center;
gap: 0.25rem;
font-size: 0.625rem;
transition: all 0.2s ease;
}
.composer-chip:hover {
background: hsl(var(--muted) / 0.6);
transform: translateY(-1px);
}
.composer-chip-remove {
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 999px;
cursor: pointer;
transition: all 0.2s ease;
}
.composer-chip-remove:hover {
background: hsl(var(--destructive));
color: hsl(var(--destructive-foreground));
}
.messages-recording-line {
color: hsl(var(--destructive));
font-size: 0.75rem;
font-weight: 600;
padding: 0.75rem;
background: hsl(var(--destructive) / 0.1);
border-radius: 0.5rem;
margin-bottom: 0.5rem;
border: 1px solid hsl(var(--destructive) / 0.2);
}
.messages-composer-row {
display: grid;
grid-template-columns: auto auto minmax(0, 1fr) auto;
gap: 0.75rem;
align-items: end;
}
.messages-composer-input-wrap {
position: relative;
}
.messages-composer-textarea {
min-height: 3rem;
max-height: 9rem;
width: 100%;
resize: none;
border: 1px solid hsl(var(--border));
border-radius: 0.75rem;
background: hsl(var(--background));
padding: 0.75rem;
font-size: 0.875rem;
line-height: 1.25rem;
transition: all 0.2s ease;
}
.messages-composer-textarea:focus {
outline: none;
border-color: hsl(var(--primary));
box-shadow: 0 0 0 2px hsl(var(--primary) / 0.15);
}
/* Modern mention menu */
.mention-menu {
position: absolute;
left: 0;
right: 0;
bottom: calc(100% + 0.75rem);
border: 1px solid hsl(var(--border));
border-radius: 0.75rem;
background: hsl(var(--card));
box-shadow: 0 8px 26px hsl(0 0% 0% / 0.24);
max-height: 16rem;
overflow-y: auto;
z-index: 20;
backdrop-filter: blur(10px);
}
.mention-menu-empty {
padding: 0.75rem;
color: hsl(var(--muted-foreground));
font-size: 0.75rem;
}
.mention-option {
width: 100%;
text-align: left;
border: none;
background: transparent;
padding: 0.75rem;
display: flex;
align-items: center;
gap: 0.75rem;
transition: all 0.2s ease;
cursor: pointer;
}
.mention-option-active,
.mention-option:hover {
background: hsl(var(--muted) / 0.6);
}
.mention-option-copy {
min-width: 0;
}
.mention-option-title {
font-size: 0.75rem;
font-weight: 600;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.mention-option-sub {
font-size: 0.625rem;
color: hsl(var(--muted-foreground));
}
.messages-composer-footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
margin-top: 0.75rem;
}
.messages-inline-toggle {
display: inline-flex;
align-items: center;
gap: 0.5rem;
font-size: 0.75rem;
color: hsl(var(--muted-foreground));
}
/* Responsive design */
@media (max-width: 980px) {
.messages-sidebar {
width: 16rem;
min-width: 16rem;
border-inline: none;
border-radius: 0;
}
.message-bubble {
max-width: 86%;
}
}
@media (max-width: 760px) {
.messages-main {
grid-template-rows: auto auto auto auto minmax(0, 1fr) auto;
}
.messages-composer-row {
grid-template-columns: repeat(3, auto) 1fr auto;
}
.messages-composer-row > button:last-child {
grid-column: 5;
justify-self: end;
}
.messages-timeline {
padding: 1rem;
}
.message-bubble {
padding: 0.75rem;
}
.conversation-item {
padding: 0.75rem;
}
}
/* Modern animations and transitions */
.message-bubble,
.conversation-item,
.message-attachment-link,
.message-reference-pill,
.message-suggestion-card,
.reaction-pill,
.composer-chip,
.mention-option {
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
/* Focus states */
.messages-composer-textarea:focus,
.mention-option:focus {
outline: 2px solid hsl(var(--primary));
outline-offset: 2px;
}
/* Loading states */
.messages-composer-textarea:disabled {
opacity: 0.6;
cursor: not-allowed;
}
/* Dark mode enhancements */
[data-kb-theme="dark"] .message-bubble-them {
background: linear-gradient(135deg, hsl(var(--muted)) 0%, hsl(var(--muted) / 0.8) 100%);
border-color: hsl(var(--border) / 0.3);
}
[data-kb-theme="dark"] .conversation-item:hover {
background: hsl(var(--muted) / 0.4);
}
/* Accessibility improvements */
.message-bubble:focus,
.conversation-item:focus,
.mention-option:focus {
outline: 2px solid hsl(var(--primary));
outline-offset: 2px;
}
/* High contrast mode support */
@media (prefers-contrast: high) {
.message-bubble {
border-width: 2px;
}
.conversation-item {
border-width: 2px;
}
.reaction-pill {
border-width: 2px;
}
}
@@ -1768,6 +1768,7 @@ export const Messages = () => {
if (!selectedConversationId()) return;
const body = inputText().trim();
if (!body && selectedFiles().length === 0 && attachedLibraryFiles().length === 0 && composerAiReferences().length === 0) return;
if (sendingMessage()) return;
try {
const localFiles = [...selectedFiles()];
@@ -2751,6 +2752,7 @@ export const Messages = () => {
}}
disabled={
sendingMessage() ||
uploadProgress() !== null ||
(!inputText().trim() && selectedFiles().length === 0 && attachedLibraryFiles().length === 0 && composerAiReferences().length === 0)
}
>