feat: migrate dashboard to svelte 5 (#577)
* chore: migration to SvelteKit 2 * stage 1: migrate to svelte 5 and fix rerendering issues * stage 2: fix more $: reactivity across dashboard * fix merge conflicts * chore: migrate code in main to svelte 5 * chore: update preventDefault * chore: simplify tsconfig and remove unused mobileMenuRef in MobileMenu.svelte * chore: enforce .ts across dashboard * rename from classroomio-com to website * stage-3: Replace carbon icon svelte with lucide icon * update lock file * chore: finish icon replacement * fix: settings and setup page multiple rerender * stage 3: More icon and rerendering fixes * feat: checkpoint * feat: update editor * [not working] connect everything with ui build * storybook + ui + dashboard all working independently * add bg-black to +page.svelte * feat: add editor to storybook * chore: animate lucid icons (#590) * v1 animations * feat: change some course navigation icons & animate org navigation icons * chore: change settings icon * chore: use css instead of js for hover * rename animations --------- Co-authored-by: tunny17 <[email protected]> * chore: update path to node_modules types in api tsconfig * fix: update import path for DropdownMenu component * fix: add rollupOptions to build configuration in vite.config.ts * fix: remove rollupOptions from build configuration and add @floating-ui/dom dependency * install --------- Co-authored-by: tunny17 <[email protected]>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
<script lang="ts">
|
||||
import { onMount, type Snippet } from 'svelte';
|
||||
import { BubbleMenuPlugin, type BubbleMenuPluginProps } from '@tiptap/extension-bubble-menu';
|
||||
import type { Editor } from '@tiptap/core';
|
||||
|
||||
type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
|
||||
|
||||
interface Props
|
||||
extends Optional<Omit<Optional<BubbleMenuPluginProps, 'pluginKey'>, 'element'>, 'editor'> {
|
||||
editor?: Editor;
|
||||
children?: Snippet<[]>;
|
||||
class?: string;
|
||||
style?: string;
|
||||
pluginKey?: string;
|
||||
updateDelay?: number;
|
||||
resizeDelay?: number;
|
||||
}
|
||||
|
||||
let {
|
||||
editor,
|
||||
shouldShow = null,
|
||||
class: className = '',
|
||||
style = '',
|
||||
children,
|
||||
updateDelay,
|
||||
resizeDelay,
|
||||
pluginKey = 'bubbleMenu',
|
||||
options,
|
||||
...restProps
|
||||
}: Props = $props();
|
||||
|
||||
let element = $state<HTMLElement>();
|
||||
|
||||
onMount(() => {
|
||||
if (!element) return;
|
||||
|
||||
element.style.position = 'absolute';
|
||||
element.style.visibility = 'hidden';
|
||||
|
||||
if (!editor || editor.isDestroyed) {
|
||||
console.warn('BubbleMenu component does not have editor prop or editor is destroyed.');
|
||||
return;
|
||||
}
|
||||
|
||||
const plugin = BubbleMenuPlugin({
|
||||
pluginKey,
|
||||
editor,
|
||||
element,
|
||||
shouldShow,
|
||||
updateDelay,
|
||||
resizeDelay,
|
||||
options
|
||||
});
|
||||
|
||||
editor.registerPlugin(plugin);
|
||||
|
||||
return () => {
|
||||
if (editor && !editor.isDestroyed) {
|
||||
editor.unregisterPlugin(pluginKey);
|
||||
}
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<div bind:this={element} class={`bubble-menu-wrapper ${className}`} {style} {...restProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
@@ -0,0 +1,31 @@
|
||||
<script lang="ts">
|
||||
import type { Editor } from '@tiptap/core';
|
||||
import { onMount } from 'svelte';
|
||||
import GripVertical from '@lucide/svelte/icons/grip-vertical';
|
||||
import { DragHandlePlugin } from '../extensions/drag-handle';
|
||||
|
||||
interface Props {
|
||||
editor: Editor;
|
||||
}
|
||||
|
||||
const { editor }: Props = $props();
|
||||
|
||||
const pluginKey = 'globalDragHandle';
|
||||
|
||||
onMount(() => {
|
||||
const plugin = DragHandlePlugin({
|
||||
pluginKey: pluginKey,
|
||||
dragHandleWidth: 20,
|
||||
scrollTreshold: 100,
|
||||
dragHandleSelector: '.drag-handle',
|
||||
excludedTags: ['pre', 'code', 'table p'],
|
||||
customNodes: []
|
||||
});
|
||||
editor.registerPlugin(plugin);
|
||||
return () => editor.unregisterPlugin(pluginKey);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="drag-handle">
|
||||
<GripVertical />
|
||||
</div>
|
||||
@@ -0,0 +1,30 @@
|
||||
<script lang="ts">
|
||||
import type { Icon } from '@lucide/svelte';
|
||||
import type { Snippet } from 'svelte';
|
||||
import { NodeViewWrapper } from 'svelte-tiptap';
|
||||
|
||||
interface Props {
|
||||
icon?: typeof Icon;
|
||||
title?: string;
|
||||
onClick?: () => void;
|
||||
class?: string;
|
||||
children?: Snippet<[]>;
|
||||
}
|
||||
|
||||
const { icon, title, onClick, class: className = '', children }: Props = $props();
|
||||
</script>
|
||||
|
||||
<NodeViewWrapper
|
||||
as="div"
|
||||
contenteditable="false"
|
||||
class={`media-placeholder ${className}`}
|
||||
onclick={onClick}
|
||||
style="user-select: none;"
|
||||
>
|
||||
{#if !children && icon && title}
|
||||
{@const Icon = icon}
|
||||
<Icon />
|
||||
<div contenteditable="false">{title}</div>
|
||||
{/if}
|
||||
{@render children?.()}
|
||||
</NodeViewWrapper>
|
||||
Reference in New Issue
Block a user