fd0858
feat: expanded note toolbar (U, S, H, lists, rule) + 250px editor body (v1.4.55)
- time
- 2026-04-23 13:49 UTC · 6 months ago
- machine
- koh2
- parent
- fb33e4
↓ peach-browser-fd0858.tar.gzatlas at this save
files changed5 files
manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/popup/styles/popup.css+39 −13src/popup/views/NoteEditor.tsx+56 −20manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach",4- "version": "1.4.54",4+ "version": "1.4.55",55 "description": "Zero-knowledge password manager",66 "browser_specific_settings": {77 "gecko": {manifest.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach",4- "version": "1.4.54",4+ "version": "1.4.55",55 "description": "Zero-knowledge password manager",66 "action": {77 "default_popup": "src/popup/index.html",package.json+1 −1
@@ -1,6 +1,6 @@11 {22 "name": "peach",3- "version": "1.4.54",3+ "version": "1.4.55",44 "description": "Zero-knowledge password manager",55 "type": "module",66 "scripts": {src/popup/styles/popup.css+39 −13
@@ -2324,17 +2324,12 @@23242324 border-color: var(--peach-t3);23252325 }23262326 2327-.peach-note-tool-bold {2328- font-weight: 700;2329- font-family: Inter, system-ui, sans-serif;2330- font-size: 11px;2327+.peach-note-tool-icon {2328+ padding: 3px 7px;2329+ display: inline-flex;2330+ align-items: center;2331+ justify-content: center;23312332 }2332-.peach-note-tool-italic {2333- font-style: italic;2334- font-family: "Cormorant Garamond", serif;2335- font-size: 14px;2336- padding: 1px 7px;2337-}23382333 23392334 .peach-note-tool-divider {23402335 width: 1px;@@ -2375,11 +2370,42 @@23752370 padding: 5px 10px 4px;23762371 }23772372 .peach-note-editor-body--inline {2378- min-height: 140px;2379- max-height: 200px;2373+ min-height: 250px;23802374 font-size: 15px;2381- padding: 10px 14px 12px;2375+ padding: 10px 14px 14px;23822376 background: var(--peach-t4);2377+}2378+2379+/* Rich content element styles (editor + display) */2380+.peach-note-editor-body h2,2381+.peach-note-content h2 {2382+ font-family: "Cormorant Garamond", serif;2383+ font-size: 20px;2384+ font-weight: 600;2385+ font-style: italic;2386+ color: var(--peach-t0);2387+ margin: 6px 0 2px;2388+ line-height: 1.3;2389+}2390+.peach-note-editor-body ul,2391+.peach-note-content ul {2392+ padding-left: 18px;2393+ margin: 3px 0;2394+ list-style: disc;2395+}2396+.peach-note-editor-body ol,2397+.peach-note-content ol {2398+ padding-left: 18px;2399+ margin: 3px 0;2400+ list-style: decimal;2401+}2402+.peach-note-editor-body li,2403+.peach-note-content li { margin: 2px 0; }2404+.peach-note-editor-body hr,2405+.peach-note-content hr {2406+ border: none;2407+ border-top: 1px solid var(--peach-t3);2408+ margin: 10px 0;23832409 }23842410 23852411 /* font size elements from execCommand */src/popup/views/NoteEditor.tsx+56 −20
@@ -9,31 +9,67 @@99 .replace(/\n/g, "<br>");1010 }1111 12-function Toolbar(props: { exec: (cmd: string, val?: string) => void }) {12+const BoldIcon = () => <span style="font-family:Inter,system-ui,sans-serif;font-weight:700;font-size:11px;">B</span>;13+const ItalicIcon = () => <span style="font-family:'Cormorant Garamond',serif;font-style:italic;font-size:13px;">I</span>;14+const UnderlineIcon = () => <span style="text-decoration:underline;font-size:10px;font-family:'IBM Plex Mono',monospace;">U</span>;15+const StrikeIcon = () => <span style="text-decoration:line-through;font-size:10px;font-family:'IBM Plex Mono',monospace;">S</span>;16+const HeadingIcon = () => <span style="font-family:Inter,system-ui,sans-serif;font-weight:600;font-size:10px;letter-spacing:0.03em;">H</span>;17+18+const BulletIcon = () => (19+ <svg width="12" height="11" viewBox="0 0 12 11" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round">20+ <circle cx="1.5" cy="2.5" r="1" fill="currentColor" stroke="none"/>21+ <line x1="4" y1="2.5" x2="11" y2="2.5"/>22+ <circle cx="1.5" cy="6" r="1" fill="currentColor" stroke="none"/>23+ <line x1="4" y1="6" x2="11" y2="6"/>24+ <circle cx="1.5" cy="9.5" r="1" fill="currentColor" stroke="none"/>25+ <line x1="4" y1="9.5" x2="11" y2="9.5"/>26+ </svg>27+);28+29+const NumberedIcon = () => (30+ <svg width="12" height="11" viewBox="0 0 12 11" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round">31+ <text x="0" y="4" font-size="4" fill="currentColor" stroke="none" font-family="monospace">1.</text>32+ <line x1="4" y1="2.5" x2="11" y2="2.5"/>33+ <text x="0" y="7.5" font-size="4" fill="currentColor" stroke="none" font-family="monospace">2.</text>34+ <line x1="4" y1="6" x2="11" y2="6"/>35+ <text x="0" y="11" font-size="4" fill="currentColor" stroke="none" font-family="monospace">3.</text>36+ <line x1="4" y1="9.5" x2="11" y2="9.5"/>37+ </svg>38+);39+40+const RuleIcon = () => (41+ <svg width="12" height="8" viewBox="0 0 12 8" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round">42+ <line x1="0" y1="4" x2="12" y2="4"/>43+ <line x1="2" y1="1.5" x2="2" y2="6.5" stroke-width="0.6" opacity="0.5"/>44+ <line x1="10" y1="1.5" x2="10" y2="6.5" stroke-width="0.6" opacity="0.5"/>45+ </svg>46+);47+48+type ExecFn = (cmd: string, val?: string) => void;49+50+function Toolbar(props: { exec: ExecFn }) {1351 const e = props.exec;52+ function toggleHeading() {53+ const val = document.queryCommandValue("formatBlock").toLowerCase();54+ e("formatBlock", val === "h2" ? "p" : "h2");55+ }1456 return (1557 <div class="peach-note-toolbar">16- <button class="peach-note-tool-btn peach-note-tool-bold"17- onMouseDown={(ev) => { ev.preventDefault(); e("bold"); }}18- title="Bold (⌘B)">B</button>19- <button class="peach-note-tool-btn peach-note-tool-italic"20- onMouseDown={(ev) => { ev.preventDefault(); e("italic"); }}21- title="Italic (⌘I)">I</button>58+ <button class="peach-note-tool-btn" onMouseDown={(ev) => { ev.preventDefault(); e("bold"); }} title="Bold (⌘B)"><BoldIcon /></button>59+ <button class="peach-note-tool-btn" onMouseDown={(ev) => { ev.preventDefault(); e("italic"); }} title="Italic (⌘I)"><ItalicIcon /></button>60+ <button class="peach-note-tool-btn" onMouseDown={(ev) => { ev.preventDefault(); e("underline"); }} title="Underline (⌘U)"><UnderlineIcon /></button>61+ <button class="peach-note-tool-btn" onMouseDown={(ev) => { ev.preventDefault(); e("strikeThrough"); }} title="Strikethrough"><StrikeIcon /></button>2262 <div class="peach-note-tool-divider" />23- <button class="peach-note-tool-btn"24- onMouseDown={(ev) => { ev.preventDefault(); e("fontSize", "1"); }}25- title="Small">sm</button>26- <button class="peach-note-tool-btn"27- onMouseDown={(ev) => { ev.preventDefault(); e("fontSize", "3"); }}28- title="Normal">md</button>29- <button class="peach-note-tool-btn"30- onMouseDown={(ev) => { ev.preventDefault(); e("fontSize", "5"); }}31- title="Large">lg</button>63+ <button class="peach-note-tool-btn" onMouseDown={(ev) => { ev.preventDefault(); toggleHeading(); }} title="Heading"><HeadingIcon /></button>64+ <button class="peach-note-tool-btn peach-note-tool-icon" onMouseDown={(ev) => { ev.preventDefault(); e("insertUnorderedList"); }} title="Bullet list"><BulletIcon /></button>65+ <button class="peach-note-tool-btn peach-note-tool-icon" onMouseDown={(ev) => { ev.preventDefault(); e("insertOrderedList"); }} title="Numbered list"><NumberedIcon /></button>66+ <div class="peach-note-tool-divider" />67+ <button class="peach-note-tool-btn peach-note-tool-icon" onMouseDown={(ev) => { ev.preventDefault(); e("insertHorizontalRule"); }} title="Divider"><RuleIcon /></button>3268 </div>3369 );3470 }3571 36-/* ── Full-popup overlay editor (Entry.tsx — editing existing notes) ── */72+/* ── Full-popup overlay editor (Entry.tsx) ── */3773 3874 interface NoteEditorProps {3975 initialContent: string;@@ -68,6 +104,7 @@68104 const mod = e.metaKey || e.ctrlKey;69105 if (mod && e.key === "b") { e.preventDefault(); exec("bold"); return; }70106 if (mod && e.key === "i") { e.preventDefault(); exec("italic"); return; }107+ if (mod && e.key === "u") { e.preventDefault(); exec("underline"); return; }71108 if (e.key === "Escape") { e.preventDefault(); props.onCancel(); }72109 }73110 @@ -88,9 +125,7 @@88125 {props.saving ? "saving…" : "save"}89126 </button>90127 </div>91-92128 <Toolbar exec={exec} />93-94129 <div ref={editorRef} class="peach-note-editor-body"95130 contenteditable="true" onKeyDown={handleKeyDown}96131 aria-multiline="true" aria-label="Note content" />@@ -98,7 +133,7 @@98133 );99134 }100135 101-/* ── Inline editor (Add.tsx — embedded in the new-entry form) ── */136+/* ── Inline editor (Add.tsx) ── */102137 103138 interface NoteEditorInlineProps {104139 initialContent: string;@@ -123,6 +158,7 @@123158 const mod = e.metaKey || e.ctrlKey;124159 if (mod && e.key === "b") { e.preventDefault(); exec("bold"); }125160 if (mod && e.key === "i") { e.preventDefault(); exec("italic"); }161+ if (mod && e.key === "u") { e.preventDefault(); exec("underline"); }126162 }127163 128164 return (