From cd23a61b907e30a58a0f34046a6ce8ea7013dc25 Mon Sep 17 00:00:00 2001 From: "@s.roertgen" Date: Wed, 23 Apr 2025 10:22:21 +0200 Subject: [PATCH] Add markdown rendering and improve styling a bit --- package-lock.json | 112 ++++++++++++++++++++++ package.json | 2 + src/lib/components/Board.svelte | 117 ++--------------------- src/lib/components/Card.svelte | 17 ++++ src/lib/components/Column.svelte | 76 +++++++++++++++ src/lib/components/MarkdownEditor.svelte | 5 +- src/lib/db.js | 30 ++++-- src/lib/icons/PlusCircleFill.svelte | 11 +++ src/routes/board/[id]/+page.svelte | 1 - 9 files changed, 251 insertions(+), 120 deletions(-) create mode 100644 src/lib/components/Card.svelte create mode 100644 src/lib/components/Column.svelte create mode 100644 src/lib/icons/PlusCircleFill.svelte diff --git a/package-lock.json b/package-lock.json index bd9c009..d6c2092 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,11 @@ "name": "educards", "version": "0.0.1", "dependencies": { + "@cartamd/plugin-emoji": "^4.3.0", "@nostr-dev-kit/ndk": "^2.11.0", "@tailwindcss/vite": "^4.1.4", "carta-md": "^4.9.0", + "marked": "^15.0.9", "tailwindcss": "^4.1.4" }, "devDependencies": { @@ -46,6 +48,19 @@ "node": ">=6.0.0" } }, + "node_modules/@cartamd/plugin-emoji": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@cartamd/plugin-emoji/-/plugin-emoji-4.3.0.tgz", + "integrity": "sha512-D73qZP/55er1b08CVmBA385omOY9/88zwB1JKBdhEFmOZzYfwr42GiyGHcHpcRinKe/MiaWV4k8vEYj461/wOQ==", + "dependencies": { + "bezier-easing": "^2.1.0", + "node-emoji": "^2.1.3", + "remark-emoji": "^5.0.0" + }, + "peerDependencies": { + "carta-md": "^4.0.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.24.2", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", @@ -1215,6 +1230,17 @@ "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==" }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, "node_modules/@sveltejs/adapter-vercel": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/@sveltejs/adapter-vercel/-/adapter-vercel-5.6.1.tgz", @@ -1766,6 +1792,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/bezier-easing": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bezier-easing/-/bezier-easing-2.1.0.tgz", + "integrity": "sha512-gbIqZ/eslnUFC1tjEvtz0sgx+xTK20wDnYMIA27VA04R7w6xxXQPZDbibjA9DTWZRA2CXtwHykkVzlCaAJAZig==" + }, "node_modules/bindings": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", @@ -1837,6 +1868,14 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "engines": { + "node": ">=10" + } + }, "node_modules/character-entities": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", @@ -2084,6 +2123,20 @@ "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz", "integrity": "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==" }, + "node_modules/emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==" + }, + "node_modules/emoticon": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-4.1.0.tgz", + "integrity": "sha512-VWZfnxqwNcc51hIy/sbOdEem6D+cVtpPzEEtVAFdaas30+1dgkyaOQ4sQ6Bp0tOMqWO1v+HQfYaoodOkdhK6SQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/enhanced-resolve": { "version": "5.18.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", @@ -3133,6 +3186,17 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/marked": { + "version": "15.0.9", + "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.9.tgz", + "integrity": "sha512-9AW/bn9DxQeZVjR52l5jsc0W2pwuhP04QaQewPvylil12Cfr2GBfWmgp6mu8i9Jy8UlBjqDZ9uMTDuJ8QOGZJA==", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/mdast-util-find-and-replace": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", @@ -3972,6 +4036,20 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/node-emoji": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz", + "integrity": "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==", + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -4541,6 +4619,21 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remark-emoji": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-5.0.1.tgz", + "integrity": "sha512-QCqTSvcZ65Ym+P+VyBKd4JfJfh7icMl7cIOGVmPMzWkDtdD8pQ0nQG7yxGolVIiMzSx90EZ7SwNiVpYpfTxn7w==", + "dependencies": { + "@types/mdast": "^4.0.4", + "emoticon": "^4.0.1", + "mdast-util-find-and-replace": "^3.0.1", + "node-emoji": "^2.1.3", + "unified": "^11.0.4" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/remark-gfm": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", @@ -4800,6 +4893,17 @@ "node": ">=18" } }, + "node_modules/skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "dependencies": { + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -5176,6 +5280,14 @@ "resolved": "https://registry.npmjs.org/typescript-lru-cache/-/typescript-lru-cache-2.0.0.tgz", "integrity": "sha512-Jp57Qyy8wXeMkdNuZiglE6v2Cypg13eDA1chHwDG6kq51X7gk4K7P7HaDdzZKCxkegXkVHNcPD0n5aW6OZH3aA==" }, + "node_modules/unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", + "engines": { + "node": ">=4" + } + }, "node_modules/unified": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", diff --git a/package.json b/package.json index 65bb49a..e580c0f 100644 --- a/package.json +++ b/package.json @@ -34,9 +34,11 @@ "vite": "^6.0.0" }, "dependencies": { + "@cartamd/plugin-emoji": "^4.3.0", "@nostr-dev-kit/ndk": "^2.11.0", "@tailwindcss/vite": "^4.1.4", "carta-md": "^4.9.0", + "marked": "^15.0.9", "tailwindcss": "^4.1.4" } } diff --git a/src/lib/components/Board.svelte b/src/lib/components/Board.svelte index bf6a2d6..8656888 100644 --- a/src/lib/components/Board.svelte +++ b/src/lib/components/Board.svelte @@ -1,23 +1,18 @@
-

