diff --git a/src/app.css b/src/app.css
index 447401c..1f73230 100644
--- a/src/app.css
+++ b/src/app.css
@@ -1,3 +1,3 @@
/* Global styles for the entire application */
@import './assets/styles/reset.css';
-@import './assets/styles/globals.scss';
\ No newline at end of file
+@import './assets/styles/globals.scss';
diff --git a/src/assets/styles/imports.scss b/src/assets/styles/imports.scss
index 5b45e44..509590f 100644
--- a/src/assets/styles/imports.scss
+++ b/src/assets/styles/imports.scss
@@ -3,4 +3,4 @@
@import './variables.scss';
@import './fonts.scss';
-@import './themes.scss';
\ No newline at end of file
+@import './themes.scss';
diff --git a/src/lib/components/SegmentedController.svelte b/src/lib/components/SegmentedController.svelte
index c6a28ba..d93c478 100644
--- a/src/lib/components/SegmentedController.svelte
+++ b/src/lib/components/SegmentedController.svelte
@@ -119,9 +119,7 @@
onmouseenter={() => (hoveredIndex = index)}
onmouseleave={() => (hoveredIndex = null)}
>
-
+
{item.text}
{/each}
diff --git a/src/lib/components/admin/EditorWithUpload.svelte b/src/lib/components/admin/EditorWithUpload.svelte
index 7894c6c..c6a0da5 100644
--- a/src/lib/components/admin/EditorWithUpload.svelte
+++ b/src/lib/components/admin/EditorWithUpload.svelte
@@ -83,18 +83,18 @@
let mediaDropdownTriggerRef = $state()
let dropdownPosition = $state({ top: 0, left: 0 })
let mediaDropdownPosition = $state({ top: 0, left: 0 })
-
+
// URL convert dropdown state
let showUrlConvertDropdown = $state(false)
let urlConvertDropdownPosition = $state({ x: 0, y: 0 })
let urlConvertPos = $state(null)
-
+
// Link context menu state
let showLinkContextMenu = $state(false)
let linkContextMenuPosition = $state({ x: 0, y: 0 })
let linkContextUrl = $state(null)
let linkContextPos = $state(null)
-
+
// Link edit dialog state
let showLinkEditDialog = $state(false)
let linkEditDialogPosition = $state({ x: 0, y: 0 })
@@ -239,85 +239,89 @@
showLinkEditDialog = false
}
}
-
+
// Handle URL convert dropdown
const handleShowUrlConvertDropdown = (pos: number, url: string) => {
if (!editor) return
-
+
// Get the cursor coordinates
const coords = editor.view.coordsAtPos(pos)
urlConvertDropdownPosition = { x: coords.left, y: coords.bottom + 5 }
urlConvertPos = pos
showUrlConvertDropdown = true
}
-
+
// Handle link context menu
- const handleShowLinkContextMenu = (pos: number, url: string, coords: { x: number, y: number }) => {
+ const handleShowLinkContextMenu = (
+ pos: number,
+ url: string,
+ coords: { x: number; y: number }
+ ) => {
if (!editor) return
-
+
linkContextMenuPosition = { x: coords.x, y: coords.y + 5 }
linkContextUrl = url
linkContextPos = pos
showLinkContextMenu = true
}
-
+
const handleConvertToEmbed = () => {
if (!editor || urlConvertPos === null) return
-
+
editor.commands.convertLinkToEmbed(urlConvertPos)
showUrlConvertDropdown = false
urlConvertPos = null
}
-
+
const handleConvertLinkToEmbed = () => {
if (!editor || linkContextPos === null) return
-
+
editor.commands.convertLinkToEmbed(linkContextPos)
showLinkContextMenu = false
linkContextPos = null
linkContextUrl = null
}
-
+
const handleEditLink = () => {
if (!editor || !linkContextUrl) return
-
+
linkEditUrl = linkContextUrl
linkEditPos = linkContextPos
linkEditDialogPosition = { ...linkContextMenuPosition }
showLinkEditDialog = true
showLinkContextMenu = false
}
-
+
const handleSaveLink = (newUrl: string) => {
if (!editor) return
-
+
editor.chain().focus().extendMarkRange('link').setLink({ href: newUrl }).run()
showLinkEditDialog = false
linkEditPos = null
linkEditUrl = ''
}
-
+
const handleCopyLink = () => {
if (!linkContextUrl) return
-
+
navigator.clipboard.writeText(linkContextUrl)
showLinkContextMenu = false
linkContextPos = null
linkContextUrl = null
}
-
+
const handleRemoveLink = () => {
if (!editor) return
-
+
editor.chain().focus().extendMarkRange('link').unsetLink().run()
showLinkContextMenu = false
linkContextPos = null
linkContextUrl = null
}
-
+
const handleOpenLink = () => {
if (!linkContextUrl) return
-
+
window.open(linkContextUrl, '_blank', 'noopener,noreferrer')
showLinkContextMenu = false
linkContextPos = null
@@ -325,7 +329,13 @@
}
$effect(() => {
- if (showTextStyleDropdown || showMediaDropdown || showUrlConvertDropdown || showLinkContextMenu || showLinkEditDialog) {
+ if (
+ showTextStyleDropdown ||
+ showMediaDropdown ||
+ showUrlConvertDropdown ||
+ showLinkContextMenu ||
+ showLinkEditDialog
+ ) {
document.addEventListener('click', handleClickOutside)
return () => {
document.removeEventListener('click', handleClickOutside)
@@ -484,16 +494,16 @@
// Dismiss URL convert dropdown if user types
if (showUrlConvertDropdown && transaction.docChanged) {
// Check if the change is actual typing (not just cursor movement)
- const hasTextChange = transaction.steps.some(step =>
- step.toJSON().stepType === 'replace' ||
- step.toJSON().stepType === 'replaceAround'
+ const hasTextChange = transaction.steps.some(
+ (step) =>
+ step.toJSON().stepType === 'replace' || step.toJSON().stepType === 'replaceAround'
)
if (hasTextChange) {
showUrlConvertDropdown = false
urlConvertPos = null
}
}
-
+
// Call the original onUpdate if provided
if (onUpdate) {
onUpdate({ editor: updatedEditor, transaction })
diff --git a/src/lib/components/edra/extensions/link-context-menu/LinkContextMenu.ts b/src/lib/components/edra/extensions/link-context-menu/LinkContextMenu.ts
index c8b3626..5208b8d 100644
--- a/src/lib/components/edra/extensions/link-context-menu/LinkContextMenu.ts
+++ b/src/lib/components/edra/extensions/link-context-menu/LinkContextMenu.ts
@@ -2,7 +2,7 @@ import { Extension } from '@tiptap/core'
import { Plugin, PluginKey } from '@tiptap/pm/state'
export interface LinkContextMenuOptions {
- onShowContextMenu?: (pos: number, url: string, coords: { x: number, y: number }) => void
+ onShowContextMenu?: (pos: number, url: string, coords: { x: number; y: number }) => void
}
export const LinkContextMenu = Extension.create({
@@ -16,7 +16,7 @@ export const LinkContextMenu = Extension.create({
addProseMirrorPlugins() {
const options = this.options
-
+
return [
new Plugin({
key: new PluginKey('linkContextMenu'),
@@ -25,26 +25,26 @@ export const LinkContextMenu = Extension.create({
contextmenu: (view, event) => {
const { state } = view
const pos = view.posAtCoords({ left: event.clientX, top: event.clientY })
-
+
if (!pos) return false
-
+
const $pos = state.doc.resolve(pos.pos)
const marks = $pos.marks()
- const linkMark = marks.find(mark => mark.type.name === 'link')
-
+ const linkMark = marks.find((mark) => mark.type.name === 'link')
+
if (linkMark && linkMark.attrs.href) {
event.preventDefault()
-
+
if (options.onShowContextMenu) {
options.onShowContextMenu(pos.pos, linkMark.attrs.href, {
x: event.clientX,
y: event.clientY
})
}
-
+
return true
}
-
+
return false
}
}
@@ -52,4 +52,4 @@ export const LinkContextMenu = Extension.create({
})
]
}
-})
\ No newline at end of file
+})
diff --git a/src/lib/components/edra/extensions/url-embed/UrlEmbed.ts b/src/lib/components/edra/extensions/url-embed/UrlEmbed.ts
index e52b7dd..511fbcf 100644
--- a/src/lib/components/edra/extensions/url-embed/UrlEmbed.ts
+++ b/src/lib/components/edra/extensions/url-embed/UrlEmbed.ts
@@ -78,7 +78,10 @@ export const UrlEmbed = Node.create({
},
renderHTML({ HTMLAttributes }) {
- return ['div', mergeAttributes({ 'data-url-embed': '' }, this.options.HTMLAttributes, HTMLAttributes)]
+ return [
+ 'div',
+ mergeAttributes({ 'data-url-embed': '' }, this.options.HTMLAttributes, HTMLAttributes)
+ ]
},
addCommands() {
@@ -102,35 +105,41 @@ export const UrlEmbed = Node.create({
(pos) =>
({ state, commands, chain }) => {
const { doc } = state
-
+
// Find the link mark at the given position
const $pos = doc.resolve(pos)
const marks = $pos.marks()
- const linkMark = marks.find(mark => mark.type.name === 'link')
-
+ const linkMark = marks.find((mark) => mark.type.name === 'link')
+
if (!linkMark) return false
-
+
const url = linkMark.attrs.href
if (!url) return false
-
+
// Find the complete range of text with this link mark
let from = pos
let to = pos
-
+
// Walk backwards to find the start
doc.nodesBetween(Math.max(0, pos - 300), pos, (node, nodePos) => {
- if (node.isText && node.marks.some(m => m.type.name === 'link' && m.attrs.href === url)) {
+ if (
+ node.isText &&
+ node.marks.some((m) => m.type.name === 'link' && m.attrs.href === url)
+ ) {
from = nodePos
}
})
-
+
// Walk forwards to find the end
doc.nodesBetween(pos, Math.min(doc.content.size, pos + 300), (node, nodePos) => {
- if (node.isText && node.marks.some(m => m.type.name === 'link' && m.attrs.href === url)) {
+ if (
+ node.isText &&
+ node.marks.some((m) => m.type.name === 'link' && m.attrs.href === url)
+ ) {
to = nodePos + node.nodeSize
}
})
-
+
// Use Tiptap's chain commands to replace content
return chain()
.focus()
@@ -179,40 +188,53 @@ export const UrlEmbed = Node.create({
// Check if it's a plain text paste
if (text && !html) {
// Simple URL regex check
- const urlRegex = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/
-
+ const urlRegex =
+ /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/
+
if (urlRegex.test(text.trim())) {
// It's a URL, let it paste as a link naturally (don't prevent default)
// But track it so we can show dropdown after
const pastedUrl = text.trim()
-
+
// Get the position before paste
const beforePos = view.state.selection.from
-
+
setTimeout(() => {
const { state } = view
const { doc } = state
-
+
// Find the link that was just inserted
// Start from where we were before paste
let linkStart = -1
let linkEnd = -1
-
+
// Search for the link in a reasonable range
- for (let pos = beforePos; pos < Math.min(doc.content.size, beforePos + pastedUrl.length + 10); pos++) {
+ for (
+ let pos = beforePos;
+ pos < Math.min(doc.content.size, beforePos + pastedUrl.length + 10);
+ pos++
+ ) {
try {
const $pos = doc.resolve(pos)
const marks = $pos.marks()
- const linkMark = marks.find(m => m.type.name === 'link' && m.attrs.href === pastedUrl)
-
+ const linkMark = marks.find(
+ (m) => m.type.name === 'link' && m.attrs.href === pastedUrl
+ )
+
if (linkMark) {
// Found the link, now find its boundaries
linkStart = pos
-
+
// Find the end of the link
- for (let endPos = pos; endPos < Math.min(doc.content.size, pos + pastedUrl.length + 5); endPos++) {
+ for (
+ let endPos = pos;
+ endPos < Math.min(doc.content.size, pos + pastedUrl.length + 5);
+ endPos++
+ ) {
const $endPos = doc.resolve(endPos)
- const hasLink = $endPos.marks().some(m => m.type.name === 'link' && m.attrs.href === pastedUrl)
+ const hasLink = $endPos
+ .marks()
+ .some((m) => m.type.name === 'link' && m.attrs.href === pastedUrl)
if (hasLink) {
linkEnd = endPos + 1
} else {
@@ -225,7 +247,7 @@ export const UrlEmbed = Node.create({
// Position might be invalid, continue
}
}
-
+
if (linkStart !== -1) {
// Store the pasted URL info with correct position
const tr = state.tr.setMeta('urlEmbedPaste', {
@@ -233,7 +255,7 @@ export const UrlEmbed = Node.create({
lastPastedPos: linkStart
})
view.dispatch(tr)
-
+
// Notify the editor to show dropdown
if (options.onShowDropdown) {
options.onShowDropdown(linkStart, pastedUrl)
@@ -251,4 +273,4 @@ export const UrlEmbed = Node.create({
})
]
}
-})
\ No newline at end of file
+})
diff --git a/src/lib/components/edra/extensions/url-embed/UrlEmbedExtended.ts b/src/lib/components/edra/extensions/url-embed/UrlEmbedExtended.ts
index 9edec3f..f41154f 100644
--- a/src/lib/components/edra/extensions/url-embed/UrlEmbedExtended.ts
+++ b/src/lib/components/edra/extensions/url-embed/UrlEmbedExtended.ts
@@ -49,4 +49,4 @@ export const UrlEmbedExtended = (component: any) =>
addNodeView() {
return SvelteNodeViewRenderer(component)
}
- })
\ No newline at end of file
+ })
diff --git a/src/lib/components/edra/extensions/url-embed/UrlEmbedPlaceholder.ts b/src/lib/components/edra/extensions/url-embed/UrlEmbedPlaceholder.ts
index 8ce71f0..2c81ff4 100644
--- a/src/lib/components/edra/extensions/url-embed/UrlEmbedPlaceholder.ts
+++ b/src/lib/components/edra/extensions/url-embed/UrlEmbedPlaceholder.ts
@@ -32,4 +32,4 @@ export const UrlEmbedPlaceholder = (component: any) =>
addNodeView() {
return SvelteNodeViewRenderer(component)
}
- })
\ No newline at end of file
+ })
diff --git a/src/lib/components/edra/headless/components/EmbedContextMenu.svelte b/src/lib/components/edra/headless/components/EmbedContextMenu.svelte
index d76bc5c..3d4ca3e 100644
--- a/src/lib/components/edra/headless/components/EmbedContextMenu.svelte
+++ b/src/lib/components/edra/headless/components/EmbedContextMenu.svelte
@@ -1,7 +1,7 @@