Workspace UI overhaul: rail note panel, split task detail, project goal header
- WorkspaceNoteEditor: replace toggling list/editor views with always-visible
left rail (155px) showing note list alongside editor pane; persist last-open
note per project in localStorage (workspace_note_{projectId})
- WorkspaceTaskPanel: add priority dot + due date on task rows; replace full
overlay detail with bottom-split (44% list / 56% detail); close button
replaces back nav; active row highlighted; fade transition
- WorkspaceView: show project goal in header instead of 'Workspace'; non-equal
panel widths (0.8fr / 1.1fr / 1.1fr); empty chat quick-action chips (Project
status / New note / Add tasks); prefill() helper
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,7 @@ const projectId = computed(() => Number(route.params.projectId));
|
||||
interface Project {
|
||||
id: number;
|
||||
title: string;
|
||||
goal?: string;
|
||||
}
|
||||
|
||||
const project = ref<Project | null>(null);
|
||||
@@ -56,12 +57,11 @@ function _loadPanelState(pid: number) {
|
||||
const panelOpen = ref({ tasks: true, chat: true, notes: true });
|
||||
|
||||
const gridColumns = computed(() => {
|
||||
const cols = [
|
||||
panelOpen.value.tasks ? "1fr" : "0px",
|
||||
panelOpen.value.chat ? "1fr" : "0px",
|
||||
panelOpen.value.notes ? "1fr" : "0px",
|
||||
];
|
||||
return cols.join(" ");
|
||||
return [
|
||||
panelOpen.value.tasks ? "minmax(0, 0.8fr)" : "0px",
|
||||
panelOpen.value.chat ? "minmax(0, 1.1fr)" : "0px",
|
||||
panelOpen.value.notes ? "minmax(0, 1.1fr)" : "0px",
|
||||
].join(" ");
|
||||
});
|
||||
|
||||
// SSE watcher
|
||||
@@ -124,6 +124,11 @@ function togglePanel(panel: keyof typeof panelOpen.value) {
|
||||
localStorage.setItem(_panelKey(projectId.value), JSON.stringify(panelOpen.value));
|
||||
}
|
||||
|
||||
function prefill(text: string) {
|
||||
messageInput.value = text;
|
||||
nextTick(() => inputEl.value?.focus());
|
||||
}
|
||||
|
||||
async function sendMessage() {
|
||||
const content = messageInput.value.trim();
|
||||
if (!content) return;
|
||||
@@ -230,7 +235,7 @@ onUnmounted(async () => {
|
||||
<router-link :to="project ? `/projects/${project.id}` : '/projects'" class="ws-back">
|
||||
← {{ project?.title ?? "Project" }}
|
||||
</router-link>
|
||||
<span class="ws-title">Workspace</span>
|
||||
<span class="ws-title">{{ project?.goal ?? '' }}</span>
|
||||
<div class="ws-panel-toggles">
|
||||
<button
|
||||
:class="['panel-toggle', { active: panelOpen.tasks }]"
|
||||
@@ -341,12 +346,17 @@ onUnmounted(async () => {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<p
|
||||
<div
|
||||
v-if="chatStore.currentConversation && !chatStore.currentConversation.messages.length && !chatStore.streaming"
|
||||
class="empty-chat-msg"
|
||||
class="empty-chat-prompt"
|
||||
>
|
||||
Ask the agent to create notes or tasks for this project.
|
||||
</p>
|
||||
<p class="empty-hint">What would you like to work on?</p>
|
||||
<div class="quick-chips">
|
||||
<button class="quick-chip" @click="prefill('Summarize the current status of this project')">📊 Project status</button>
|
||||
<button class="quick-chip" @click="prefill('Create a note about ')">📝 New note</button>
|
||||
<button class="quick-chip" @click="prefill('Add tasks for ')">✓ Add tasks</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chat-input-area">
|
||||
@@ -428,10 +438,13 @@ onUnmounted(async () => {
|
||||
}
|
||||
|
||||
.ws-title {
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
font-size: 0.78rem;
|
||||
color: var(--color-text-muted);
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.ws-panel-toggles {
|
||||
@@ -501,12 +514,37 @@ onUnmounted(async () => {
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.empty-chat-msg {
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.875rem;
|
||||
.empty-chat-prompt {
|
||||
text-align: center;
|
||||
padding: 2rem 1rem;
|
||||
}
|
||||
.empty-hint {
|
||||
margin: 0 0 1rem;
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.quick-chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
justify-content: center;
|
||||
}
|
||||
.quick-chip {
|
||||
background: var(--color-surface);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 20px;
|
||||
padding: 0.4rem 0.85rem;
|
||||
font-size: 0.82rem;
|
||||
color: var(--color-text-secondary);
|
||||
cursor: pointer;
|
||||
transition: border-color 0.15s, color 0.15s, background 0.15s;
|
||||
font-family: inherit;
|
||||
}
|
||||
.quick-chip:hover {
|
||||
border-color: var(--color-primary);
|
||||
color: var(--color-primary);
|
||||
background: color-mix(in srgb, var(--color-primary) 5%, var(--color-surface));
|
||||
}
|
||||
|
||||
.chat-input-area {
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user