1import { Show } from "solid-js";2import { isNativePlatform } from "../../shared/native";34export type ToolbarExec = (cmd: string, val?: string) => void;56const BoldIcon = () => (7 <svg viewBox="0 0 14 14" aria-hidden="true">8 <path d="M4 2h3.75a2.5 2.5 0 0 1 0 5H4V2Zm0 5h4.25a2.5 2.5 0 0 1 0 5H4V7Z" />9 </svg>10);1112const ItalicIcon = () => (13 <svg viewBox="0 0 14 14" aria-hidden="true">14 <path d="M6 2h5M3 12h5M8.5 2l-3 10" />15 </svg>16);1718const UnderlineIcon = () => (19 <svg viewBox="0 0 14 14" aria-hidden="true">20 <path d="M3.5 2v4.25a3.5 3.5 0 0 0 7 0V2M2.5 12h9" />21 </svg>22);2324const StrikeIcon = () => (25 <svg viewBox="0 0 14 14" aria-hidden="true">26 <path d="M10.5 3.25C9.75 2.4 8.65 2 7.2 2 5.35 2 4 2.8 4 4.2c0 1.2.95 1.75 2.55 2.15M3.5 10.5c.85 1 2.1 1.5 3.75 1.5 1.9 0 3.25-.8 3.25-2.2 0-1.15-.9-1.75-2.45-2.15M2 7h10" />27 </svg>28);2930const HeadingIcon = () => (31 <svg viewBox="0 0 14 14" aria-hidden="true">32 <path d="M2 2.5v9M8 2.5v9M2 7h6M10 9.25c.25-.6.7-.9 1.35-.9.8 0 1.3.45 1.3 1.1 0 .55-.35.95-1.2 1.55L10.2 12h2.65" />33 </svg>34);3536const QuoteIcon = () => (37 <svg viewBox="0 0 14 14" aria-hidden="true">38 <path d="M2.25 4.25h3v3h-2c0 1.4.55 2.45 1.65 3.15M8.25 4.25h3v3h-2c0 1.4.55 2.45 1.65 3.15" />39 </svg>40);4142const BulletIcon = () => (43 <svg viewBox="0 0 14 14" aria-hidden="true">44 <path d="M5 3h7M5 7h7M5 11h7" />45 <circle cx="2" cy="3" r=".75" />46 <circle cx="2" cy="7" r=".75" />47 <circle cx="2" cy="11" r=".75" />48 </svg>49);5051const NumberedIcon = () => (52 <svg viewBox="0 0 14 14" aria-hidden="true">53 <path d="M5 3h7M5 7h7M5 11h7M1.25 2.25h.8V4M1.2 6.15c.2-.35.5-.55.95-.55.55 0 .9.3.9.75 0 .4-.25.65-.8 1.05l-1 .7h1.9M1.2 10.15c.25-.3.55-.45.95-.45.55 0 .9.25.9.65 0 .35-.25.6-.7.65.5.05.8.3.8.7 0 .45-.4.75-1 .75-.45 0-.8-.15-1.05-.45" />54 </svg>55);5657const RuleIcon = () => (58 <svg viewBox="0 0 14 14" aria-hidden="true">59 <path d="M1.5 7h11" />60 </svg>61);6263function applyBold(exec: ToolbarExec) { exec("bold"); }64function applyItalic(exec: ToolbarExec) { exec("italic"); }65function applyUnderline(exec: ToolbarExec) { exec("underline"); }66function applyStrike(exec: ToolbarExec) { exec("strikeThrough"); }67function applyHeading(exec: ToolbarExec) {68 const val = document.queryCommandValue("formatBlock").toLowerCase();69 exec("formatBlock", val === "h2" ? "p" : "h2");70}71function applyQuote(exec: ToolbarExec) {72 const val = document.queryCommandValue("formatBlock").toLowerCase();73 exec("formatBlock", val === "blockquote" ? "p" : "blockquote");74}75function applyBullet(exec: ToolbarExec) { exec("insertUnorderedList"); }76function applyNumbered(exec: ToolbarExec) { exec("insertOrderedList"); }77function applyRule(exec: ToolbarExec) { exec("insertHorizontalRule"); }7879interface ToolbarProps {80 exec: ToolbarExec;81 keyboardVisible?: boolean;82 onDismissKeyboard?: () => void;83 class?: string;84}8586export function NoteToolbar(props: ToolbarProps) {87 return (88 <Show89 when={isNativePlatform()}90 fallback={91 92 <div class={props.class ?? "peach-note-toolbar-desktop-inline"}>93 <button class="peach-note-toolbar-btn" onMouseDown={(e) => { e.preventDefault(); applyBold(props.exec); }} title="Bold" aria-label="Bold"><BoldIcon /></button>94 <button class="peach-note-toolbar-btn" onMouseDown={(e) => { e.preventDefault(); applyItalic(props.exec); }} title="Italic" aria-label="Italic"><ItalicIcon /></button>95 <button class="peach-note-toolbar-btn" onMouseDown={(e) => { e.preventDefault(); applyUnderline(props.exec); }} title="Underline" aria-label="Underline"><UnderlineIcon /></button>96 <button class="peach-note-toolbar-btn" onMouseDown={(e) => { e.preventDefault(); applyStrike(props.exec); }} title="Strikethrough" aria-label="Strikethrough"><StrikeIcon /></button>97 <div class="peach-note-toolbar-divider" />98 <button class="peach-note-toolbar-btn" onMouseDown={(e) => { e.preventDefault(); applyHeading(props.exec); }} title="Heading" aria-label="Heading"><HeadingIcon /></button>99 <button class="peach-note-toolbar-btn" onMouseDown={(e) => { e.preventDefault(); applyQuote(props.exec); }} title="Quote" aria-label="Quote"><QuoteIcon /></button>100 <button class="peach-note-toolbar-btn" onMouseDown={(e) => { e.preventDefault(); applyBullet(props.exec); }} title="Bullet list" aria-label="Bullet list"><BulletIcon /></button>101 <button class="peach-note-toolbar-btn" onMouseDown={(e) => { e.preventDefault(); applyNumbered(props.exec); }} title="Numbered list" aria-label="Numbered list"><NumberedIcon /></button>102 <button class="peach-note-toolbar-btn" onMouseDown={(e) => { e.preventDefault(); applyRule(props.exec); }} title="Divider" aria-label="Divider"><RuleIcon /></button>103 </div>104 }105 >106 {}107 <Show when={props.keyboardVisible}>108 <div class={props.class ?? "peach-note-toolbar-mobile"}>109 <button class="peach-note-toolbar-btn" onPointerDown={(e) => { e.preventDefault(); applyBold(props.exec); }} aria-label="Bold"><BoldIcon /></button>110 <button class="peach-note-toolbar-btn" onPointerDown={(e) => { e.preventDefault(); applyItalic(props.exec); }} aria-label="Italic"><ItalicIcon /></button>111 <button class="peach-note-toolbar-btn" onPointerDown={(e) => { e.preventDefault(); applyUnderline(props.exec); }} aria-label="Underline"><UnderlineIcon /></button>112 <button class="peach-note-toolbar-btn" onPointerDown={(e) => { e.preventDefault(); applyStrike(props.exec); }} aria-label="Strikethrough"><StrikeIcon /></button>113 <div class="peach-note-toolbar-divider" />114 <button class="peach-note-toolbar-btn" onPointerDown={(e) => { e.preventDefault(); applyHeading(props.exec); }} aria-label="Heading"><HeadingIcon /></button>115 <button class="peach-note-toolbar-btn" onPointerDown={(e) => { e.preventDefault(); applyQuote(props.exec); }} aria-label="Quote"><QuoteIcon /></button>116 <button class="peach-note-toolbar-btn" onPointerDown={(e) => { e.preventDefault(); applyBullet(props.exec); }} aria-label="Bullet list"><BulletIcon /></button>117 <button class="peach-note-toolbar-btn" onPointerDown={(e) => { e.preventDefault(); applyNumbered(props.exec); }} aria-label="Numbered list"><NumberedIcon /></button>118 <button class="peach-note-toolbar-btn" onPointerDown={(e) => { e.preventDefault(); applyRule(props.exec); }} aria-label="Divider"><RuleIcon /></button>119 <div class="peach-note-toolbar-spacer" />120 <button class="peach-note-toolbar-btn" onPointerDown={(e) => { e.preventDefault(); props.onDismissKeyboard?.(); }} aria-label="Dismiss keyboard">121 <svg viewBox="0 0 14 14" aria-hidden="true"><path d="M1.5 3h11v7h-11V3ZM3 5h.01M5 5h.01M7 5h.01M9 5h.01M11 5h.01M3 7h.01M5 7h.01M7 7h.01M9 7h2M4 9h6M5 12l2 1.5L9 12" /></svg>122 </button>123 </div>124 </Show>125 </Show>126 );127}