Polish: draft autosave, history refresh, outdated footer, more

Bug fixes / UX

- Footer: the privacy line still claimed 'generation runs in your
  browser'. Now correctly says the generation runs on the server and
  the key never reaches the browser.

- History panel: when the panel was open while a new generation
  completed, the new entry didn't appear until the user closed and
  re-opened the panel. The history module now dispatches a custom
  'melodymuse-history-updated' event on every write; the panel
  listens and re-reads. removeFromHistory/clearHistory emit too.
  writeAll is also now try/catch'd against quota errors.

- Auto-save the input form: the input is persisted to localStorage
  ('melodymuse-draft', debounced 400ms) so a refresh doesn't wipe
  what the user was typing. The initial state hydrates from the
  draft on mount.

- Cmd/Ctrl+Enter now works in the Music style field as well as
  the idea field — shared onKeyDown handler, propagated through the
  StyleField sub-component.

- Full regen ('Generate' / 'Regenerate All') now clears the previous
  assets before kicking off the new request, so the skeleton state
  shows during the round-trip instead of stale cards with a spinner
  on top. Per-section regen still leaves the other cards intact.

- Settings → Local data: the in-progress draft is now listed
  alongside history and theme, and has its own 'Clear in-progress
  draft' button. The 'Clear all local data' button clears it too.
This commit is contained in:
2026-06-03 08:59:31 +02:00
parent 1f82825849
commit 3096669a13
6 changed files with 137 additions and 34 deletions
+11 -1
View File
@@ -228,6 +228,7 @@ export function InputPanel({
loading={styleLoading}
onChange={(v) => set("style_hint", v)}
onRandom={handleStyleRandom}
onCmdEnter={onKeyDown}
/>
<div>
@@ -324,7 +325,15 @@ interface StyleFieldProps {
onRandom: (mode: "normal" | "crazy") => void;
}
function StyleField({ value, loading, onChange, onRandom }: StyleFieldProps) {
function StyleField({
value,
loading,
onChange,
onRandom,
onCmdEnter,
}: StyleFieldProps & {
onCmdEnter: (e: KeyboardEvent<HTMLTextAreaElement>) => void;
}) {
return (
<div>
<label
@@ -340,6 +349,7 @@ function StyleField({ value, loading, onChange, onRandom }: StyleFieldProps) {
placeholder="e.g. dark synthwave, analog pads, 110 BPM"
value={value}
onChange={(e) => onChange(e.target.value)}
onKeyDown={onCmdEnter}
className="textarea text-sm"
/>
<div className="mt-2 grid grid-cols-2 gap-2">