v4: the playlist and dump edit forms end in one bar of actions, a panel of its own — the playlist editor drew rules between its fields and its actions, and on a phone its Delete, Cancel and Save wrapped into a staircase, then stacked (a0c8b1d), neither of which held together. Both forms are now built as DumpEdit was: surface panels 3px apart (.form-panel, from .dump-edit-panel), the last a bar (.form-panel--bar, from .dump-edit-footer) holding Delete on the left and Cancel and Save on the right, compact (btn-sm), on one line. The new DeleteButton says "Delete" and names what goes to assistive tech ("Delete playlist", "Delete dump"); in a bar too narrow for the three labels in every face and language (a container query, under 18rem), it shows 🗑 instead. While edited, the playlist's header drops its own card for the form's panels. The phone stacking rule is gone. An auto-sized editor also re-fits when its width changes with its text unchanged: opening the form makes the page tall enough for a scrollbar, which narrowed the description after it was measured, so it overflowed; and it hides its overflow below its max-height, where a scrollbar could only come of rounding, and drops the resize grip, which the next keystroke would undo. 669 frontend tests pass, and tsc, eslint, deno fmt, doc:lint and i18n:compile --strict are clean; checked in screenshots in Kanagawa dark (French, 385 and 360px), Smooth light at 1000px and DumpEdit in Smooth at 390px.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -47,6 +47,7 @@ import { SubmitButton } from "../components/form/SubmitButton.tsx";
|
||||
import { TextField } from "../components/form/TextField.tsx";
|
||||
import { useApiForm } from "../hooks/form/useApiForm.ts";
|
||||
import { VisibilityToggle } from "../components/form/SegmentedField.tsx";
|
||||
import { DeleteButton } from "../components/form/DeleteButton.tsx";
|
||||
import { SlugField } from "../components/form/SlugField.tsx";
|
||||
import { useCanonicalPath } from "../hooks/shared/useCanonicalPath.ts";
|
||||
import { userPath } from "../../shared/paths.ts";
|
||||
@@ -446,7 +447,7 @@ function DumpEditForm({
|
||||
/* The source panel holds what was dumped, the details panel how it
|
||||
is presented and who sees it. */
|
||||
}
|
||||
<div className="dump-edit-panel dump-edit-panel--source">
|
||||
<div className="form-panel dump-edit-panel--source">
|
||||
{preview}
|
||||
|
||||
<div className="form-field">
|
||||
@@ -507,7 +508,7 @@ function DumpEditForm({
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="dump-edit-panel dump-edit-panel--details">
|
||||
<div className="form-panel dump-edit-panel--details">
|
||||
<FormError title={t`Could not save`} />
|
||||
|
||||
<TextField<EditValues>
|
||||
@@ -553,23 +554,17 @@ function DumpEditForm({
|
||||
<VisibilityToggle<EditValues> name="isPublic" />
|
||||
</div>
|
||||
|
||||
<div className="dump-edit-footer">
|
||||
<div className="form-panel form-panel--bar">
|
||||
{deleteError && (
|
||||
<ErrorCard title={t`Could not delete`} message={deleteError} />
|
||||
)}
|
||||
<div className="form-actions">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onRequestDelete}
|
||||
className="btn-danger"
|
||||
>
|
||||
<Trans>Delete dump</Trans>
|
||||
</button>
|
||||
<DeleteButton label={t`Delete dump`} onClick={onRequestDelete} />
|
||||
<div className="form-actions-right">
|
||||
<Link to={dumpUrl(dump)} className="form-cancel">
|
||||
<Trans>Cancel</Trans>
|
||||
</Link>
|
||||
<SubmitButton>
|
||||
<SubmitButton className="btn-primary btn-sm">
|
||||
<Trans>Save</Trans>
|
||||
</SubmitButton>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user