Last round of prettier: npx prettier --write src/

This commit is contained in:
Scott Idem
2026-03-24 13:27:40 -04:00
parent 23d25bf65a
commit a8f3c29b9f
146 changed files with 13201 additions and 9277 deletions

View File

@@ -1,120 +1,163 @@
<script lang="ts">
/**
* element_editor_tiptap.svelte
* Zero-Dependency Rich Text Editor for Aether Platform.
* Uses native contenteditable to avoid TipTap/ProseMirror library conflicts.
* Styles aligned with existing .tiptap SCSS definitions.
*/
import { onMount, untrack } from 'svelte';
import { browser } from '$app/environment';
import { AlignLeft, Bold, Code, Italic, List, ListOrdered, RemoveFormatting, Type } from '@lucide/svelte';
import { ae_util } from '$lib/ae_utils/ae_utils';
/**
* element_editor_tiptap.svelte
* Zero-Dependency Rich Text Editor for Aether Platform.
* Uses native contenteditable to avoid TipTap/ProseMirror library conflicts.
* Styles aligned with existing .tiptap SCSS definitions.
*/
import { onMount, untrack } from 'svelte';
import { browser } from '$app/environment';
import {
AlignLeft,
Bold,
Code,
Italic,
List,
ListOrdered,
RemoveFormatting,
Type
} from '@lucide/svelte';
import { ae_util } from '$lib/ae_utils/ae_utils';
interface Props {
content?: string;
new_content?: string;
placeholder?: string;
readonly?: boolean;
auto_format?: boolean;
class_li?: string;
interface Props {
content?: string;
new_content?: string;
placeholder?: string;
readonly?: boolean;
auto_format?: boolean;
class_li?: string;
}
let {
content = $bindable(''),
new_content = $bindable(),
placeholder = 'Start writing...',
readonly = false,
auto_format = true,
class_li = ''
}: Props = $props();
let editor_element: HTMLDivElement | undefined = $state();
let is_focused = $state(false);
// Sync external content changes into the editor
$effect(() => {
if (editor_element && content !== editor_element.innerHTML) {
untrack(() => {
editor_element!.innerHTML = content || '';
});
}
});
let {
content = $bindable(''),
new_content = $bindable(),
placeholder = 'Start writing...',
readonly = false,
auto_format = true,
class_li = ''
}: Props = $props();
function handle_input(e: Event) {
const html = (e.target as HTMLDivElement).innerHTML;
// Clean up empty state (browsers sometimes leave <br> or <p></p>)
const cleaned = html === '<br>' || html === '<p></p>' ? '' : html;
content = cleaned;
new_content = cleaned;
}
let editor_element: HTMLDivElement | undefined = $state();
let is_focused = $state(false);
// Toolbar Actions using native execCommand
// (While deprecated, it remains the standard for zero-dep simple rich text)
function exec(command: string, value: string | undefined = undefined) {
if (!browser || readonly) return;
document.execCommand(command, false, value);
editor_element?.focus();
}
// Sync external content changes into the editor
$effect(() => {
if (editor_element && content !== editor_element.innerHTML) {
untrack(() => {
editor_element!.innerHTML = content || '';
});
function handle_keydown(e: KeyboardEvent) {
// Basic shortcuts: Cmd/Ctrl + B, I
if (e.metaKey || e.ctrlKey) {
if (e.key === 'b') {
e.preventDefault();
exec('bold');
}
});
function handle_input(e: Event) {
const html = (e.target as HTMLDivElement).innerHTML;
// Clean up empty state (browsers sometimes leave <br> or <p></p>)
const cleaned = (html === '<br>' || html === '<p></p>') ? '' : html;
content = cleaned;
new_content = cleaned;
}
// Toolbar Actions using native execCommand
// (While deprecated, it remains the standard for zero-dep simple rich text)
function exec(command: string, value: string | undefined = undefined) {
if (!browser || readonly) return;
document.execCommand(command, false, value);
editor_element?.focus();
}
function handle_keydown(e: KeyboardEvent) {
// Basic shortcuts: Cmd/Ctrl + B, I
if (e.metaKey || e.ctrlKey) {
if (e.key === 'b') { e.preventDefault(); exec('bold'); }
if (e.key === 'i') { e.preventDefault(); exec('italic'); }
if (e.key === 'i') {
e.preventDefault();
exec('italic');
}
}
}
function handle_format() {
if (!content) return;
const formatted = ae_util.format_html(content);
content = formatted;
new_content = formatted;
}
function handle_format() {
if (!content) return;
const formatted = ae_util.format_html(content);
content = formatted;
new_content = formatted;
}
function handle_blur() {
is_focused = false;
if (auto_format) {
handle_format();
}
function handle_blur() {
is_focused = false;
if (auto_format) {
handle_format();
}
}
</script>
<div class="ae__comp__editor_tiptap flex flex-col border border-surface-500/20 rounded-container overflow-hidden bg-white dark:bg-black/10 {class_li}">
<div
class="ae__comp__editor_tiptap border-surface-500/20 rounded-container flex flex-col overflow-hidden border bg-white dark:bg-black/10 {class_li}">
{#if !readonly}
<div class="toolbar flex flex-wrap gap-1 p-1 bg-surface-50 dark:bg-surface-900 border-b border-surface-500/20">
<button type="button" class="btn btn-sm variant-soft hover:variant-filled-primary" onclick={() => exec('bold')} title="Bold">
<div
class="toolbar bg-surface-50 dark:bg-surface-900 border-surface-500/20 flex flex-wrap gap-1 border-b p-1">
<button
type="button"
class="btn btn-sm variant-soft hover:variant-filled-primary"
onclick={() => exec('bold')}
title="Bold">
<Bold size="14" />
</button>
<button type="button" class="btn btn-sm variant-soft hover:variant-filled-primary" onclick={() => exec('italic')} title="Italic">
<button
type="button"
class="btn btn-sm variant-soft hover:variant-filled-primary"
onclick={() => exec('italic')}
title="Italic">
<Italic size="14" />
</button>
<div class="w-px h-4 bg-surface-500/20 mx-1 self-center"></div>
<button type="button" class="btn btn-sm variant-soft hover:variant-filled-primary" onclick={() => exec('insertUnorderedList')} title="Bullet List">
<div class="bg-surface-500/20 mx-1 h-4 w-px self-center"></div>
<button
type="button"
class="btn btn-sm variant-soft hover:variant-filled-primary"
onclick={() => exec('insertUnorderedList')}
title="Bullet List">
<List size="14" />
</button>
<button type="button" class="btn btn-sm variant-soft hover:variant-filled-primary" onclick={() => exec('insertOrderedList')} title="Numbered List">
<button
type="button"
class="btn btn-sm variant-soft hover:variant-filled-primary"
onclick={() => exec('insertOrderedList')}
title="Numbered List">
<ListOrdered size="14" />
</button>
<div class="w-px h-4 bg-surface-500/20 mx-1 self-center"></div>
<button type="button" class="btn btn-sm variant-soft hover:variant-filled-error" onclick={() => exec('removeFormat')} title="Clear Formatting">
<div class="bg-surface-500/20 mx-1 h-4 w-px self-center"></div>
<button
type="button"
class="btn btn-sm variant-soft hover:variant-filled-error"
onclick={() => exec('removeFormat')}
title="Clear Formatting">
<RemoveFormatting size="14" />
</button>
<button type="button" class="btn btn-sm variant-soft hover:variant-filled-success" onclick={handle_format} title="Format HTML Source">
<button
type="button"
class="btn btn-sm variant-soft hover:variant-filled-success"
onclick={handle_format}
title="Format HTML Source">
<AlignLeft size="14" />
<span class="text-[10px] ml-1">Format</span>
<span class="ml-1 text-[10px]">Format</span>
</button>
<div class="ml-auto flex gap-1 items-center px-2">
<div class="ml-auto flex items-center gap-1 px-2">
<Type size="12" class="opacity-30" />
<span class="text-[10px] opacity-50 uppercase font-bold">Visual</span>
<span class="text-[10px] font-bold uppercase opacity-50"
>Visual</span>
</div>
</div>
{/if}
<div class="grow relative h-full min-h-[150px] overflow-auto p-4">
<div class="relative h-full min-h-[150px] grow overflow-auto p-4">
{#if !content && !is_focused}
<div class="absolute top-4 left-4 pointer-events-none opacity-30 italic text-sm">
<div
class="pointer-events-none absolute top-4 left-4 text-sm italic opacity-30">
{placeholder}
</div>
{/if}
@@ -122,33 +165,33 @@
<div
bind:this={editor_element}
contenteditable={!readonly}
class="tiptap outline-none h-full w-full prose dark:prose-invert max-w-none"
class="tiptap prose dark:prose-invert h-full w-full max-w-none outline-none"
oninput={handle_input}
onfocus={() => is_focused = true}
onfocus={() => (is_focused = true)}
onblur={handle_blur}
onkeydown={handle_keydown}
role="textbox"
tabindex="0"
aria-multiline="true"
></div>
aria-multiline="true">
</div>
</div>
</div>
<style lang="postcss">
/* Import your existing TipTap styles */
@import './styles/element_tiptap_editor.scss';
/* Import your existing TipTap styles */
@import './styles/element_tiptap_editor.scss';
.ae__comp__editor_tiptap :global(.tiptap) {
min-height: 120px;
}
.ae__comp__editor_tiptap :global(.tiptap) {
min-height: 120px;
}
/* Ensure lists look correct inside the editor */
.ae__comp__editor_tiptap :global(.tiptap ul) {
list-style-type: disc;
padding-left: 1.5rem;
}
.ae__comp__editor_tiptap :global(.tiptap ol) {
list-style-type: decimal;
padding-left: 1.5rem;
}
/* Ensure lists look correct inside the editor */
.ae__comp__editor_tiptap :global(.tiptap ul) {
list-style-type: disc;
padding-left: 1.5rem;
}
.ae__comp__editor_tiptap :global(.tiptap ol) {
list-style-type: decimal;
padding-left: 1.5rem;
}
</style>