Add note context visibility in chat and standardize UI design tokens
Improve chat context: build_context() now returns metadata about auto-found notes, emitted as an SSE event so the frontend can display context pills showing which notes influenced the response. Users can promote notes for deeper context (+) or exclude irrelevant ones (x). A note picker lets users manually attach notes. Multi-word search uses per-term AND matching, and auto-search iterates keywords individually for broader OR-style coverage. Standardize styling: introduce CSS design tokens (--radius-sm/md/lg/pill, --color-success/warning/overlay, --focus-ring) and migrate all components to use them. Fix header alignment to full-width, add active nav link state, replace hardcoded colors with CSS variables, and normalize button padding. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,12 @@ const emit = defineEmits<{
|
||||
|
||||
const rendered = computed(() => renderMarkdown(props.message.content));
|
||||
|
||||
const formattedTime = computed(() => {
|
||||
if (!props.message.created_at) return "";
|
||||
const date = new Date(props.message.created_at);
|
||||
return date.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" });
|
||||
});
|
||||
|
||||
const roleLabel = computed(() => {
|
||||
switch (props.message.role) {
|
||||
case "user":
|
||||
@@ -31,24 +37,27 @@ const roleLabel = computed(() => {
|
||||
|
||||
<template>
|
||||
<div class="chat-message" :class="`role-${message.role}`">
|
||||
<div class="message-bubble">
|
||||
<div class="message-header">
|
||||
<span class="role-label">{{ roleLabel }}</span>
|
||||
<div class="message-actions" v-if="message.role === 'assistant' && !isStreaming">
|
||||
<button class="btn-save" @click="emit('saveAsNote', message.id)" title="Save as note">
|
||||
Save as Note
|
||||
</button>
|
||||
<div class="message-group">
|
||||
<div class="message-bubble">
|
||||
<div class="message-header">
|
||||
<span class="role-label">{{ roleLabel }}</span>
|
||||
<div class="message-actions" v-if="message.role === 'assistant' && !isStreaming">
|
||||
<button class="btn-save" @click="emit('saveAsNote', message.id)" title="Save as note">
|
||||
Save as Note
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="message-content prose" v-html="rendered"></div>
|
||||
<div
|
||||
v-if="message.context_note_id"
|
||||
class="context-badge"
|
||||
>
|
||||
<router-link :to="`/notes/${message.context_note_id}`">
|
||||
Note #{{ message.context_note_id }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="message-content prose" v-html="rendered"></div>
|
||||
<div
|
||||
v-if="message.context_note_id"
|
||||
class="context-badge"
|
||||
>
|
||||
<router-link :to="`/notes/${message.context_note_id}`">
|
||||
Note #{{ message.context_note_id }}
|
||||
</router-link>
|
||||
</div>
|
||||
<span v-if="formattedTime" class="message-timestamp">{{ formattedTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -65,8 +74,11 @@ const roleLabel = computed(() => {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.message-bubble {
|
||||
.message-group {
|
||||
max-width: 80%;
|
||||
}
|
||||
|
||||
.message-bubble {
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: 16px;
|
||||
}
|
||||
@@ -136,7 +148,7 @@ const roleLabel = computed(() => {
|
||||
padding: 0.1rem 0.4rem;
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 4px;
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--color-text-secondary);
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -159,4 +171,12 @@ const roleLabel = computed(() => {
|
||||
.context-badge a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.message-timestamp {
|
||||
display: block;
|
||||
font-size: 0.7rem;
|
||||
color: var(--color-text-muted);
|
||||
margin-top: 0.15rem;
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user