fix: resolve Gitea issues #1–#5 (mobile layout, suggestion refresh, import/export icons, context rail default/icon, manual save)
CI / build (push) Waiting to run
CI / build (push) Waiting to run
Closes #1 Closes #2 Closes #3 Closes #4 Closes #5
This commit is contained in:
@@ -112,6 +112,11 @@ export class AIStore {
|
||||
if (this.loaded) return;
|
||||
const rows = await this.persistence.list(this.projectId);
|
||||
for (const row of rows) {
|
||||
const cleanedSuggestions = (row.suggestions ?? []).filter(
|
||||
(sg) =>
|
||||
!String(sg.newText ?? sg.text ?? "").includes("—clear and unsparing") &&
|
||||
!String(sg.newText ?? sg.text ?? "").includes("—sharp and unmistakable"),
|
||||
);
|
||||
this.sessions.set(row.id, {
|
||||
id: row.id,
|
||||
projectId: row.projectId,
|
||||
@@ -122,7 +127,7 @@ export class AIStore {
|
||||
providerId: row.providerId,
|
||||
model: row.model,
|
||||
messages: row.messages ?? [],
|
||||
suggestions: row.suggestions ?? [],
|
||||
suggestions: cleanedSuggestions,
|
||||
notes: row.notes ?? [],
|
||||
createdAt: row.createdAt,
|
||||
updatedAt: row.updatedAt,
|
||||
@@ -328,6 +333,16 @@ export class AIStore {
|
||||
});
|
||||
}
|
||||
|
||||
/** Clear all pending suggestions in a session before populating fresh suggestions from a new prompt. */
|
||||
async clearPendingSuggestions(sessionId: string): Promise<AISession> {
|
||||
return this.withTransaction(async () => {
|
||||
const session = this.require(sessionId);
|
||||
session.suggestions = session.suggestions.filter((s) => s.status !== "pending");
|
||||
session.updatedAt = nowIso();
|
||||
return this.clone(session);
|
||||
});
|
||||
}
|
||||
|
||||
/** Update a suggestion's line number or text anchor when editor blocks shift. */
|
||||
async updateSuggestion(
|
||||
sessionId: string,
|
||||
|
||||
@@ -1392,3 +1392,138 @@ body {
|
||||
|
||||
/* ---- Focus visible ---- */
|
||||
:focus-visible { outline: 2px solid var(--ps-accent); outline-offset: 2px; }
|
||||
|
||||
/* ---- Mobile Helpers (Hidden on Desktop by Default) ---- */
|
||||
.ps-mobile-nav-btn,
|
||||
.ps-mobile-nav-backdrop,
|
||||
.ps-mobile-rail-backdrop,
|
||||
.ps-mobile-ai-backdrop,
|
||||
.ps-mobile-ai-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ---- Mobile Friendly Layout (Issue #1) ---- */
|
||||
@media (max-width: 768px) {
|
||||
.ps-app,
|
||||
.ps-app.is-nav-collapsed {
|
||||
grid-template-columns: 1fr !important;
|
||||
grid-template-rows: var(--ps-topbar-h) 1fr !important;
|
||||
grid-template-areas:
|
||||
"topbar"
|
||||
"main" !important;
|
||||
width: 100vw;
|
||||
max-width: 100vw;
|
||||
height: 100dvh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ps-mobile-nav-btn {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
/* 1. Side panels hide completely when closed and dismiss when tapping outside */
|
||||
.ps-sidebar {
|
||||
display: none !important;
|
||||
}
|
||||
.ps-app.is-mobile-nav-open .ps-sidebar {
|
||||
display: flex !important;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: min(270px, 82vw) !important;
|
||||
z-index: 210;
|
||||
box-shadow: 12px 0 32px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
.ps-app.is-mobile-nav-open .ps-mobile-nav-backdrop {
|
||||
display: block;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.52);
|
||||
z-index: 205;
|
||||
}
|
||||
|
||||
/* Story Context Rail overlays on mobile and hides completely when tapping outside */
|
||||
.ps-context-rail {
|
||||
position: fixed !important;
|
||||
top: var(--ps-topbar-h);
|
||||
bottom: 44px;
|
||||
right: 0;
|
||||
width: min(300px, 86vw) !important;
|
||||
z-index: 210;
|
||||
box-shadow: -10px 0 28px rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
.ps-mobile-rail-backdrop {
|
||||
display: block;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.48);
|
||||
z-index: 205;
|
||||
}
|
||||
|
||||
/* 4. AI features docked at bottom of phone screen */
|
||||
.ps-ai-sidebar {
|
||||
position: fixed !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
bottom: 0 !important;
|
||||
top: auto !important;
|
||||
width: 100vw !important;
|
||||
height: 74dvh !important;
|
||||
border-left: none !important;
|
||||
border-top: 2px solid var(--ps-accent) !important;
|
||||
border-radius: 16px 16px 0 0;
|
||||
z-index: 220;
|
||||
box-shadow: 0 -12px 36px rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
.ps-ai-resize-handle {
|
||||
display: none !important;
|
||||
}
|
||||
.ps-mobile-ai-backdrop {
|
||||
display: block;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.48);
|
||||
z-index: 215;
|
||||
}
|
||||
|
||||
.ps-mobile-ai-bar {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 44px;
|
||||
padding: 5px 12px;
|
||||
background: var(--ps-surface);
|
||||
border-top: 1px solid var(--ps-border);
|
||||
z-index: 150;
|
||||
align-items: center;
|
||||
}
|
||||
.ps-mobile-ai-bar-btn {
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid color-mix(in srgb, var(--ps-accent) 55%, var(--ps-border));
|
||||
background: color-mix(in srgb, var(--ps-accent) 16%, var(--ps-surface-2));
|
||||
color: var(--ps-text);
|
||||
font-family: var(--ps-font-ui);
|
||||
font-size: 12.5px;
|
||||
font-weight: 600;
|
||||
padding: 0 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ps-topbar {
|
||||
padding: 0 10px;
|
||||
gap: 6px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.ps-topbar-search {
|
||||
max-width: 150px;
|
||||
min-width: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user