forked from mirror/crumbs-original
style: collapse formatting toolbar into single line with More dropdown on mobile
Reorganize toolbar: inline formatting (bold/italic/strike/underline) as primary buttons, move blockquote/code/alignment/HR into a "More" dropdown. Use overflow-x-auto instead of flex-wrap for single-line scrollable toolbar. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
9c10dd2679
commit
2df5353d0b
@@ -109,7 +109,7 @@
|
||||
<svelte:document onpointerdown={handlePointerDown} onkeydown={handleKeydown} />
|
||||
|
||||
<div
|
||||
class="flex flex-wrap items-center gap-0.5 border-b border-[var(--border-subtle)] px-2 py-1"
|
||||
class="flex items-center gap-0.5 overflow-x-auto border-b border-[var(--border-subtle)] px-2 py-1"
|
||||
data-testid="formatting-toolbar"
|
||||
>
|
||||
<!-- History -->
|
||||
@@ -132,7 +132,43 @@
|
||||
<Redo2 size={iconSize} />
|
||||
</button>
|
||||
|
||||
<div class="mx-1 h-4 w-px bg-[var(--border-subtle)]"></div>
|
||||
<div class="mx-1 h-4 w-px shrink-0 bg-[var(--border-subtle)]"></div>
|
||||
|
||||
<!-- Inline -->
|
||||
<button
|
||||
onclick={() => editor?.chain().focus().toggleBold().run()}
|
||||
class={btnClass(editor?.isActive('bold') ?? false)}
|
||||
title="Bold (Ctrl+B)"
|
||||
data-testid="format-bold"
|
||||
>
|
||||
<Bold size={iconSize} />
|
||||
</button>
|
||||
<button
|
||||
onclick={() => editor?.chain().focus().toggleItalic().run()}
|
||||
class={btnClass(editor?.isActive('italic') ?? false)}
|
||||
title="Italic (Ctrl+I)"
|
||||
data-testid="format-italic"
|
||||
>
|
||||
<Italic size={iconSize} />
|
||||
</button>
|
||||
<button
|
||||
onclick={() => editor?.chain().focus().toggleStrike().run()}
|
||||
class={btnClass(editor?.isActive('strike') ?? false)}
|
||||
title="Strikethrough (Ctrl+Shift+X)"
|
||||
data-testid="format-strikethrough"
|
||||
>
|
||||
<Strikethrough size={iconSize} />
|
||||
</button>
|
||||
<button
|
||||
onclick={() => editor?.chain().focus().toggleUnderline().run()}
|
||||
class={btnClass(editor?.isActive('underline') ?? false)}
|
||||
title="Underline (Ctrl+U)"
|
||||
data-testid="format-underline"
|
||||
>
|
||||
<Underline size={iconSize} />
|
||||
</button>
|
||||
|
||||
<div class="mx-1 h-4 w-px shrink-0 bg-[var(--border-subtle)]"></div>
|
||||
|
||||
<!-- Heading dropdown -->
|
||||
<div class="relative" data-dropdown="heading">
|
||||
@@ -208,67 +244,6 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<button
|
||||
onclick={() => editor?.chain().focus().toggleBlockquote().run()}
|
||||
class={btnClass(editor?.isActive('blockquote') ?? false)}
|
||||
title="Blockquote"
|
||||
data-testid="format-blockquote"
|
||||
>
|
||||
<TextQuote size={iconSize} />
|
||||
</button>
|
||||
<button
|
||||
onclick={() => editor?.chain().focus().toggleCodeBlock().run()}
|
||||
class={btnClass(editor?.isActive('codeBlock') ?? false)}
|
||||
title="Code block"
|
||||
data-testid="format-code-block"
|
||||
>
|
||||
<CodeXml size={iconSize} />
|
||||
</button>
|
||||
|
||||
<div class="mx-1 h-4 w-px bg-[var(--border-subtle)]"></div>
|
||||
|
||||
<!-- Inline -->
|
||||
<button
|
||||
onclick={() => editor?.chain().focus().toggleBold().run()}
|
||||
class={btnClass(editor?.isActive('bold') ?? false)}
|
||||
title="Bold (Ctrl+B)"
|
||||
data-testid="format-bold"
|
||||
>
|
||||
<Bold size={iconSize} />
|
||||
</button>
|
||||
<button
|
||||
onclick={() => editor?.chain().focus().toggleItalic().run()}
|
||||
class={btnClass(editor?.isActive('italic') ?? false)}
|
||||
title="Italic (Ctrl+I)"
|
||||
data-testid="format-italic"
|
||||
>
|
||||
<Italic size={iconSize} />
|
||||
</button>
|
||||
<button
|
||||
onclick={() => editor?.chain().focus().toggleStrike().run()}
|
||||
class={btnClass(editor?.isActive('strike') ?? false)}
|
||||
title="Strikethrough (Ctrl+Shift+X)"
|
||||
data-testid="format-strikethrough"
|
||||
>
|
||||
<Strikethrough size={iconSize} />
|
||||
</button>
|
||||
<button
|
||||
onclick={() => editor?.chain().focus().toggleCode().run()}
|
||||
class={btnClass(editor?.isActive('code') ?? false)}
|
||||
title="Inline code (Ctrl+E)"
|
||||
data-testid="format-code"
|
||||
>
|
||||
<Code size={iconSize} />
|
||||
</button>
|
||||
<button
|
||||
onclick={() => editor?.chain().focus().toggleUnderline().run()}
|
||||
class={btnClass(editor?.isActive('underline') ?? false)}
|
||||
title="Underline (Ctrl+U)"
|
||||
data-testid="format-underline"
|
||||
>
|
||||
<Underline size={iconSize} />
|
||||
</button>
|
||||
|
||||
<!-- Link popover -->
|
||||
<div class="relative" data-dropdown="link">
|
||||
<button
|
||||
@@ -327,28 +302,61 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="mx-1 h-4 w-px bg-[var(--border-subtle)]"></div>
|
||||
<div class="mx-1 h-4 w-px shrink-0 bg-[var(--border-subtle)]"></div>
|
||||
|
||||
<!-- Align dropdown -->
|
||||
<div class="relative" data-dropdown="align">
|
||||
<!-- More dropdown -->
|
||||
<div class="relative" data-dropdown="more">
|
||||
<button
|
||||
onclick={() => toggleDropdown('align')}
|
||||
class={dropdownBtnClass(editor?.isActive({ textAlign: 'center' }) || editor?.isActive({ textAlign: 'right' }) || editor?.isActive({ textAlign: 'justify' }) ? true : false)}
|
||||
title="Text alignment"
|
||||
data-testid="format-align"
|
||||
onclick={() => toggleDropdown('more')}
|
||||
class={dropdownBtnClass(false)}
|
||||
title="More options"
|
||||
data-testid="format-more"
|
||||
>
|
||||
<AlignLeft size={iconSize} />
|
||||
<Minus size={iconSize} />
|
||||
<ChevronDown size={chevronSize} />
|
||||
</button>
|
||||
{#if openDropdown === 'align'}
|
||||
<div class="absolute left-0 top-full z-50 mt-1 min-w-[150px] rounded-sm border border-[var(--border)] bg-[var(--bg-surface)] py-1">
|
||||
{#if openDropdown === 'more'}
|
||||
<div class="absolute right-0 top-full z-50 mt-1 min-w-[170px] rounded-sm border border-[var(--border)] bg-[var(--bg-surface)] py-1">
|
||||
<button
|
||||
onclick={() => { editor?.chain().focus().toggleCode().run(); closeDropdowns(); }}
|
||||
class={dropdownItemClass(editor?.isActive('code') ?? false)}
|
||||
data-testid="format-code"
|
||||
>
|
||||
<Code size={iconSize} />
|
||||
<span>Inline code</span>
|
||||
</button>
|
||||
<button
|
||||
onclick={() => { editor?.chain().focus().toggleBlockquote().run(); closeDropdowns(); }}
|
||||
class={dropdownItemClass(editor?.isActive('blockquote') ?? false)}
|
||||
data-testid="format-blockquote"
|
||||
>
|
||||
<TextQuote size={iconSize} />
|
||||
<span>Blockquote</span>
|
||||
</button>
|
||||
<button
|
||||
onclick={() => { editor?.chain().focus().toggleCodeBlock().run(); closeDropdowns(); }}
|
||||
class={dropdownItemClass(editor?.isActive('codeBlock') ?? false)}
|
||||
data-testid="format-code-block"
|
||||
>
|
||||
<CodeXml size={iconSize} />
|
||||
<span>Code block</span>
|
||||
</button>
|
||||
<button
|
||||
onclick={() => { editor?.chain().focus().setHorizontalRule().run(); closeDropdowns(); }}
|
||||
class={dropdownItemClass()}
|
||||
data-testid="format-hr"
|
||||
>
|
||||
<Minus size={iconSize} />
|
||||
<span>Horizontal rule</span>
|
||||
</button>
|
||||
<div class="my-1 h-px bg-[var(--border-subtle)]"></div>
|
||||
<button
|
||||
onclick={() => { editor?.chain().focus().setTextAlign('left').run(); closeDropdowns(); }}
|
||||
class={dropdownItemClass(editor?.isActive({ textAlign: 'left' }) ?? false)}
|
||||
data-testid="format-align-left"
|
||||
>
|
||||
<AlignLeft size={iconSize} />
|
||||
<span>Left</span>
|
||||
<span>Align left</span>
|
||||
</button>
|
||||
<button
|
||||
onclick={() => { editor?.chain().focus().setTextAlign('center').run(); closeDropdowns(); }}
|
||||
@@ -356,7 +364,7 @@
|
||||
data-testid="format-align-center"
|
||||
>
|
||||
<AlignCenter size={iconSize} />
|
||||
<span>Center</span>
|
||||
<span>Align center</span>
|
||||
</button>
|
||||
<button
|
||||
onclick={() => { editor?.chain().focus().setTextAlign('right').run(); closeDropdowns(); }}
|
||||
@@ -364,7 +372,7 @@
|
||||
data-testid="format-align-right"
|
||||
>
|
||||
<AlignRight size={iconSize} />
|
||||
<span>Right</span>
|
||||
<span>Align right</span>
|
||||
</button>
|
||||
<button
|
||||
onclick={() => { editor?.chain().focus().setTextAlign('justify').run(); closeDropdowns(); }}
|
||||
@@ -377,16 +385,4 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="mx-1 h-4 w-px bg-[var(--border-subtle)]"></div>
|
||||
|
||||
<!-- Insert -->
|
||||
<button
|
||||
onclick={() => editor?.chain().focus().setHorizontalRule().run()}
|
||||
class={btnClass()}
|
||||
title="Horizontal rule"
|
||||
data-testid="format-hr"
|
||||
>
|
||||
<Minus size={iconSize} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
- [x] on mobile the colour selection overflows outside the screen
|
||||
- [x] let's use another icon for toggling the raw md mode, also the active state doesn't make on this icon now, either we change the icon when it's in one state or the other, or the button should be active when the md state is active
|
||||
- [x] same for the list icon, toggling between this mode is nice but the icon becomes inactive which is weird
|
||||
- [ ] on mobile the toolbar collapose on two lines, can we do something so it stays only on one line and we have a dropdown to open the additional options
|
||||
- [x] on mobile the toolbar collapose on two lines, can we do something so it stays only on one line and we have a dropdown to open the additional options
|
||||
- [ ] add this todo.md to gitignore and remove from git
|
||||
- [ ] close the menu by default on mobile
|
||||
- [ ] when note content is really long on mobile (maybe on desktop also I didn't check) it overflows out of view without scrolling
|
||||
|
||||
Reference in New Issue
Block a user