feat(design): surface phase PR 3 — Chat surface polish
Per the surface-phase spec for the Chat cluster (ChatView, ChatPanel, ChatMessage, ChatInputBar, ToolCallCard): Long-form line-height - ChatMessage: assistant-bubble .message-content jumps from 1.55 to 1.7 — chat is a reading surface, not a snippet stream. User bubbles stay tighter. - JournalView: dropped its :deep(.role-assistant .message-content) override; ChatMessage handles it now and Journal inherits. ToolCallCard borders - Removed the outer 1px border. ToolCallCard always renders inside an assistant bubble; the bubble already contains it. Background tint differentiates without re-bordering. Per the structural-not-decorative rule. - Error state preserved as a 3px left-edge accent in --color-danger, mirroring the assistant bubble's own left-edge pattern. Button reclassification per Hybrid rule - ChatView .bulk-link "All"/"None": accent text → --color-text-secondary (these are tertiary list-control affordances, not brand moments) - ChatView .bulk-delete-btn: --color-danger (Error terracotta) → --color-action-destructive (Oxblood) per Hybrid; paired with a Trash2 icon since destructive should always be reinforced by an icon, not just color - ChatView .btn-delete-conv hover: same Error → Oxblood swap - .btn-new-conv stays accent (brand moment, correct already) - .btn-send stays accent gradient (primary brand moment, foundation) Two-weights-only - Snapped every font-weight: 600/700 to 500 across ChatView, ChatPanel, ChatMessage, ToolCallCard per the doc rule. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@ import { useRoute, useRouter } from "vue-router";
|
||||
import { useChatStore } from "@/stores/chat";
|
||||
import { apiGet } from "@/api/client";
|
||||
import ChatPanel from "@/components/ChatPanel.vue";
|
||||
import { MoreVertical, Menu, Paperclip } from "lucide-vue-next";
|
||||
import { MoreVertical, Menu, Paperclip, Trash2 } from "lucide-vue-next";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
@@ -338,6 +338,7 @@ onUnmounted(() => {
|
||||
:disabled="bulkDeleting"
|
||||
@click="bulkDelete"
|
||||
>
|
||||
<Trash2 :size="16" />
|
||||
{{ bulkDeleting ? '...' : bulkConfirm ? `Delete ${selectedIds.size}?` : `Delete (${selectedIds.size})` }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -545,22 +546,29 @@ onUnmounted(() => {
|
||||
|
||||
.bulk-count { font-size: 0.75rem; color: var(--color-text-muted); flex-shrink: 0; }
|
||||
.bulk-link {
|
||||
background: none; border: none; color: var(--color-primary);
|
||||
background: none; border: none; color: var(--color-text-secondary);
|
||||
font-size: 0.75rem; cursor: pointer; padding: 0; text-decoration: underline;
|
||||
}
|
||||
.bulk-link:hover { color: var(--color-text); }
|
||||
|
||||
/* Destructive action — Oxblood per Hybrid rule, paired with Trash2 icon */
|
||||
.bulk-delete-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
margin-left: auto;
|
||||
background: none;
|
||||
border: 1px solid var(--color-danger, #e74c3c);
|
||||
color: var(--color-danger, #e74c3c);
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--color-action-destructive);
|
||||
color: var(--color-action-destructive);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
font-weight: 500;
|
||||
padding: 0.2rem 0.55rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.bulk-delete-btn:hover:not(:disabled) { background: var(--color-action-destructive); color: #fff; }
|
||||
.bulk-delete-btn:disabled { opacity: 0.5; cursor: default; }
|
||||
.bulk-delete-btn.confirm { background: var(--color-danger, #e74c3c); color: #fff; }
|
||||
.bulk-delete-btn.confirm { background: var(--color-action-destructive-hover); color: #fff; border-color: var(--color-action-destructive-hover); }
|
||||
|
||||
.conv-checkbox {
|
||||
flex-shrink: 0;
|
||||
@@ -580,7 +588,7 @@ onUnmounted(() => {
|
||||
}
|
||||
.conv-group-label {
|
||||
font-size: 0.68rem;
|
||||
font-weight: 700;
|
||||
font-weight: 500;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
color: var(--color-text-muted);
|
||||
@@ -614,7 +622,7 @@ onUnmounted(() => {
|
||||
background: none; border: none; color: var(--color-text-muted);
|
||||
cursor: pointer; font-size: 1.2rem; padding: 0 0.25rem; line-height: 1;
|
||||
}
|
||||
.btn-delete-conv:hover { color: var(--color-danger, #e74c3c); }
|
||||
.btn-delete-conv:hover { color: var(--color-action-destructive); }
|
||||
|
||||
.chat-main {
|
||||
flex: 1;
|
||||
@@ -721,7 +729,7 @@ onUnmounted(() => {
|
||||
cursor: pointer;
|
||||
}
|
||||
.scope-option:hover { background: var(--color-bg-secondary); }
|
||||
.scope-option.active { color: var(--color-primary); font-weight: 600; }
|
||||
.scope-option.active { color: var(--color-primary); font-weight: 500; }
|
||||
|
||||
/* Context toggle button (header) */
|
||||
.btn-context-toggle {
|
||||
@@ -748,7 +756,7 @@ onUnmounted(() => {
|
||||
.context-icon { font-size: 0.85rem; line-height: 1; }
|
||||
.context-count-badge {
|
||||
font-size: 0.65rem;
|
||||
font-weight: 700;
|
||||
font-weight: 500;
|
||||
background: var(--color-bg);
|
||||
padding: 0.05rem 0.35rem;
|
||||
border-radius: 8px;
|
||||
|
||||
@@ -389,12 +389,6 @@ onMounted(async () => {
|
||||
|
||||
.journal-chat-panel { flex: 1; min-height: 0; }
|
||||
|
||||
/* Long-form reading line-height for journal assistant bubbles
|
||||
(the daily prep is prose, not chat snippets — wants the doc's 1.7) */
|
||||
.journal-chat-panel :deep(.role-assistant .message-content) {
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
/* ── Right column ─────────────────────────────────────────────────────────── */
|
||||
.journal-right {
|
||||
grid-column: 2;
|
||||
|
||||
Reference in New Issue
Block a user