diff --git a/README.md b/README.md index 1ccacee8..322bf15b 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,11 @@ npm install --save-dev svelte-highlight typescript-svelte-plugin npm install flowbite flowbite-svelte tailwind-merge @popperjs/core ``` +More packages related to the Tiptap editor +```bash +npm install @tiptap/extension-link @tiptap/extension-bullet-list @tiptap/extension-history @tiptap/extension-typography @tiptap/extension-underline +``` + ## Build ## Environment file diff --git a/package-lock.json b/package-lock.json index f6859a14..95947a60 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "@tiptap/extension-paragraph": "^2.10.2", "@tiptap/extension-text": "^2.10.2", "@tiptap/extension-typography": "^2.10.2", + "@tiptap/extension-underline": "^2.10.3", "@tiptap/pm": "^2.10.2", "@tiptap/starter-kit": "^2.10.2", "axios": "^1.7.0", @@ -1728,6 +1729,19 @@ "@tiptap/core": "^2.7.0" } }, + "node_modules/@tiptap/extension-underline": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-2.10.3.tgz", + "integrity": "sha512-VeGs0jeNiTnXddHHJEgOc/sKljZiyTEgSSuqMmsBACrr9aGFXbLTgKTvNjkZ9WzSnu7LwgJuBrwEhg8yYixUyQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, "node_modules/@tiptap/pm": { "version": "2.10.2", "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.10.2.tgz", diff --git a/package.json b/package.json index b4038caf..5d2226a4 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "@tiptap/extension-paragraph": "^2.10.2", "@tiptap/extension-text": "^2.10.2", "@tiptap/extension-typography": "^2.10.2", + "@tiptap/extension-underline": "^2.10.3", "@tiptap/pm": "^2.10.2", "@tiptap/starter-kit": "^2.10.2", "axios": "^1.7.0", diff --git a/src/lib/ae_events/ae_events__event.ts b/src/lib/ae_events/ae_events__event.ts index b285d012..65371122 100644 --- a/src/lib/ae_events/ae_events__event.ts +++ b/src/lib/ae_events/ae_events__event.ts @@ -331,7 +331,7 @@ export async function qry_ae_obj_li__event( } -// Updated 2024-09-25 +// Updated 2024-12-02 export async function create_ae_obj__event( { api_cfg, @@ -371,7 +371,8 @@ export async function create_ae_obj__event( db_save_ae_obj_li__event( { obj_type: 'event', - obj_li: [event_obj_create_result] + obj_li: [event_obj_create_result], + log_lvl: log_lvl }); } return event_obj_create_result; diff --git a/src/lib/element_tiptap_editor.scss b/src/lib/element_tiptap_editor.scss index 7ad642cc..9e2a54c9 100644 --- a/src/lib/element_tiptap_editor.scss +++ b/src/lib/element_tiptap_editor.scss @@ -1,102 +1,113 @@ /* Basic editor styles */ .tiptap { -:first-child { - margin-top: 0; -} - -/* List styles */ -ul { - list-style-type: disc; - margin-left: 1.5rem; - // border: solid thin red; -} -ol { - list-style-type: decimal; - margin-left: 1.5rem; - // border: solid thin red; -} - -ul, -ol { - padding: 0 1rem; - margin: 1.25rem 1rem 1.25rem 0.4rem; - - li p { - margin-top: 0.25em; - margin-bottom: 0.25em; + :first-child { + margin-top: 0; } -} -/* Heading styles */ -h1, -h2, -h3, -h4, -h5, -h6 { - line-height: 1.1; - margin-top: 2.5rem; - text-wrap: pretty; -} + /* Link styles */ + a { + color: var(--purple); + cursor: pointer; + text-decoration: underline; -h1, -h2 { - margin-top: 3.5rem; - margin-bottom: 1.5rem; -} + &:hover { + color: var(--purple-contrast); + } + } -h1 { - font-size: 1.4rem; -} + /* List styles */ + ul { + list-style-type: disc; + margin-left: 1.5rem; + // border: solid thin red; + } + ol { + list-style-type: decimal; + margin-left: 1.5rem; + // border: solid thin red; + } -h2 { - font-size: 1.2rem; -} + ul, + ol { + padding: 0 1rem; + margin: 1.25rem 1rem 1.25rem 0.4rem; -h3 { - font-size: 1.1rem; -} + li p { + margin-top: 0.25em; + margin-bottom: 0.25em; + } + } -h4, -h5, -h6 { - font-size: 1rem; -} + /* Heading styles */ + h1, + h2, + h3, + h4, + h5, + h6 { + line-height: 1.1; + margin-top: 2.5rem; + text-wrap: pretty; + } -/* Code and preformatted text styles */ -code { - background-color: var(--purple-light); - border-radius: 0.4rem; - color: var(--black); - font-size: 0.85rem; - padding: 0.25em 0.3em; -} + h1, + h2 { + margin-top: 3.5rem; + margin-bottom: 1.5rem; + } -pre { - background: var(--black); - border-radius: 0.5rem; - color: var(--white); - font-family: 'JetBrainsMono', monospace; - margin: 1.5rem 0; - padding: 0.75rem 1rem; + h1 { + font-size: 1.4rem; + } + h2 { + font-size: 1.2rem; + } + + h3 { + font-size: 1.1rem; + } + + h4, + h5, + h6 { + font-size: 1rem; + } + + /* Code and preformatted text styles */ code { - background: none; - color: inherit; - font-size: 0.8rem; - padding: 0; + background-color: var(--purple-light); + border-radius: 0.4rem; + color: var(--black); + font-size: 0.85rem; + padding: 0.25em 0.3em; } -} -blockquote { - border-left: 3px solid var(--gray-3); - margin: 1.5rem 0; - padding-left: 1rem; -} + pre { + background: var(--black); + border-radius: 0.5rem; + color: var(--white); + font-family: 'JetBrainsMono', monospace; + margin: 1.5rem 0; + padding: 0.75rem 1rem; -hr { - border: none; - border-top: 1px solid var(--gray-2); - margin: 2rem 0; -} + code { + background: none; + color: inherit; + font-size: 0.8rem; + padding: 0; + } + } + + blockquote { + border-left: 3px solid var(--gray-3); + margin: 1.5rem 0; + padding-left: 1rem; + } + + hr { + border: none; + border-top: 1px solid var(--gray-2); + margin: 2rem 0; + } } \ No newline at end of file diff --git a/src/lib/element_tiptap_editor.svelte b/src/lib/element_tiptap_editor.svelte index d2484e28..d21e4c60 100644 --- a/src/lib/element_tiptap_editor.svelte +++ b/src/lib/element_tiptap_editor.svelte @@ -24,6 +24,7 @@ import Strike from '@tiptap/extension-strike'; import Text from '@tiptap/extension-text'; import TextStyle from '@tiptap/extension-text-style'; import Typography from '@tiptap/extension-typography'; +import Underline from '@tiptap/extension-underline'; import "./element_tiptap_editor.scss"; @@ -125,10 +126,11 @@ onMount(() => { CodeBlock, // part of StarterKit Italic, // part of StarterKit Strike, // part of StarterKit + Underline, // part of StarterKit BulletList, // part of StarterKit - Color.configure({ types: [TextStyle.name, ListItem.name] }), - TextStyle.configure({ types: [ListItem.name] }), - Heading.configure({ levels: [1, 2, 3, 4, 5, 6] }), + // Color.configure({ types: [TextStyle.name, ListItem.name] }), + // TextStyle.configure({ types: [ListItem.name] }), + // Heading.configure({ levels: [1, 2, 3, 4, 5, 6] }), Highlight, History.configure({ depth: 100, @@ -141,56 +143,56 @@ onMount(() => { protocols: ['http', 'https'], isAllowedUri: (url, ctx) => { try { - // construct URL - const parsedUrl = url.includes(':') ? new URL(url) : new URL(`${ctx.defaultProtocol}://${url}`) + // construct URL + const parsedUrl = url.includes(':') ? new URL(url) : new URL(`${ctx.defaultProtocol}://${url}`) - // use default validation - if (!ctx.defaultValidate(parsedUrl.href)) { + // use default validation + if (!ctx.defaultValidate(parsedUrl.href)) { + return false + } + + // disallowed protocols + const disallowedProtocols = ['ftp', 'file', 'mailto'] + const protocol = parsedUrl.protocol.replace(':', '') + + if (disallowedProtocols.includes(protocol)) { + return false + } + + // only allow protocols specified in ctx.protocols + const allowedProtocols = ctx.protocols.map(p => (typeof p === 'string' ? p : p.scheme)) + + if (!allowedProtocols.includes(protocol)) { + return false + } + + // disallowed domains + const disallowedDomains = ['example-phishing.com', 'malicious-site.net'] + const domain = parsedUrl.hostname + + if (disallowedDomains.includes(domain)) { + return false + } + + // all checks have passed + return true + } catch (error) { return false } - - // disallowed protocols - const disallowedProtocols = ['ftp', 'file', 'mailto'] - const protocol = parsedUrl.protocol.replace(':', '') - - if (disallowedProtocols.includes(protocol)) { - return false - } - - // only allow protocols specified in ctx.protocols - const allowedProtocols = ctx.protocols.map(p => (typeof p === 'string' ? p : p.scheme)) - - if (!allowedProtocols.includes(protocol)) { - return false - } - - // disallowed domains - const disallowedDomains = ['example-phishing.com', 'malicious-site.net'] - const domain = parsedUrl.hostname - - if (disallowedDomains.includes(domain)) { - return false - } - - // all checks have passed - return true - } catch (error) { - return false - } }, shouldAutoLink: url => { try { - // construct URL - const parsedUrl = url.includes(':') ? new URL(url) : new URL(`https://${url}`) + // construct URL + const parsedUrl = url.includes(':') ? new URL(url) : new URL(`https://${url}`) - // only auto-link if the domain is not in the disallowed list - const disallowedDomains = ['example-no-autolink.com', 'another-no-autolink.com'] - const domain = parsedUrl.hostname + // only auto-link if the domain is not in the disallowed list + const disallowedDomains = ['example-no-autolink.com', 'another-no-autolink.com'] + const domain = parsedUrl.hostname - return !disallowedDomains.includes(domain) - } catch (error) { - return false - } + return !disallowedDomains.includes(domain) + } catch (error) { + return false + } }, }), ListItem, @@ -201,18 +203,20 @@ onMount(() => { Typography, ], content: html_text, - onTransaction: () => { + onTransaction: ({ editor, transaction }) => { + // console.log('onTransaction'); // force re-render so `editor.isActive` works as expected - editor = editor; + // editor = editor; - let updated_html = editor.getHTML(); - if (updated_html == '
') { - new_html = ''; - } else { - new_html = updated_html; - } + // let updated_html = editor.getHTML(); + // if (updated_html == '') { + // new_html = ''; + // } else { + // new_html = updated_html; + // } }, onUpdate: ({ editor }) => { + console.log('onUpdate', editor.getHTML()); let updated_html = editor.getHTML(); if (updated_html == '') { new_html = ''; diff --git a/src/routes/idaa/(idaa)/bb/ae_idaa_comp__post_comment_obj_id_edit.svelte b/src/routes/idaa/(idaa)/bb/ae_idaa_comp__post_comment_obj_id_edit.svelte index 7d307723..ea64b79b 100644 --- a/src/routes/idaa/(idaa)/bb/ae_idaa_comp__post_comment_obj_id_edit.svelte +++ b/src/routes/idaa/(idaa)/bb/ae_idaa_comp__post_comment_obj_id_edit.svelte @@ -330,7 +330,7 @@ function send_poster_notification_email() {{@html $lq__event_obj?.description}