@autumnsgrove/groveengine 0.6.4 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/index.d.ts +1 -2
- package/dist/auth/index.js +8 -4
- package/dist/auth/session.d.ts +14 -33
- package/dist/auth/session.js +5 -103
- package/dist/components/admin/FloatingToolbar.svelte +373 -0
- package/dist/components/admin/FloatingToolbar.svelte.d.ts +17 -0
- package/dist/components/admin/MarkdownEditor.svelte +26 -347
- package/dist/components/admin/MarkdownEditor.svelte.d.ts +1 -1
- package/dist/components/admin/composables/index.d.ts +0 -2
- package/dist/components/admin/composables/index.js +0 -2
- package/dist/components/custom/ContentWithGutter.svelte +22 -25
- package/dist/components/custom/MobileTOC.svelte +20 -13
- package/dist/components/quota/UpgradePrompt.svelte +1 -1
- package/dist/server/services/database.d.ts +138 -0
- package/dist/server/services/database.js +234 -0
- package/dist/server/services/index.d.ts +5 -1
- package/dist/server/services/index.js +24 -2
- package/dist/server/services/turnstile.d.ts +66 -0
- package/dist/server/services/turnstile.js +131 -0
- package/dist/server/services/users.d.ts +104 -0
- package/dist/server/services/users.js +158 -0
- package/dist/styles/README.md +50 -0
- package/dist/styles/vine-pattern.css +24 -0
- package/dist/types/turnstile.d.ts +42 -0
- package/dist/ui/components/forms/TurnstileWidget.svelte +111 -0
- package/dist/ui/components/forms/TurnstileWidget.svelte.d.ts +14 -0
- package/dist/ui/components/primitives/dialog/dialog-overlay.svelte +1 -1
- package/dist/ui/components/primitives/sheet/sheet-overlay.svelte +1 -1
- package/dist/ui/components/ui/Glass.svelte +158 -0
- package/dist/ui/components/ui/Glass.svelte.d.ts +52 -0
- package/dist/ui/components/ui/GlassButton.svelte +157 -0
- package/dist/ui/components/ui/GlassButton.svelte.d.ts +39 -0
- package/dist/ui/components/ui/GlassCard.svelte +160 -0
- package/dist/ui/components/ui/GlassCard.svelte.d.ts +39 -0
- package/dist/ui/components/ui/GlassConfirmDialog.svelte +208 -0
- package/dist/ui/components/ui/GlassConfirmDialog.svelte.d.ts +52 -0
- package/dist/ui/components/ui/GlassOverlay.svelte +93 -0
- package/dist/ui/components/ui/GlassOverlay.svelte.d.ts +33 -0
- package/dist/ui/components/ui/Logo.svelte +161 -23
- package/dist/ui/components/ui/Logo.svelte.d.ts +4 -10
- package/dist/ui/components/ui/index.d.ts +5 -0
- package/dist/ui/components/ui/index.js +6 -0
- package/dist/ui/styles/grove.css +136 -0
- package/dist/ui/tokens/fonts.d.ts +69 -0
- package/dist/ui/tokens/fonts.js +341 -0
- package/dist/ui/tokens/index.d.ts +6 -5
- package/dist/ui/tokens/index.js +7 -6
- package/dist/utils/gutter.d.ts +2 -8
- package/dist/utils/markdown.d.ts +1 -0
- package/dist/utils/markdown.js +32 -11
- package/package.json +1 -1
- package/static/robots.txt +520 -0
- package/dist/auth/jwt.d.ts +0 -20
- package/dist/auth/jwt.js +0 -123
- package/dist/components/admin/composables/useCommandPalette.svelte.d.ts +0 -87
- package/dist/components/admin/composables/useCommandPalette.svelte.js +0 -158
- package/dist/components/admin/composables/useSlashCommands.svelte.d.ts +0 -104
- package/dist/components/admin/composables/useSlashCommands.svelte.js +0 -215
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
import "../../styles/content.css";
|
|
6
6
|
import { Button, Input, Logo } from '../../ui';
|
|
7
7
|
import Dialog from "../../ui/components/ui/Dialog.svelte";
|
|
8
|
+
import FloatingToolbar from "./FloatingToolbar.svelte";
|
|
8
9
|
|
|
9
|
-
// Import composables
|
|
10
|
+
// Import composables (simplified - removed command palette and slash commands)
|
|
10
11
|
import {
|
|
11
12
|
useAmbientSounds,
|
|
12
13
|
soundLibrary,
|
|
@@ -15,8 +16,6 @@
|
|
|
15
16
|
useSnippets,
|
|
16
17
|
useDraftManager,
|
|
17
18
|
useWritingSession,
|
|
18
|
-
useSlashCommands,
|
|
19
|
-
useCommandPalette,
|
|
20
19
|
} from "./composables/index.js";
|
|
21
20
|
|
|
22
21
|
/**
|
|
@@ -46,7 +45,7 @@
|
|
|
46
45
|
let previewRef = $state(null);
|
|
47
46
|
/** @type {HTMLElement | null} */
|
|
48
47
|
let lineNumbersRef = $state(null);
|
|
49
|
-
let showPreview = $state(
|
|
48
|
+
let showPreview = $state(false); // Default to false for Medium-style focused writing
|
|
50
49
|
let cursorLine = $state(1);
|
|
51
50
|
let cursorCol = $state(1);
|
|
52
51
|
let isUpdating = $state(false);
|
|
@@ -91,38 +90,7 @@
|
|
|
91
90
|
readonly,
|
|
92
91
|
});
|
|
93
92
|
|
|
94
|
-
|
|
95
|
-
getTextareaRef: () => textareaRef,
|
|
96
|
-
getContent: () => content,
|
|
97
|
-
setContent: (/** @type {string} */ c) => (content = c),
|
|
98
|
-
getSnippets: () => snippetsManager.snippets,
|
|
99
|
-
onOpenSnippetsModal: () => snippetsManager.openModal(),
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
// Command palette actions
|
|
103
|
-
const basePaletteActions = [
|
|
104
|
-
{ id: "save", label: "Save", shortcut: "⌘S", action: () => onSave() },
|
|
105
|
-
{ id: "preview", label: "Toggle Preview", shortcut: "", action: () => (showPreview = !showPreview) },
|
|
106
|
-
{ id: "fullPreview", label: "Full Preview", shortcut: "", action: () => (showFullPreview = true) },
|
|
107
|
-
{ id: "zen", label: "Toggle Zen Mode", shortcut: "⌘⇧↵", action: () => toggleZenMode() },
|
|
108
|
-
{ id: "campfire", label: "Start Campfire Session", shortcut: "", action: () => writingSession.startCampfire() },
|
|
109
|
-
{ id: "bold", label: "Bold", shortcut: "⌘B", action: () => wrapSelection("**", "**") },
|
|
110
|
-
{ id: "italic", label: "Italic", shortcut: "⌘I", action: () => wrapSelection("_", "_") },
|
|
111
|
-
{ id: "code", label: "Insert Code Block", shortcut: "", action: () => insertCodeBlock() },
|
|
112
|
-
{ id: "link", label: "Insert Link", shortcut: "", action: () => insertLink() },
|
|
113
|
-
{ id: "image", label: "Insert Image", shortcut: "", action: () => insertImage() },
|
|
114
|
-
{ id: "goal", label: "Set Writing Goal", shortcut: "", action: () => writingSession.promptWritingGoal() },
|
|
115
|
-
{ id: "snippets", label: "Manage Snippets", shortcut: "", action: () => snippetsManager.openModal() },
|
|
116
|
-
{ id: "newSnippet", label: "Create New Snippet", shortcut: "", action: () => snippetsManager.openModal() },
|
|
117
|
-
{ id: "sounds", label: "Toggle Ambient Sounds", shortcut: "", action: () => ambientSounds.toggle() },
|
|
118
|
-
{ id: "soundPanel", label: "Sound Settings", shortcut: "", action: () => ambientSounds.togglePanel() },
|
|
119
|
-
];
|
|
120
|
-
|
|
121
|
-
const commandPalette = useCommandPalette({
|
|
122
|
-
getActions: () => basePaletteActions,
|
|
123
|
-
getThemes: () => themes,
|
|
124
|
-
getCurrentTheme: () => editorTheme.currentTheme,
|
|
125
|
-
});
|
|
93
|
+
// Note: Slash commands and command palette removed for simplified Medium-style UX
|
|
126
94
|
|
|
127
95
|
// Computed values
|
|
128
96
|
let wordCount = $derived(content.trim() ? content.trim().split(/\s+/).length : 0);
|
|
@@ -159,25 +127,6 @@
|
|
|
159
127
|
return anchors;
|
|
160
128
|
});
|
|
161
129
|
|
|
162
|
-
// Filtered commands for UI
|
|
163
|
-
let filteredSlashCommands = $derived.by(() => slashCommands.getFilteredCommands());
|
|
164
|
-
let filteredPaletteCommands = $derived.by(() => {
|
|
165
|
-
// Include theme actions that actually set the theme
|
|
166
|
-
const actions = basePaletteActions.filter((cmd) =>
|
|
167
|
-
cmd.label.toLowerCase().includes(commandPalette.query.toLowerCase())
|
|
168
|
-
);
|
|
169
|
-
const themeCommands = Object.entries(themes)
|
|
170
|
-
.filter(([key, theme]) =>
|
|
171
|
-
`Theme: ${theme.label} (${theme.desc})`.toLowerCase().includes(commandPalette.query.toLowerCase())
|
|
172
|
-
)
|
|
173
|
-
.map(([key, theme]) => ({
|
|
174
|
-
id: `theme-${key}`,
|
|
175
|
-
label: `Theme: ${theme.label} (${theme.desc})`,
|
|
176
|
-
shortcut: editorTheme.currentTheme === key ? "●" : "",
|
|
177
|
-
action: () => editorTheme.setTheme(key),
|
|
178
|
-
}));
|
|
179
|
-
return [...actions, ...themeCommands];
|
|
180
|
-
});
|
|
181
130
|
|
|
182
131
|
// Public exports
|
|
183
132
|
export function getAvailableAnchors() {
|
|
@@ -207,61 +156,17 @@
|
|
|
207
156
|
cursorCol = lines[lines.length - 1].length + 1;
|
|
208
157
|
}
|
|
209
158
|
|
|
210
|
-
// Keyboard handlers
|
|
159
|
+
// Keyboard handlers (simplified - removed slash commands and command palette)
|
|
211
160
|
/** @param {KeyboardEvent} e */
|
|
212
161
|
function handleKeydown(e) {
|
|
213
|
-
// Escape key handling
|
|
162
|
+
// Escape key handling - exit zen mode
|
|
214
163
|
if (e.key === "Escape") {
|
|
215
|
-
if (slashCommands.isOpen) {
|
|
216
|
-
slashCommands.close();
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
if (commandPalette.isOpen) {
|
|
220
|
-
commandPalette.close();
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
164
|
if (isZenMode) {
|
|
224
165
|
isZenMode = false;
|
|
225
166
|
return;
|
|
226
167
|
}
|
|
227
168
|
}
|
|
228
169
|
|
|
229
|
-
// Slash commands trigger
|
|
230
|
-
if (e.key === "/" && !slashCommands.isOpen && textareaRef) {
|
|
231
|
-
const pos = textareaRef.selectionStart;
|
|
232
|
-
// Only trigger at start of line or after whitespace
|
|
233
|
-
if (pos === 0 || /\s$/.test(content.substring(0, pos))) {
|
|
234
|
-
setTimeout(() => slashCommands.open(), 0);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Close slash menu on space or enter
|
|
239
|
-
if (slashCommands.isOpen && (e.key === " " || e.key === "Enter")) {
|
|
240
|
-
if (e.key === "Enter") {
|
|
241
|
-
e.preventDefault();
|
|
242
|
-
slashCommands.execute(slashCommands.menu.selectedIndex);
|
|
243
|
-
}
|
|
244
|
-
slashCommands.close();
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// Navigate slash menu
|
|
248
|
-
if (slashCommands.isOpen) {
|
|
249
|
-
if (e.key === "ArrowDown") {
|
|
250
|
-
e.preventDefault();
|
|
251
|
-
slashCommands.navigate("down");
|
|
252
|
-
}
|
|
253
|
-
if (e.key === "ArrowUp") {
|
|
254
|
-
e.preventDefault();
|
|
255
|
-
slashCommands.navigate("up");
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// Command palette: Cmd+K
|
|
260
|
-
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
|
|
261
|
-
e.preventDefault();
|
|
262
|
-
commandPalette.toggle();
|
|
263
|
-
}
|
|
264
|
-
|
|
265
170
|
// Zen mode: Cmd+Shift+Enter
|
|
266
171
|
if (e.key === "Enter" && (e.metaKey || e.ctrlKey) && e.shiftKey) {
|
|
267
172
|
e.preventDefault();
|
|
@@ -558,16 +463,6 @@
|
|
|
558
463
|
}
|
|
559
464
|
}
|
|
560
465
|
|
|
561
|
-
// Command palette execution
|
|
562
|
-
/** @param {number} index */
|
|
563
|
-
function executePaletteCommand(index) {
|
|
564
|
-
const cmd = filteredPaletteCommands[index];
|
|
565
|
-
if (cmd && cmd.action) {
|
|
566
|
-
cmd.action();
|
|
567
|
-
commandPalette.close();
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
|
|
571
466
|
onMount(() => {
|
|
572
467
|
updateCursorPosition();
|
|
573
468
|
snippetsManager.load();
|
|
@@ -642,57 +537,10 @@
|
|
|
642
537
|
</div>
|
|
643
538
|
{/if}
|
|
644
539
|
|
|
645
|
-
<!-- Toolbar -->
|
|
540
|
+
<!-- Minimal Toolbar (Medium-style - formatting via floating toolbar on selection) -->
|
|
646
541
|
<div class="toolbar">
|
|
647
|
-
<div class="toolbar-
|
|
648
|
-
<
|
|
649
|
-
[h<span class="key">1</span>]
|
|
650
|
-
</button>
|
|
651
|
-
<button type="button" class="toolbar-btn" onclick={() => insertHeading(2)} title="Heading 2" disabled={readonly}>
|
|
652
|
-
[h<span class="key">2</span>]
|
|
653
|
-
</button>
|
|
654
|
-
<button type="button" class="toolbar-btn" onclick={() => insertHeading(3)} title="Heading 3" disabled={readonly}>
|
|
655
|
-
[h<span class="key">3</span>]
|
|
656
|
-
</button>
|
|
657
|
-
</div>
|
|
658
|
-
|
|
659
|
-
<div class="toolbar-divider">|</div>
|
|
660
|
-
|
|
661
|
-
<div class="toolbar-group">
|
|
662
|
-
<button type="button" class="toolbar-btn" onclick={() => wrapSelection("**", "**")} title="Bold (Cmd+B)" disabled={readonly}>
|
|
663
|
-
[<span class="key">b</span>old]
|
|
664
|
-
</button>
|
|
665
|
-
<button type="button" class="toolbar-btn" onclick={() => wrapSelection("_", "_")} title="Italic (Cmd+I)" disabled={readonly}>
|
|
666
|
-
[<span class="key">i</span>talic]
|
|
667
|
-
</button>
|
|
668
|
-
<button type="button" class="toolbar-btn" onclick={() => wrapSelection("`", "`")} title="Inline Code" disabled={readonly}>
|
|
669
|
-
[<span class="key">c</span>ode]
|
|
670
|
-
</button>
|
|
671
|
-
</div>
|
|
672
|
-
|
|
673
|
-
<div class="toolbar-divider">|</div>
|
|
674
|
-
|
|
675
|
-
<div class="toolbar-group">
|
|
676
|
-
<button type="button" class="toolbar-btn" onclick={insertLink} title="Link" disabled={readonly}>
|
|
677
|
-
[<span class="key">l</span>ink]
|
|
678
|
-
</button>
|
|
679
|
-
<button type="button" class="toolbar-btn" onclick={insertImage} title="Image" disabled={readonly}>
|
|
680
|
-
[i<span class="key">m</span>g]
|
|
681
|
-
</button>
|
|
682
|
-
<button type="button" class="toolbar-btn" onclick={insertCodeBlock} title="Code Block" disabled={readonly}>
|
|
683
|
-
[bloc<span class="key">k</span>]
|
|
684
|
-
</button>
|
|
685
|
-
</div>
|
|
686
|
-
|
|
687
|
-
<div class="toolbar-divider">|</div>
|
|
688
|
-
|
|
689
|
-
<div class="toolbar-group">
|
|
690
|
-
<button type="button" class="toolbar-btn" onclick={insertList} title="List" disabled={readonly}>
|
|
691
|
-
[lis<span class="key">t</span>]
|
|
692
|
-
</button>
|
|
693
|
-
<button type="button" class="toolbar-btn" onclick={insertQuote} title="Quote" disabled={readonly}>
|
|
694
|
-
[<span class="key">q</span>uote]
|
|
695
|
-
</button>
|
|
542
|
+
<div class="toolbar-left">
|
|
543
|
+
<span class="toolbar-hint">Select text to format</span>
|
|
696
544
|
</div>
|
|
697
545
|
|
|
698
546
|
<div class="toolbar-spacer"></div>
|
|
@@ -812,74 +660,13 @@
|
|
|
812
660
|
</div>
|
|
813
661
|
</div>
|
|
814
662
|
|
|
815
|
-
<!--
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
class="slash-menu-item"
|
|
823
|
-
class:selected={i === slashCommands.menu.selectedIndex}
|
|
824
|
-
onclick={() => slashCommands.execute(i)}
|
|
825
|
-
>
|
|
826
|
-
<span class="slash-cmd-label">{cmd.label}</span>
|
|
827
|
-
</button>
|
|
828
|
-
{/each}
|
|
829
|
-
{#if filteredSlashCommands.length === 0}
|
|
830
|
-
<div class="slash-menu-empty">; no commands found</div>
|
|
831
|
-
{/if}
|
|
832
|
-
</div>
|
|
833
|
-
{/if}
|
|
834
|
-
|
|
835
|
-
<!-- Command Palette -->
|
|
836
|
-
{#if commandPalette.isOpen}
|
|
837
|
-
<!-- svelte-ignore a11y_no_static_element_interactions a11y_click_events_have_key_events -->
|
|
838
|
-
<div class="command-palette-overlay" onclick={() => commandPalette.close()} role="dialog" aria-modal="true" aria-label="Command palette">
|
|
839
|
-
<!-- svelte-ignore a11y_no_static_element_interactions a11y_click_events_have_key_events -->
|
|
840
|
-
<div class="command-palette" onclick={(e) => e.stopPropagation()}>
|
|
841
|
-
<input
|
|
842
|
-
type="text"
|
|
843
|
-
class="command-palette-input"
|
|
844
|
-
placeholder="> type a command..."
|
|
845
|
-
value={commandPalette.query}
|
|
846
|
-
oninput={(e) => commandPalette.setQuery(/** @type {HTMLInputElement} */ (e.target).value)}
|
|
847
|
-
onkeydown={(e) => {
|
|
848
|
-
if (e.key === "ArrowDown") {
|
|
849
|
-
e.preventDefault();
|
|
850
|
-
commandPalette.navigate("down");
|
|
851
|
-
}
|
|
852
|
-
if (e.key === "ArrowUp") {
|
|
853
|
-
e.preventDefault();
|
|
854
|
-
commandPalette.navigate("up");
|
|
855
|
-
}
|
|
856
|
-
if (e.key === "Enter") {
|
|
857
|
-
e.preventDefault();
|
|
858
|
-
executePaletteCommand(commandPalette.selectedIndex);
|
|
859
|
-
}
|
|
860
|
-
if (e.key === "Escape") {
|
|
861
|
-
commandPalette.close();
|
|
862
|
-
}
|
|
863
|
-
}}
|
|
864
|
-
/>
|
|
865
|
-
<div class="command-palette-list">
|
|
866
|
-
{#each filteredPaletteCommands as cmd, i}
|
|
867
|
-
<button
|
|
868
|
-
type="button"
|
|
869
|
-
class="command-palette-item"
|
|
870
|
-
class:selected={i === commandPalette.selectedIndex}
|
|
871
|
-
onclick={() => executePaletteCommand(i)}
|
|
872
|
-
>
|
|
873
|
-
<span class="palette-cmd-label">{cmd.label}</span>
|
|
874
|
-
{#if cmd.shortcut}
|
|
875
|
-
<span class="palette-cmd-shortcut">{cmd.shortcut}</span>
|
|
876
|
-
{/if}
|
|
877
|
-
</button>
|
|
878
|
-
{/each}
|
|
879
|
-
</div>
|
|
880
|
-
</div>
|
|
881
|
-
</div>
|
|
882
|
-
{/if}
|
|
663
|
+
<!-- Floating Toolbar for text formatting (Medium-style) -->
|
|
664
|
+
<FloatingToolbar
|
|
665
|
+
{textareaRef}
|
|
666
|
+
bind:content={content}
|
|
667
|
+
{readonly}
|
|
668
|
+
onContentChange={(c) => content = c}
|
|
669
|
+
/>
|
|
883
670
|
|
|
884
671
|
<!-- Campfire Session Controls -->
|
|
885
672
|
{#if writingSession.isCampfireActive}
|
|
@@ -1321,6 +1108,15 @@
|
|
|
1321
1108
|
.toolbar-spacer {
|
|
1322
1109
|
flex: 1;
|
|
1323
1110
|
}
|
|
1111
|
+
.toolbar-left {
|
|
1112
|
+
display: flex;
|
|
1113
|
+
align-items: center;
|
|
1114
|
+
}
|
|
1115
|
+
.toolbar-hint {
|
|
1116
|
+
color: var(--editor-text-dim, #5a5a5a);
|
|
1117
|
+
font-size: 0.75rem;
|
|
1118
|
+
font-style: italic;
|
|
1119
|
+
}
|
|
1324
1120
|
.editor-area {
|
|
1325
1121
|
display: flex;
|
|
1326
1122
|
flex: 1;
|
|
@@ -1657,124 +1453,7 @@
|
|
|
1657
1453
|
.campfire-end:hover {
|
|
1658
1454
|
color: #f0d0a0;
|
|
1659
1455
|
}
|
|
1660
|
-
|
|
1661
|
-
position: fixed;
|
|
1662
|
-
top: 50%;
|
|
1663
|
-
left: 50%;
|
|
1664
|
-
transform: translate(-50%, -50%);
|
|
1665
|
-
min-width: 220px;
|
|
1666
|
-
max-height: 300px;
|
|
1667
|
-
overflow-y: auto;
|
|
1668
|
-
background: #252526;
|
|
1669
|
-
border: 1px solid var(--light-border-primary);
|
|
1670
|
-
border-radius: 8px;
|
|
1671
|
-
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
|
|
1672
|
-
z-index: 1001;
|
|
1673
|
-
animation: scale-in 0.15s ease;
|
|
1674
|
-
}
|
|
1675
|
-
.slash-menu-header {
|
|
1676
|
-
padding: 0.5rem 0.75rem;
|
|
1677
|
-
font-size: 0.8rem;
|
|
1678
|
-
font-family: "JetBrains Mono", "Fira Code", monospace;
|
|
1679
|
-
color: #8bc48b;
|
|
1680
|
-
border-bottom: 1px solid var(--light-border-primary);
|
|
1681
|
-
}
|
|
1682
|
-
.slash-menu-item {
|
|
1683
|
-
display: flex;
|
|
1684
|
-
align-items: center;
|
|
1685
|
-
width: 100%;
|
|
1686
|
-
padding: 0.6rem 0.75rem;
|
|
1687
|
-
background: transparent;
|
|
1688
|
-
border: none;
|
|
1689
|
-
color: #d4d4d4;
|
|
1690
|
-
font-size: 0.85rem;
|
|
1691
|
-
font-family: "JetBrains Mono", "Fira Code", monospace;
|
|
1692
|
-
text-align: left;
|
|
1693
|
-
cursor: pointer;
|
|
1694
|
-
transition: background-color 0.1s ease;
|
|
1695
|
-
}
|
|
1696
|
-
.slash-menu-item:hover,
|
|
1697
|
-
.slash-menu-item.selected {
|
|
1698
|
-
background: var(--light-border-primary);
|
|
1699
|
-
}
|
|
1700
|
-
.slash-menu-item.selected {
|
|
1701
|
-
color: #8bc48b;
|
|
1702
|
-
}
|
|
1703
|
-
.slash-menu-empty {
|
|
1704
|
-
padding: 0.75rem;
|
|
1705
|
-
color: #7a9a7a;
|
|
1706
|
-
font-family: "JetBrains Mono", "Fira Code", monospace;
|
|
1707
|
-
font-size: 0.8rem;
|
|
1708
|
-
text-align: center;
|
|
1709
|
-
}
|
|
1710
|
-
.command-palette-overlay {
|
|
1711
|
-
position: fixed;
|
|
1712
|
-
inset: 0;
|
|
1713
|
-
background: rgba(0, 0, 0, 0.5);
|
|
1714
|
-
display: flex;
|
|
1715
|
-
align-items: flex-start;
|
|
1716
|
-
justify-content: center;
|
|
1717
|
-
padding-top: 15vh;
|
|
1718
|
-
z-index: 1002;
|
|
1719
|
-
}
|
|
1720
|
-
.command-palette {
|
|
1721
|
-
width: 100%;
|
|
1722
|
-
max-width: 500px;
|
|
1723
|
-
background: var(--light-bg-primary);
|
|
1724
|
-
border: 1px solid var(--light-border-primary);
|
|
1725
|
-
border-radius: 8px;
|
|
1726
|
-
box-shadow: 0 16px 64px rgba(0, 0, 0, 0.6);
|
|
1727
|
-
overflow: hidden;
|
|
1728
|
-
animation: slide-down 0.2s ease;
|
|
1729
|
-
}
|
|
1730
|
-
.command-palette-input {
|
|
1731
|
-
width: 100%;
|
|
1732
|
-
padding: 1rem;
|
|
1733
|
-
background: transparent;
|
|
1734
|
-
border: none;
|
|
1735
|
-
border-bottom: 1px solid var(--light-border-primary);
|
|
1736
|
-
color: #d4d4d4;
|
|
1737
|
-
font-size: 1rem;
|
|
1738
|
-
font-family: "JetBrains Mono", "Fira Code", monospace;
|
|
1739
|
-
outline: none;
|
|
1740
|
-
}
|
|
1741
|
-
.command-palette-input::-moz-placeholder {
|
|
1742
|
-
color: #7a9a7a;
|
|
1743
|
-
}
|
|
1744
|
-
.command-palette-input::placeholder {
|
|
1745
|
-
color: #7a9a7a;
|
|
1746
|
-
}
|
|
1747
|
-
.command-palette-list {
|
|
1748
|
-
max-height: 300px;
|
|
1749
|
-
overflow-y: auto;
|
|
1750
|
-
}
|
|
1751
|
-
.command-palette-item {
|
|
1752
|
-
display: flex;
|
|
1753
|
-
align-items: center;
|
|
1754
|
-
justify-content: space-between;
|
|
1755
|
-
width: 100%;
|
|
1756
|
-
padding: 0.75rem 1rem;
|
|
1757
|
-
background: transparent;
|
|
1758
|
-
border: none;
|
|
1759
|
-
color: #d4d4d4;
|
|
1760
|
-
font-size: 0.9rem;
|
|
1761
|
-
font-family: "JetBrains Mono", "Fira Code", monospace;
|
|
1762
|
-
text-align: left;
|
|
1763
|
-
cursor: pointer;
|
|
1764
|
-
transition: background-color 0.1s ease;
|
|
1765
|
-
}
|
|
1766
|
-
.command-palette-item:hover,
|
|
1767
|
-
.command-palette-item.selected {
|
|
1768
|
-
background: var(--light-bg-tertiary);
|
|
1769
|
-
}
|
|
1770
|
-
.command-palette-item.selected {
|
|
1771
|
-
color: #8bc48b;
|
|
1772
|
-
}
|
|
1773
|
-
.palette-cmd-shortcut {
|
|
1774
|
-
font-size: 0.75rem;
|
|
1775
|
-
color: #6a6a6a;
|
|
1776
|
-
font-family: "JetBrains Mono", monospace;
|
|
1777
|
-
}
|
|
1456
|
+
/* Slash menu and command palette styles removed - using FloatingToolbar instead */
|
|
1778
1457
|
@keyframes fade-in {
|
|
1779
1458
|
from { opacity: 0; transform: translateY(10px); }
|
|
1780
1459
|
to { opacity: 1; transform: translateY(0); }
|
|
@@ -27,7 +27,7 @@ declare const MarkdownEditor: import("svelte").Component<{
|
|
|
27
27
|
clearDraft: () => void;
|
|
28
28
|
getDraftStatus: () => {
|
|
29
29
|
hasDraft: boolean;
|
|
30
|
-
storedDraft: import("./composables/useDraftManager.svelte
|
|
30
|
+
storedDraft: import("./composables/useDraftManager.svelte").StoredDraft | null;
|
|
31
31
|
};
|
|
32
32
|
}, "content">;
|
|
33
33
|
type $$ComponentProps = {
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
export { useSnippets } from "./useSnippets.svelte.js";
|
|
2
2
|
export { useDraftManager } from "./useDraftManager.svelte.js";
|
|
3
3
|
export { useWritingSession } from "./useWritingSession.svelte.js";
|
|
4
|
-
export { useCommandPalette } from "./useCommandPalette.svelte.js";
|
|
5
4
|
export { useAmbientSounds, soundLibrary } from "./useAmbientSounds.svelte.js";
|
|
6
5
|
export { useEditorTheme, themes } from "./useEditorTheme.svelte.js";
|
|
7
|
-
export { useSlashCommands, baseSlashCommands } from "./useSlashCommands.svelte.js";
|
|
@@ -8,5 +8,3 @@ export { useEditorTheme, themes } from "./useEditorTheme.svelte.js";
|
|
|
8
8
|
export { useSnippets } from "./useSnippets.svelte.js";
|
|
9
9
|
export { useDraftManager } from "./useDraftManager.svelte.js";
|
|
10
10
|
export { useWritingSession } from "./useWritingSession.svelte.js";
|
|
11
|
-
export { useSlashCommands, baseSlashCommands } from "./useSlashCommands.svelte.js";
|
|
12
|
-
export { useCommandPalette } from "./useCommandPalette.svelte.js";
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
* Helper to get anchor key with headers context
|
|
65
65
|
* @param {string} anchor
|
|
66
66
|
*/
|
|
67
|
-
function getKey(anchor) {
|
|
67
|
+
function getKey(anchor: string) {
|
|
68
68
|
return getAnchorKey(anchor, headers);
|
|
69
69
|
}
|
|
70
70
|
|
|
@@ -72,16 +72,16 @@
|
|
|
72
72
|
* Get items for a specific anchor
|
|
73
73
|
* @param {string} anchor
|
|
74
74
|
*/
|
|
75
|
-
function getItems(anchor) {
|
|
75
|
+
function getItems(anchor: string) {
|
|
76
76
|
return getItemsForAnchor(gutterContent, anchor);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
80
|
* Generate unique key for a gutter item
|
|
81
|
-
* @param {
|
|
81
|
+
* @param {GutterItemType} item
|
|
82
82
|
* @param {number} index
|
|
83
83
|
*/
|
|
84
|
-
function getItemKey(item, index) {
|
|
84
|
+
function getItemKey(item: GutterItemType, index: number): string {
|
|
85
85
|
// Combine item properties to create a unique identifier
|
|
86
86
|
const parts = [
|
|
87
87
|
item.type || 'unknown',
|
|
@@ -103,16 +103,15 @@
|
|
|
103
103
|
|
|
104
104
|
// Use getBoundingClientRect for accurate relative positioning
|
|
105
105
|
// This works regardless of offset parent chains and CSS transforms
|
|
106
|
-
const gutterRect = gutterElement.getBoundingClientRect();
|
|
106
|
+
const gutterRect = (gutterElement as HTMLElement).getBoundingClientRect();
|
|
107
107
|
|
|
108
108
|
let lastBottom = 0; // Track the bottom edge of the last positioned item
|
|
109
|
-
|
|
110
|
-
const newOverflowingAnchors = [];
|
|
109
|
+
const newOverflowingAnchors: string[] = [];
|
|
111
110
|
const newPositions = { ...itemPositions };
|
|
112
111
|
|
|
113
112
|
// Sort anchors by their position in the document
|
|
114
113
|
const anchorPositions = uniqueAnchors.map(anchor => {
|
|
115
|
-
const el = findAnchorElement(anchor, contentBodyElement ?? null, headers);
|
|
114
|
+
const el = findAnchorElement(anchor, (contentBodyElement ?? null) as HTMLElement | null, headers);
|
|
116
115
|
if (!el && import.meta.env.DEV) {
|
|
117
116
|
console.warn(`Anchor element not found for: ${anchor}`);
|
|
118
117
|
}
|
|
@@ -168,8 +167,7 @@
|
|
|
168
167
|
|
|
169
168
|
// Setup resize listener on mount with proper cleanup
|
|
170
169
|
onMount(() => {
|
|
171
|
-
|
|
172
|
-
let resizeTimeoutId;
|
|
170
|
+
let resizeTimeoutId: ReturnType<typeof setTimeout> | undefined;
|
|
173
171
|
const handleResize = () => {
|
|
174
172
|
clearTimeout(resizeTimeoutId);
|
|
175
173
|
resizeTimeoutId = setTimeout(() => {
|
|
@@ -186,9 +184,8 @@
|
|
|
186
184
|
|
|
187
185
|
// Setup copy button functionality for code blocks
|
|
188
186
|
onMount(() => {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const button = /** @type {HTMLElement} */ (event.currentTarget);
|
|
187
|
+
const handleCopyClick = async (event: Event) => {
|
|
188
|
+
const button = event.currentTarget as HTMLElement;
|
|
192
189
|
const codeText = button.getAttribute('data-code');
|
|
193
190
|
|
|
194
191
|
if (!codeText) return;
|
|
@@ -251,20 +248,19 @@
|
|
|
251
248
|
// Add IDs to headers and position mobile gutter items
|
|
252
249
|
$effect(() => {
|
|
253
250
|
// Track moved elements for cleanup
|
|
254
|
-
|
|
255
|
-
const movedElements = [];
|
|
251
|
+
const movedElements: Array<{ element: HTMLElement; originalParent: HTMLElement | null; originalNextSibling: Node | null }> = [];
|
|
256
252
|
|
|
257
253
|
untrack(() => {
|
|
258
254
|
if (!contentBodyElement) return;
|
|
259
255
|
|
|
260
256
|
// First, add IDs to headers
|
|
261
257
|
if (headers && headers.length > 0) {
|
|
262
|
-
const headerElements = contentBodyElement.querySelectorAll('h1, h2, h3, h4, h5, h6');
|
|
263
|
-
headerElements.forEach((el) => {
|
|
264
|
-
const text = el.textContent?.trim() || '';
|
|
265
|
-
const matchingHeader = headers.find(
|
|
258
|
+
const headerElements = (contentBodyElement as HTMLElement).querySelectorAll('h1, h2, h3, h4, h5, h6');
|
|
259
|
+
headerElements.forEach((el: Element) => {
|
|
260
|
+
const text = (el as HTMLElement).textContent?.trim() || '';
|
|
261
|
+
const matchingHeader = headers.find((h: Header) => h.text === text);
|
|
266
262
|
if (matchingHeader) {
|
|
267
|
-
el.id = matchingHeader.id;
|
|
263
|
+
(el as HTMLElement).id = matchingHeader.id;
|
|
268
264
|
}
|
|
269
265
|
});
|
|
270
266
|
}
|
|
@@ -279,7 +275,7 @@
|
|
|
279
275
|
const originalParent = mobileGutterEl.parentElement;
|
|
280
276
|
const originalNextSibling = mobileGutterEl.nextSibling;
|
|
281
277
|
|
|
282
|
-
const targetEl = findAnchorElement(anchor, contentBodyElement, headers);
|
|
278
|
+
const targetEl = findAnchorElement(anchor, contentBodyElement as HTMLElement, headers);
|
|
283
279
|
|
|
284
280
|
if (targetEl) {
|
|
285
281
|
targetEl.insertAdjacentElement('afterend', mobileGutterEl);
|
|
@@ -308,12 +304,13 @@
|
|
|
308
304
|
const updateHeight = () => {
|
|
309
305
|
if (!contentBodyElement) return;
|
|
310
306
|
// Get the bottom of content-body relative to the article
|
|
311
|
-
const rect = contentBodyElement.getBoundingClientRect();
|
|
312
|
-
const
|
|
307
|
+
const rect = (contentBodyElement as HTMLElement).getBoundingClientRect();
|
|
308
|
+
const articleEl = (contentBodyElement as HTMLElement).closest('.content-article');
|
|
309
|
+
const articleRect = articleEl?.getBoundingClientRect();
|
|
313
310
|
if (articleRect) {
|
|
314
311
|
contentHeight = rect.bottom - articleRect.top;
|
|
315
312
|
} else {
|
|
316
|
-
contentHeight = contentBodyElement.offsetTop + contentBodyElement.offsetHeight;
|
|
313
|
+
contentHeight = (contentBodyElement as HTMLElement).offsetTop + (contentBodyElement as HTMLElement).offsetHeight;
|
|
317
314
|
}
|
|
318
315
|
};
|
|
319
316
|
updateHeight();
|
|
@@ -348,7 +345,7 @@
|
|
|
348
345
|
* @param {string} html
|
|
349
346
|
* @param {string[]} overflowKeys
|
|
350
347
|
*/
|
|
351
|
-
function injectReferenceMarkers(html, overflowKeys) {
|
|
348
|
+
function injectReferenceMarkers(html: string, overflowKeys: string[]): string {
|
|
352
349
|
if (!overflowKeys || overflowKeys.length === 0 || typeof window === 'undefined') {
|
|
353
350
|
return html;
|
|
354
351
|
}
|