feat: add Toolbar component with active state and formatting buttons

This commit is contained in:
Steffen Becker committed 2026-05-25 20:43:04 +02:00
1 parent 9ffa1995a0
commit e8eee6ce3b
1 file changed
+135
+135
View File
@@ -0,0 +1,135 @@
<script lang="ts">
import type { Editor } from '@tiptap/core';
let { editor }: { editor: Editor | null } = $props();
</script>
<div class="toolbar">
{#if editor}
<div class="toolbar-group">
<button
class:active={editor.isActive('bold')}
onclick={() => editor?.chain().focus().toggleBold().run()}
title="Bold (Ctrl+B)"
>
<strong>B</strong>
</button>
<button
class:active={editor.isActive('italic')}
onclick={() => editor?.chain().focus().toggleItalic().run()}
title="Italic (Ctrl+I)"
>
<em>I</em>
</button>
<button
class:active={editor.isActive('underline')}
onclick={() => editor?.chain().focus().toggleUnderline().run()}
title="Underline (Ctrl+U)"
>
<u>U</u>
</button>
</div>
<div class="toolbar-separator"></div>
<div class="toolbar-group">
<button
class:active={editor.isActive('heading', { level: 1 })}
onclick={() => editor?.chain().focus().toggleHeading({ level: 1 }).run()}
title="Heading 1"
>
H1
</button>
<button
class:active={editor.isActive('heading', { level: 2 })}
onclick={() => editor?.chain().focus().toggleHeading({ level: 2 }).run()}
title="Heading 2"
>
H2
</button>
<button
class:active={editor.isActive('heading', { level: 3 })}
onclick={() => editor?.chain().focus().toggleHeading({ level: 3 }).run()}
title="Heading 3"
>
H3
</button>
</div>
<div class="toolbar-separator"></div>
<div class="toolbar-group">
<button
onclick={() => editor?.chain().focus().undo().run()}
disabled={!editor.can().undo()}
title="Undo (Ctrl+Z)"
>
↩
</button>
<button
onclick={() => editor?.chain().focus().redo().run()}
disabled={!editor.can().redo()}
title="Redo (Ctrl+Shift+Z)"
>
↪
</button>
</div>
{/if}
</div>
<style>
.toolbar {
display: flex;
align-items: center;
gap: 0.25rem;
padding: 0.5rem 1rem;
background: var(--color-toolbar-bg);
border-bottom: 1px solid var(--color-border);
position: sticky;
top: 0;
z-index: 10;
}
.toolbar-group {
display: flex;
gap: 2px;
}
.toolbar-separator {
width: 1px;
height: 1.5rem;
background: var(--color-border);
margin: 0 0.5rem;
}
button {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 2rem;
height: 2rem;
padding: 0 0.5rem;
border: none;
border-radius: var(--radius);
background: transparent;
color: var(--color-text);
font-size: 0.85rem;
font-family: var(--font-sans);
cursor: pointer;
transition: background 0.15s;
}
button:hover:not(:disabled) {
background: var(--color-bg);
}
button.active {
background: var(--color-primary);
color: white;
}
button:disabled {
opacity: 0.35;
cursor: not-allowed;
}
</style>