Files
LoreMind/web/src/app/shared/ai-chat-drawer/ai-chat-drawer.component.html
IETM_FIXE\ietm6 af3a6d443c
Some checks failed
Build & Push Images / build (brain) (push) Has been cancelled
Build & Push Images / build (core) (push) Has been cancelled
Build & Push Images / build (web) (push) Has been cancelled
Build & Push Images / build-switcher (push) Has been cancelled
Mise en place de l'anglais comme deuxième langue pour l'application
2026-06-14 16:24:05 +02:00

208 lines
7.6 KiB
HTML

<aside
class="drawer"
[class.drawer-open]="isOpen"
[class.is-resizing]="isResizing"
[class.is-wide]="isWide"
[style.width.px]="effectiveWidth"
[attr.aria-label]="'aiChatDrawer.title' | translate">
<!-- Poignee de redimensionnement (desactivee en mode wide) -->
@if (!isWide) {
<div
class="resize-handle"
(mousedown)="onResizeStart($event)"
role="separator"
aria-orientation="vertical"
[attr.aria-label]="'aiChatDrawer.resizeAria' | translate"
[title]="'aiChatDrawer.resizeTitle' | translate"></div>
}
<!-- Sidebar conversations (mode persistent uniquement) -->
@if (persistent && sidebarOpen) {
<section class="conv-sidebar" [attr.aria-label]="'aiChatDrawer.conversations' | translate">
<div class="conv-sidebar-header">
<span class="conv-sidebar-title">{{ 'aiChatDrawer.conversations' | translate }}</span>
<button type="button" class="conv-new-btn" (click)="startNewConversation()" [disabled]="isStreaming" [title]="'aiChatDrawer.newConversation' | translate">
<lucide-icon [img]="MessageSquarePlus" [size]="16"></lucide-icon>
</button>
</div>
<ul class="conv-list">
@if (conversations.length === 0) {
<li class="conv-empty">{{ 'aiChatDrawer.noConversation' | translate }}</li>
}
@for (c of conversations; track c) {
<li
class="conv-item"
[class.active]="c.id === currentConversationId"
(click)="selectConversation(c)">
<span class="conv-item-title">{{ c.title }}</span>
<button
type="button"
class="conv-item-del"
(click)="deleteConversation(c, $event)"
[disabled]="isStreaming"
[title]="'common.delete' | translate">
<lucide-icon [img]="Trash2" [size]="12"></lucide-icon>
</button>
</li>
}
</ul>
</section>
}
<section class="conv-main">
<header class="drawer-header">
@if (persistent) {
<button
type="button"
class="sidebar-toggle"
(click)="toggleSidebar()"
[attr.aria-label]="(sidebarOpen ? 'aiChatDrawer.hideList' : 'aiChatDrawer.showList') | translate"
[title]="(sidebarOpen ? 'aiChatDrawer.hideList' : 'aiChatDrawer.showList') | translate">
<lucide-icon [img]="sidebarOpen ? PanelLeftClose : PanelLeftOpen" [size]="16"></lucide-icon>
</button>
}
<div class="header-title-wrap">
@if (persistent && currentConversationId) {
@if (!editingTitle) {
<h2 class="header-title" [title]="currentTitle">{{ currentTitle || ('aiChatDrawer.newConversation' | translate) }}</h2>
<button type="button" class="rename-btn" (click)="startRenameTitle()" [title]="'common.rename' | translate" [attr.aria-label]="'common.rename' | translate">
<lucide-icon [img]="Pencil" [size]="12"></lucide-icon>
</button>
} @else {
<input
class="rename-input"
type="text"
[(ngModel)]="titleDraft"
(keyup.enter)="submitRenameTitle()"
(keyup.escape)="cancelRenameTitle()"
(blur)="submitRenameTitle()"
autofocus />
}
} @else {
<h2 class="header-title">{{ 'aiChatDrawer.title' | translate }}</h2>
}
</div>
<button
type="button"
class="wide-toggle-btn"
(click)="toggleWide()"
[attr.aria-label]="(isWide ? 'aiChatDrawer.shrinkAria' : 'aiChatDrawer.expandAria') | translate"
[title]="(isWide ? 'aiChatDrawer.shrink' : 'aiChatDrawer.expand') | translate">
<lucide-icon [img]="isWide ? Minimize2 : Maximize2" [size]="16"></lucide-icon>
</button>
<button type="button" class="close-btn" (click)="onClose()" [attr.aria-label]="'common.close' | translate">
<lucide-icon [img]="X" [size]="18"></lucide-icon>
</button>
</header>
@if (usage) {
<div class="context-gauge" [attr.data-level]="usageLevel"
[attr.title]="(usageHasMax ? 'aiChatDrawer.gaugeTitleMax' : 'aiChatDrawer.gaugeTitle') | translate:{ system: usage.system, history: usage.history, current: usage.current, max: usage.max }">
<!-- Barre seulement si on connaît le plafond (Ollama). Cloud : compteur seul. -->
@if (usageHasMax) {
<div class="gauge-bar">
<div class="gauge-fill" [style.width.%]="usagePercent"></div>
</div>
}
<div class="gauge-label">
<span class="gauge-text">@if (usageHasMax) {
{{ 'aiChatDrawer.gaugeLabelMax' | translate:{ total: usageTotal, max: usage.max } }}
} @else {
{{ 'aiChatDrawer.gaugeLabel' | translate:{ total: usageTotal } }}
}</span>
@if (usageHasMax) {
<span class="gauge-percent">{{ usagePercent }}%</span>
}
</div>
</div>
}
<div #messagesContainer class="messages">
@if (messages.length === 0 && !currentAssistantText) {
<div class="msg msg-assistant md"
[innerHTML]="welcomeMessage | markdown">
</div>
}
@for (m of messages; track m) {
@if (m.role === 'user') {
<div class="msg msg-user">{{ m.content }}</div>
}
@if (m.role === 'assistant') {
<div class="msg msg-assistant md"
[innerHTML]="m.content | markdown"></div>
}
}
@if (currentAssistantText) {
<div class="msg msg-assistant msg-streaming md">
<span [innerHTML]="currentAssistantText | markdown"></span><span class="caret"></span>
</div>
}
@if (isStreaming && !currentAssistantText) {
<div class="typing-indicator" aria-live="polite">
<span></span><span></span><span></span>
</div>
}
@if (errorMessage) {
<div class="msg msg-error" role="alert">
{{ errorMessage }}
</div>
}
</div>
@if (primaryAction) {
<div class="primary-action">
<button
type="button"
class="primary-btn"
(click)="onPrimaryAction()"
[disabled]="isStreaming">
<lucide-icon [img]="Wand2" [size]="14"></lucide-icon>
{{ primaryAction.label }}
</button>
</div>
}
@if (quickSuggestions.length) {
<div class="quick-suggestions">
<p class="quick-label">{{ 'aiChatDrawer.quickSuggestions' | translate }}</p>
<div class="quick-list">
@for (s of quickSuggestions; track s) {
<button
type="button"
class="quick-btn"
(click)="useQuickSuggestion(s)"
[disabled]="isStreaming">
<lucide-icon [img]="Lightbulb" [size]="12"></lucide-icon>
{{ s }}
</button>
}
</div>
</div>
}
<form class="input-row" (ngSubmit)="send()">
<input
type="text"
[(ngModel)]="input"
name="chatInput"
[placeholder]="'aiChatDrawer.inputPlaceholder' | translate"
[disabled]="isStreaming"
autocomplete="off" />
<button type="submit" class="send-btn" [disabled]="!input.trim() || isStreaming" [attr.aria-label]="'aiChatDrawer.send' | translate">
<lucide-icon [img]="Send" [size]="16"></lucide-icon>
</button>
</form>
</section>
</aside>