A chapter you can see, in the colour you chose
A chapter did not show until the notebook had a note in it. "Nothing here" was asked of the notes alone, so a notebook whose only contents were chapters showed the empty-list panel with the chapters hidden behind it — making a chapter in a fresh notebook appeared to do nothing at all. It is asked of every row now, and a notebook with chapters but no loose notes says so in one line rather than looking like a list that failed to load. The colour is chosen while the chapter is being made, in the dialog that asks for its name. It is what tells one chapter from the next, and having to right-click a fresh one to say which it is meant two visits for one decision. Renaming and recolouring afterwards are one entry in its menu and one write; the server already took the colour on create, the client simply never sent it. The word "here" is gone. The line along the top of the pane says which of the two places you are in, and saying it twice was noise. Thirteen suites green: 338 browser checks, 241 unit tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ebf1f1bc62
commit
165ccf3cf7
8 files changed
+197
-66
No files matched your search
@@ -10,9 +10,24 @@ import { useEffect, useMemo, useRef, useState } from "react";
|
||||
*
|
||||
* Deliberately small. Naming a chapter is one field and two buttons, and
|
||||
* anything more would be a form.
|
||||
*
|
||||
* The one exception is the colour, offered when `colors` is given: it belongs to
|
||||
* the same act. Making a chapter and then having to right-click it to say which
|
||||
* one it is meant two steps for one decision.
|
||||
*/
|
||||
export function NameDialog({ title, value = "", label = "Name", confirmLabel = "Save", onSave, onClose, dark }) {
|
||||
export function NameDialog({
|
||||
title,
|
||||
value = "",
|
||||
label = "Name",
|
||||
confirmLabel = "Save",
|
||||
colors,
|
||||
color: initialColor = null,
|
||||
onSave,
|
||||
onClose,
|
||||
dark,
|
||||
}) {
|
||||
const [name, setName] = useState(value);
|
||||
const [color, setColor] = useState(initialColor);
|
||||
const inputRef = useRef(null);
|
||||
|
||||
const T = useMemo(
|
||||
@@ -35,7 +50,7 @@ export function NameDialog({ title, value = "", label = "Name", confirmLabel = "
|
||||
const save = () => {
|
||||
const trimmed = name.trim();
|
||||
if (!trimmed) return;
|
||||
onSave(trimmed);
|
||||
onSave(trimmed, color);
|
||||
onClose();
|
||||
};
|
||||
|
||||
@@ -89,6 +104,42 @@ export function NameDialog({ title, value = "", label = "Name", confirmLabel = "
|
||||
boxSizing: "border-box",
|
||||
}}
|
||||
/>
|
||||
{colors?.length > 0 && (
|
||||
<div style={{ marginTop: 16 }}>
|
||||
<div style={{ fontSize: 11.5, color: T.muted, fontWeight: 600, marginBottom: 8 }}>Colour</div>
|
||||
<div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
|
||||
{[{ label: "None", value: null }, ...colors].map((c) => {
|
||||
const picked = (c.value ?? null) === (color ?? null);
|
||||
return (
|
||||
<button
|
||||
key={c.label}
|
||||
type="button"
|
||||
onClick={() => setColor(c.value ?? null)}
|
||||
title={c.label}
|
||||
aria-label={c.label}
|
||||
aria-pressed={picked}
|
||||
data-colour-option={c.value ?? "none"}
|
||||
style={{
|
||||
width: 28,
|
||||
height: 28,
|
||||
borderRadius: 9,
|
||||
cursor: "pointer",
|
||||
// The ring, not a tick: a tick over a dark swatch is
|
||||
// unreadable and over a light one it is the only thing seen.
|
||||
border: picked ? `2px solid ${T.text}` : `1px solid ${T.border}`,
|
||||
background: c.value ?? "transparent",
|
||||
color: T.muted,
|
||||
fontSize: 11,
|
||||
lineHeight: 1,
|
||||
}}
|
||||
>
|
||||
{c.value ? "" : "—"}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div style={{ display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 18 }}>
|
||||
<button
|
||||
onClick={onClose}
|
||||
|
||||
Reference in new issue
Block a user