feat: project dropdown in sidebar, resizable AI sidebar with snap, ctx & t/s telemetry, live line-number re-anchoring, and thinking indicator

This commit is contained in:
Schwitzz
2026-10-30 11:53:32 -05:00
parent b1c22229c5
commit 271d1e2c79
6 changed files with 617 additions and 78 deletions
+19
View File
@@ -328,6 +328,25 @@ export class AIStore {
});
}
/** Update a suggestion's line number or text anchor when editor blocks shift. */
async updateSuggestion(
sessionId: string,
suggestionId: string,
patch: Partial<Pick<AISuggestion, "lineNumber" | "originalText" | "newText" | "text">>,
): Promise<AISession> {
return this.withTransaction(async () => {
const session = this.require(sessionId);
const suggestion = session.suggestions.find((s) => s.id === suggestionId);
if (!suggestion) return this.clone(session);
if (patch.lineNumber !== undefined) suggestion.lineNumber = patch.lineNumber;
if (patch.originalText !== undefined) suggestion.originalText = patch.originalText;
if (patch.newText !== undefined) suggestion.newText = patch.newText;
if (patch.text !== undefined) suggestion.text = patch.text;
session.updatedAt = nowIso();
return this.clone(session);
});
}
/** Add a note to a session and persist it. */
async addNote(sessionId: string, note: Omit<AINote, "id" | "createdAt" | "updatedAt">): Promise<AISession> {
return this.withTransaction(async () => {
+158 -1
View File
@@ -184,6 +184,47 @@ body {
width: 100%;
}
/* Sidebar Project Switcher Dropdown */
.ps-sidebar-project-box {
display: flex;
flex-direction: column;
gap: 4px;
padding: 6px 8px;
background: var(--ps-surface-2);
border: 1px solid var(--ps-border);
border-radius: 8px;
}
.ps-sidebar-project-row {
display: flex;
align-items: center;
gap: 6px;
}
.ps-sidebar-project-select {
flex: 1;
min-width: 0;
padding: 5px 8px !important;
font-size: 13px !important;
font-weight: 600;
background: var(--ps-surface) !important;
}
.ps-sidebar-project-meta {
font-size: 11.5px;
color: var(--ps-text-muted);
padding-left: 26px;
}
.ps-project-switcher-collapsed {
position: relative;
overflow: hidden;
}
.ps-project-switcher-native-overlay {
position: absolute;
inset: 0;
opacity: 0;
width: 100%;
height: 100%;
cursor: pointer;
}
.ps-topbar {
grid-area: topbar;
display: flex;
@@ -648,8 +689,9 @@ body {
flex-shrink: 0;
}
/* ---- AI Sidebar (Toggleable Right Rail) ---- */
/* ---- AI Sidebar (Toggleable & Resizable Right Rail) ---- */
.ps-ai-sidebar {
position: relative;
width: 370px;
flex-shrink: 0;
height: 100%;
@@ -660,6 +702,28 @@ body {
font-family: var(--ps-font-ui);
overflow: hidden;
}
.ps-ai-sidebar.is-resizing {
user-select: none;
}
.ps-ai-resize-handle {
position: absolute;
top: 0;
bottom: 0;
left: -3px;
width: 7px;
cursor: col-resize;
z-index: 25;
background: transparent;
transition: background 0.15s ease;
}
.ps-ai-resize-handle:hover,
.ps-ai-sidebar.is-resizing .ps-ai-resize-handle {
background: color-mix(in srgb, var(--ps-accent) 55%, transparent);
}
.ps-ai-sidebar.is-resizing .ps-ai-resize-handle.is-snapped {
background: var(--ps-success);
box-shadow: 0 0 8px var(--ps-success);
}
.ps-ai-fullpage {
width: 100%;
max-width: 900px;
@@ -909,6 +973,99 @@ body {
flex-wrap: wrap;
}
/* AI Thinking Indicator */
.ps-ai-thinking {
display: flex;
flex-direction: column;
gap: 6px;
padding: 10px 12px;
border-radius: 10px;
background: color-mix(in srgb, var(--ps-accent) 10%, var(--ps-surface-2));
border: 1px dashed color-mix(in srgb, var(--ps-accent) 55%, var(--ps-border));
font-size: 12.5px;
}
.ps-ai-thinking-head {
display: flex;
align-items: center;
gap: 8px;
color: var(--ps-accent);
}
.ps-ai-thinking-timer {
margin-left: auto;
font-family: var(--ps-font-mono);
font-size: 11px;
color: var(--ps-text-muted);
}
.ps-ai-thinking-stage {
font-size: 12px;
color: var(--ps-text);
}
.ps-ai-thinking-trace {
font-size: 11.5px;
font-style: italic;
color: var(--ps-text-muted);
border-left: 2px solid var(--ps-border);
padding-left: 8px;
}
.ps-ai-thinking-dots {
display: inline-flex;
align-items: center;
gap: 3px;
}
.ps-ai-thinking-dots > span {
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--ps-accent);
animation: ps-thinking-bounce 1.2s infinite ease-in-out both;
}
.ps-ai-thinking-dots > span:nth-child(1) { animation-delay: -0.24s; }
.ps-ai-thinking-dots > span:nth-child(2) { animation-delay: -0.12s; }
@keyframes ps-thinking-bounce {
0%, 80%, 100% { transform: scale(0.45); opacity: 0.4; }
40% { transform: scale(1); opacity: 1; }
}
/* Non-intrusive AI Telemetry Bar (Context & t/s) */
.ps-ai-telemetry-bar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
padding: 5px 12px;
border-top: 1px solid var(--ps-border);
background: var(--ps-surface-2);
font-family: var(--ps-font-mono);
font-size: 11px;
color: var(--ps-text-muted);
flex-shrink: 0;
}
.ps-ai-telemetry-ctx {
display: inline-flex;
align-items: center;
gap: 6px;
min-width: 0;
}
.ps-ai-telemetry-meter {
width: 44px;
height: 4px;
border-radius: 999px;
background: var(--ps-border);
overflow: hidden;
display: inline-block;
}
.ps-ai-telemetry-meter-fill {
display: block;
height: 100%;
background: var(--ps-accent);
border-radius: 999px;
transition: width 0.2s ease;
}
.ps-ai-telemetry-speed {
white-space: nowrap;
font-variant-numeric: tabular-nums;
}
/* ---- Projects Page & Template Wizard ---- */
.ps-projects-grid {
display: grid;