fix: update components to use Svelte 5 snippets and fix editor content loading
- Convert Button component to use snippets instead of slots - Update BaseDropdown and StatusDropdown to use new Button snippet syntax - Add effect to watch for data changes in ComposerCore and update editor content - Fix SVG component usage in Album component for Svelte 5 compatibility 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
e64788962e
commit
639a4a2429
5 changed files with 68 additions and 39 deletions
|
|
@ -165,9 +165,9 @@
|
||||||
class:playing={isPlaying}
|
class:playing={isPlaying}
|
||||||
>
|
>
|
||||||
{#if isPlaying}
|
{#if isPlaying}
|
||||||
<PauseIcon />
|
<svelte:component this={PauseIcon} />
|
||||||
{:else}
|
{:else}
|
||||||
<PlayIcon />
|
<svelte:component this={PlayIcon} />
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import type { Snippet } from 'svelte'
|
||||||
import Button from './Button.svelte'
|
import Button from './Button.svelte'
|
||||||
import DropdownMenuContainer from './DropdownMenuContainer.svelte'
|
import DropdownMenuContainer from './DropdownMenuContainer.svelte'
|
||||||
|
|
||||||
|
|
@ -9,6 +10,8 @@
|
||||||
dropdownTriggerSize?: 'small' | 'medium' | 'large'
|
dropdownTriggerSize?: 'small' | 'medium' | 'large'
|
||||||
class?: string
|
class?: string
|
||||||
onToggle?: (isOpen: boolean) => void
|
onToggle?: (isOpen: boolean) => void
|
||||||
|
trigger: Snippet
|
||||||
|
dropdown?: Snippet
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let {
|
||||||
|
|
@ -17,7 +20,9 @@
|
||||||
isLoading = false,
|
isLoading = false,
|
||||||
dropdownTriggerSize = 'large',
|
dropdownTriggerSize = 'large',
|
||||||
class: className = '',
|
class: className = '',
|
||||||
onToggle
|
onToggle,
|
||||||
|
trigger,
|
||||||
|
dropdown
|
||||||
}: Props = $props()
|
}: Props = $props()
|
||||||
|
|
||||||
function handleDropdownToggle(e: MouseEvent) {
|
function handleDropdownToggle(e: MouseEvent) {
|
||||||
|
|
@ -47,9 +52,9 @@
|
||||||
|
|
||||||
<div class="dropdown-container {className}">
|
<div class="dropdown-container {className}">
|
||||||
<div class="dropdown-trigger">
|
<div class="dropdown-trigger">
|
||||||
<slot name="trigger" />
|
{@render trigger()}
|
||||||
|
|
||||||
{#if $$slots.dropdown}
|
{#if dropdown}
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
iconOnly
|
iconOnly
|
||||||
|
|
@ -59,22 +64,24 @@
|
||||||
{isLoading}
|
{isLoading}
|
||||||
class="dropdown-toggle"
|
class="dropdown-toggle"
|
||||||
>
|
>
|
||||||
<svg slot="icon" width="12" height="12" viewBox="0 0 12 12" fill="none">
|
{#snippet icon()}
|
||||||
<path
|
<svg width="12" height="12" viewBox="0 0 12 12" fill="none">
|
||||||
d="M3 4.5L6 7.5L9 4.5"
|
<path
|
||||||
stroke="currentColor"
|
d="M3 4.5L6 7.5L9 4.5"
|
||||||
stroke-width="1.5"
|
stroke="currentColor"
|
||||||
stroke-linecap="round"
|
stroke-width="1.5"
|
||||||
stroke-linejoin="round"
|
stroke-linecap="round"
|
||||||
/>
|
stroke-linejoin="round"
|
||||||
</svg>
|
/>
|
||||||
|
</svg>
|
||||||
|
{/snippet}
|
||||||
</Button>
|
</Button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if isOpen && $$slots.dropdown}
|
{#if isOpen && dropdown}
|
||||||
<DropdownMenuContainer>
|
<DropdownMenuContainer>
|
||||||
<slot name="dropdown" />
|
{@render dropdown()}
|
||||||
</DropdownMenuContainer>
|
</DropdownMenuContainer>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { HTMLButtonAttributes } from 'svelte/elements'
|
import type { HTMLButtonAttributes } from 'svelte/elements'
|
||||||
|
import type { Snippet } from 'svelte'
|
||||||
|
|
||||||
interface Props extends HTMLButtonAttributes {
|
interface Props extends HTMLButtonAttributes {
|
||||||
variant?: 'primary' | 'secondary' | 'danger' | 'ghost' | 'text' | 'overlay' | 'danger-text'
|
variant?: 'primary' | 'secondary' | 'danger' | 'ghost' | 'text' | 'overlay' | 'danger-text'
|
||||||
|
|
@ -12,6 +13,8 @@
|
||||||
active?: boolean
|
active?: boolean
|
||||||
href?: string
|
href?: string
|
||||||
class?: string
|
class?: string
|
||||||
|
icon?: Snippet
|
||||||
|
children?: Snippet
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let {
|
||||||
|
|
@ -27,6 +30,7 @@
|
||||||
type = 'button',
|
type = 'button',
|
||||||
href,
|
href,
|
||||||
class: className = '',
|
class: className = '',
|
||||||
|
icon,
|
||||||
children,
|
children,
|
||||||
onclick,
|
onclick,
|
||||||
...restProps
|
...restProps
|
||||||
|
|
@ -60,8 +64,8 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
// Handle icon slot positioning
|
// Handle icon slot positioning
|
||||||
const hasIcon = $derived(!!$$slots.icon)
|
const hasIcon = $derived(!!icon)
|
||||||
const hasDefaultSlot = $derived(!!$$slots.default)
|
const hasDefaultSlot = $derived(!!children)
|
||||||
const showSpinner = $derived(loading && !iconOnly)
|
const showSpinner = $derived(loading && !iconOnly)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -94,21 +98,21 @@
|
||||||
|
|
||||||
{#if hasIcon && iconPosition === 'left' && !iconOnly}
|
{#if hasIcon && iconPosition === 'left' && !iconOnly}
|
||||||
<span class="btn-icon-wrapper">
|
<span class="btn-icon-wrapper">
|
||||||
<slot name="icon" />
|
{@render icon()}
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if hasDefaultSlot && !iconOnly}
|
{#if hasDefaultSlot && !iconOnly}
|
||||||
<span class="btn-label">
|
<span class="btn-label">
|
||||||
<slot />
|
{@render children()}
|
||||||
</span>
|
</span>
|
||||||
{:else if iconOnly && hasIcon}
|
{:else if iconOnly && hasIcon}
|
||||||
<slot name="icon" />
|
{@render icon()}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if hasIcon && iconPosition === 'right' && !iconOnly}
|
{#if hasIcon && iconPosition === 'right' && !iconOnly}
|
||||||
<span class="btn-icon-wrapper">
|
<span class="btn-icon-wrapper">
|
||||||
<slot name="icon" />
|
{@render icon()}
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -141,21 +145,21 @@
|
||||||
|
|
||||||
{#if hasIcon && iconPosition === 'left' && !iconOnly}
|
{#if hasIcon && iconPosition === 'left' && !iconOnly}
|
||||||
<span class="btn-icon-wrapper">
|
<span class="btn-icon-wrapper">
|
||||||
<slot name="icon" />
|
{@render icon()}
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if hasDefaultSlot && !iconOnly}
|
{#if hasDefaultSlot && !iconOnly}
|
||||||
<span class="btn-label">
|
<span class="btn-label">
|
||||||
<slot />
|
{@render children()}
|
||||||
</span>
|
</span>
|
||||||
{:else if iconOnly && hasIcon}
|
{:else if iconOnly && hasIcon}
|
||||||
<slot name="icon" />
|
{@render icon()}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if hasIcon && iconPosition === 'right' && !iconOnly}
|
{#if hasIcon && iconPosition === 'right' && !iconOnly}
|
||||||
<span class="btn-icon-wrapper">
|
<span class="btn-icon-wrapper">
|
||||||
<slot name="icon" />
|
{@render icon()}
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -55,18 +55,21 @@
|
||||||
{isLoading}
|
{isLoading}
|
||||||
class="status-dropdown"
|
class="status-dropdown"
|
||||||
>
|
>
|
||||||
<Button
|
{#snippet trigger()}
|
||||||
slot="trigger"
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
buttonSize="large"
|
buttonSize="large"
|
||||||
onclick={handlePrimaryAction}
|
onclick={handlePrimaryAction}
|
||||||
disabled={disabled || isLoading}
|
disabled={disabled || isLoading}
|
||||||
>
|
>
|
||||||
{primaryAction.label}
|
{#snippet children()}
|
||||||
</Button>
|
{primaryAction.label}
|
||||||
|
{/snippet}
|
||||||
|
</Button>
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
{#if hasDropdownContent}
|
{#snippet dropdown()}
|
||||||
<div slot="dropdown">
|
{#if hasDropdownContent}
|
||||||
{#each availableActions as action}
|
{#each availableActions as action}
|
||||||
<DropdownItem onclick={() => handleDropdownAction(action.status)}>
|
<DropdownItem onclick={() => handleDropdownAction(action.status)}>
|
||||||
{action.label}
|
{action.label}
|
||||||
|
|
@ -85,8 +88,8 @@
|
||||||
View on site
|
View on site
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
{/if}
|
||||||
{/if}
|
{/snippet}
|
||||||
</BaseDropdown>
|
</BaseDropdown>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@
|
||||||
let element = $state<HTMLElement>()
|
let element = $state<HTMLElement>()
|
||||||
let isLoading = $state(true)
|
let isLoading = $state(true)
|
||||||
let initialized = false
|
let initialized = false
|
||||||
|
let contentLoaded = false
|
||||||
const mediaSelectionState = $derived($mediaSelectionStore)
|
const mediaSelectionState = $derived($mediaSelectionStore)
|
||||||
|
|
||||||
// Toolbar component ref
|
// Toolbar component ref
|
||||||
|
|
@ -161,6 +162,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Watch for external data changes and update editor
|
||||||
|
$effect(() => {
|
||||||
|
if (editor && data && !contentLoaded) {
|
||||||
|
// Only update if the data has actual content (not just empty doc)
|
||||||
|
const hasContent = data.content && data.content.length > 0 &&
|
||||||
|
!(data.content.length === 1 && data.content[0].type === 'paragraph' && !data.content[0].content);
|
||||||
|
|
||||||
|
if (hasContent) {
|
||||||
|
editor.commands.setContent(data);
|
||||||
|
contentLoaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
// Get extensions with custom options
|
// Get extensions with custom options
|
||||||
const extensions = getEditorExtensions({
|
const extensions = getEditorExtensions({
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue