feat(ux): dogfood pass — onboarding, tasks, LLM chip, float popout
Bundles a session of dogfood UX feedback plus the two Cursor Bugbot
findings on the auto-titles branch.
Onboarding (FirstRunPage):
- Welcome leads with "Set up automatically"; system breakdown and the
full model list move behind a "Choose manually" disclosure
- Morning / evening / autostart modal copy trimmed to one short
sentence each; CTAs shortened
- "Corbie" autostart string reverted to "Kon"
- Already-downloaded models are clickable in the picker so the
Settings → About → Replay onboarding flow doesn't re-download
- Autostart "No thanks" now does isEnabled() → disable() to actually
remove the OS login item when replaying after a previous "Yes"
Tasks page:
- Bucket nav (All / Inbox / Today / Soon / Later) now a horizontal
pill row; was stacking because nav was block-level
- List sidebar sized to content via self-start max-h-full instead of
stretching to viewport when sparse
- Energy chip surfaces at opacity-60 when unset (was opacity-0,
hidden until hover) so the affordance is discoverable
- "Brain-Dead" energy label → "Zero" everywhere user-facing; enum
stays brain_dead to avoid a destructive DB migration
LLM status chip (llmStatus.svelte.ts + Dictation/Settings):
- Chip no longer auto-warms when the engine isn't loaded; it's hidden
unless ready / generating / loading / error
- refreshLlmStatus takes { force: true } so post-load reconcile clears
stale "warming"; ambient refreshes still preserve in-flight state
- markError exported; failed loads surface "AI error" with detail
rather than silently going to off
- check_llm_model is the source of truth (replaces the bool-only
get_llm_status path in the store)
Float popout window:
- Native decorations off — was stacking two titlebars + two close X's
on KWin, one of which silently failed
- ResizeHandles mounted outside the animate-float-enter wrapper so
fixed-position handles anchor to the viewport, not the transformed
root; secondary-windows capability gains
core:window:allow-start-resize-dragging for tasks-float
- GTK Utility WindowTypeHint applied pre-map (mirroring the preview
window) so KWin Wayland honours always-on-top reliably
- visible_on_all_workspaces(true) so the pinned tasks list follows
workspace switches
- togglePin does hide()+show()+focus() on re-pin to nudge the
compositor into re-evaluating window state
- Pop-out / Edit / Open viewer buttons hidden on Android via
isAndroid() — the multi-window Tauri commands stub out there
Build / Bugbot:
- src-tauri Cargo.toml: whisper feature now chains whisper-vulkan, so
the dev runner's --no-default-features --features whisper
invocation actually pulls Vulkan acceleration instead of silently
falling back to CPU-only
- jsconfig.json's inherited "types": ["node"] fixed by adding
@types/node; corresponding @ts-expect-error in vite.config.js
removed now that process is a known global
Verification: svelte-check + cargo check pass clean. Manual
device-side validation still pending for float resize and replay
autostart "No thanks" — those are the only remaining confidence items.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { tick } from "svelte";
|
||||
import type { EnergyLevel, TaskBucket, TaskEntry, TaskList } from "$lib/types/app";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { isAndroid } from "$lib/utils/runtime.js";
|
||||
import {
|
||||
tasks, addTask, completeTask, uncompleteTask, deleteTask, updateTask,
|
||||
setTaskEnergy,
|
||||
@@ -107,7 +108,7 @@
|
||||
switch (level) {
|
||||
case "high": return "High";
|
||||
case "medium": return "Medium";
|
||||
case "brain_dead": return "Brain-Dead";
|
||||
case "brain_dead": return "Zero";
|
||||
default: return "Not set";
|
||||
}
|
||||
}
|
||||
@@ -123,7 +124,7 @@
|
||||
{ value: null, label: "—" },
|
||||
{ value: "high", label: "High" },
|
||||
{ value: "medium", label: "Med" },
|
||||
{ value: "brain_dead", label: "Low" },
|
||||
{ value: "brain_dead", label: "Zero" },
|
||||
];
|
||||
let energyRadioGroupEl = $state<HTMLDivElement | null>(null);
|
||||
|
||||
@@ -359,15 +360,20 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="flex items-center gap-1.5 btn-md rounded-lg text-text-secondary hover:bg-hover hover:text-text"
|
||||
style="transition-duration: var(--duration-ui)"
|
||||
onclick={popOutTasks}
|
||||
aria-label="Pop out task window"
|
||||
>
|
||||
<ExternalLink size={14} aria-hidden="true" />
|
||||
Pop out
|
||||
</button>
|
||||
{#if !isAndroid()}
|
||||
<!-- Multi-window pop-out is desktop-only — the Tauri Android stub
|
||||
for open_task_window returns an error, so the button would just
|
||||
surface a toast on a mobile build. Hide it instead. -->
|
||||
<button
|
||||
class="flex items-center gap-1.5 btn-md rounded-lg text-text-secondary hover:bg-hover hover:text-text"
|
||||
style="transition-duration: var(--duration-ui)"
|
||||
onclick={popOutTasks}
|
||||
aria-label="Pop out task window"
|
||||
>
|
||||
<ExternalLink size={14} aria-hidden="true" />
|
||||
Pop out
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Search -->
|
||||
@@ -410,7 +416,12 @@
|
||||
|
||||
<!-- Bucket tabs + sort -->
|
||||
<div class="flex items-center gap-1 px-7 pb-3">
|
||||
<nav aria-label="Task filters">
|
||||
<!-- Bucket tabs render as a horizontal pill row. The nav element is
|
||||
block-level by default, which previously made its button children
|
||||
stack vertically — the outer flex container only governs siblings,
|
||||
not children of the nav. Adding flex/gap here puts the tabs
|
||||
side-by-side as intended. -->
|
||||
<nav aria-label="Task filters" class="flex items-center gap-1 flex-wrap">
|
||||
{#each buckets as bucket}
|
||||
<button
|
||||
class="flex items-center gap-1.5 btn-md rounded-lg
|
||||
@@ -457,10 +468,15 @@
|
||||
</div>
|
||||
|
||||
<!-- Main content: sidebar + tasks -->
|
||||
<div class="flex flex-1 min-h-0 px-7 pb-4 gap-3">
|
||||
<!-- List sidebar -->
|
||||
<div class="flex flex-1 min-h-0 px-7 pb-4 gap-3 items-start">
|
||||
<!-- List sidebar — `self-start` + `max-h-full` so the panel sizes to
|
||||
its content rather than stretching to the full task-area height.
|
||||
A nearly-empty list with three items used to draw a column that
|
||||
ran the full height of the window even though it had nothing in
|
||||
it; this keeps the surface honest. The inner items list keeps
|
||||
its scroll affordance for users with many lists. -->
|
||||
<div
|
||||
class="flex flex-col bg-bg-elevated rounded-2xl border border-border-subtle overflow-hidden
|
||||
class="flex flex-col bg-bg-elevated rounded-2xl border border-border-subtle overflow-hidden self-start max-h-full
|
||||
{sidebarCollapsed ? 'w-[40px] min-w-[40px]' : 'w-[160px] min-w-[160px]'}"
|
||||
style="transition: width var(--duration-ui)"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user