{eventTitle($currentBoard)}

- {#if userAndBoardMatch($user, $currentBoard)} +

{eventTitle($currentBoard)}

+ {#if $user && userAndBoardMatch($user, $currentBoard)} {/if}
{#each items as column (column.id)} -
- {#if column !== undefined} -
-
{column.dTag}
- {#if userAndBoardMatch($user, $currentBoard)} - - {/if} -
-
- {#if userAndBoardMatch($user, $currentBoard)} - - {/if} -
- - {#if column.items.every((e) => e !== undefined)} -
handleDndConsiderCards(column.id, e)} - on:finalize={(e) => handleDndFinalizeCards(column.id, e)} - > - - {#each column.items as item (item?.id ?? item)} -
- {eventTitle(item)} - {item.content} - -
- {/each} -
- {/if} - {/if} +
+
{/each}
- diff --git a/src/lib/components/Card.svelte b/src/lib/components/Card.svelte new file mode 100644 index 0000000..52c8b5f --- /dev/null +++ b/src/lib/components/Card.svelte @@ -0,0 +1,17 @@ + + +
+

{eventTitle(card)}

+

{@html marked.parse(card.content)}

+ +
diff --git a/src/lib/components/Column.svelte b/src/lib/components/Column.svelte new file mode 100644 index 0000000..7a173b9 --- /dev/null +++ b/src/lib/components/Column.svelte @@ -0,0 +1,76 @@ + + +{#if column !== undefined} +
+
+

{eventTitle(column)}

+
+ {#if userAndBoardMatch($user, $currentBoard)} + + {/if} +
+
+ {#if userAndBoardMatch($user, $currentBoard)} + + {/if} +
+ + {#if column.items.every((e) => e !== undefined)} +
handleDndConsiderCards(column.id, e)} + on:finalize={(e) => handleDndFinalizeCards(column.id, e)} + > + {#each column.items as item (item?.id ?? item)} +
+ +
+ {/each} +
+ {/if} +{/if} + + diff --git a/src/lib/components/MarkdownEditor.svelte b/src/lib/components/MarkdownEditor.svelte index 8e1e57c..431bee1 100644 --- a/src/lib/components/MarkdownEditor.svelte +++ b/src/lib/components/MarkdownEditor.svelte @@ -1,9 +1,12 @@ diff --git a/src/lib/db.js b/src/lib/db.js index 49af0c5..fb0f0dd 100644 --- a/src/lib/db.js +++ b/src/lib/db.js @@ -10,12 +10,15 @@ export const boards = derived(events, ($events) => { return deduped; }); export const currentBoardAddress = writable(''); -export const currentBoard = derived(currentBoardAddress, ($currentBoardAddress) => { - console.log('looking for current board'); - const board = get(events).find((e) => e.tagAddress() === $currentBoardAddress); - console.log(board); - return board; -}); +export const currentBoard = derived( + [currentBoardAddress, events], + ([$currentBoardAddress, $events]) => { + console.log('looking for current board'); + const board = get(events).find((e) => e.tagAddress() === $currentBoardAddress); + console.log(board); + return board; + } +); export const columns = derived(events, ($events) => { const allColumns = $events.filter((e) => e.kind === 30044); const deduped = deduplicateKeepMostRecent(allColumns); @@ -87,9 +90,9 @@ const createNDKStore = () => { // 'wss://relay.damus.io' // 'wss://relay.nostr.band', // 'wss://nos.lol', - // 'ws://localhost:10547' - 'wss://purplepag.es', - 'wss://relay-k12.edufeed.org' + 'ws://localhost:10547' + // 'wss://purplepag.es', + // 'wss://relay-k12.edufeed.org' // Add more default relays here ] ) => { @@ -170,3 +173,12 @@ function deduplicateKeepMostRecent(array) { }); return Array.from(mostRecentMap.values()); } + +export function userAndBoardMatch(user, board) { + return user !== undefined && board && user?.pubkey === board?.pubkey; +} + +export function deleteColumn(columnId) { + const updatedBoardItems = items.filter((e) => e.id !== columnId); + publishBoard({ ...$currentBoard, items: updatedBoardItems }); +} diff --git a/src/lib/icons/PlusCircleFill.svelte b/src/lib/icons/PlusCircleFill.svelte new file mode 100644 index 0000000..e182581 --- /dev/null +++ b/src/lib/icons/PlusCircleFill.svelte @@ -0,0 +1,11 @@ + + + diff --git a/src/routes/board/[id]/+page.svelte b/src/routes/board/[id]/+page.svelte index ed093ea..a99c945 100644 --- a/src/routes/board/[id]/+page.svelte +++ b/src/routes/board/[id]/+page.svelte @@ -3,7 +3,6 @@ import { currentBoardAddress } from '$lib/db.js'; export let data; - console.log(data.id); $currentBoardAddress = data.id;