From b35774b9a045f36eecea2ab95f129d72be51356b Mon Sep 17 00:00:00 2001 From: Silberengel Date: Mon, 12 May 2025 13:30:47 +0200 Subject: [PATCH] Interim changes --- .vscode/settings.json | 4 +- README.md | 57 +- package-lock.json | 206 ++++- package.json | 8 +- src/app.css | 705 ++++++++++++------ src/lib/components/EmoticonPicker.svelte | 80 ++ src/lib/components/EventLimitControl.svelte | 16 +- .../components/EventRenderLevelLimit.svelte | 11 +- src/lib/components/Login.svelte | 23 +- src/lib/components/LoginModal.svelte | 49 +- src/lib/components/MarkdownForm.svelte | 238 ++++++ src/lib/components/Navigation.svelte | 24 +- src/lib/components/Preview.svelte | 10 +- src/lib/components/Publication.svelte | 81 +- src/lib/components/PublicationFeed.svelte | 4 +- src/lib/components/PublicationHeader.svelte | 2 +- src/lib/components/PublicationSection.svelte | 4 +- src/lib/components/Toc.svelte | 8 +- src/lib/parser.ts | 8 +- src/lib/types/markdown-it-plugins.d.ts | 11 + src/lib/types/svelte-heros.d.ts | 4 + src/lib/utils/advancedMarkdownParser.ts | 378 ---------- src/lib/utils/basicMarkdownParser.ts | 182 ----- src/lib/utils/emoticons.ts | 85 +++ src/lib/utils/markdown/markdownItParser.ts | 391 ++++++++++ .../utils/{ => markdown}/markdownTestfile.md | 4 +- src/routes/[...catchall]/+page.svelte | 12 +- src/routes/about/+page.svelte | 123 +-- src/routes/contact/+page.svelte | 391 +++------- src/routes/contact/ContactForm.svelte | 125 ++++ src/routes/new/edit/+page.svelte | 38 +- src/routes/visualize/+page.svelte | 19 +- 32 files changed, 1984 insertions(+), 1317 deletions(-) create mode 100644 src/lib/components/EmoticonPicker.svelte create mode 100644 src/lib/components/MarkdownForm.svelte create mode 100644 src/lib/types/markdown-it-plugins.d.ts create mode 100644 src/lib/types/svelte-heros.d.ts delete mode 100644 src/lib/utils/advancedMarkdownParser.ts delete mode 100644 src/lib/utils/basicMarkdownParser.ts create mode 100644 src/lib/utils/emoticons.ts create mode 100644 src/lib/utils/markdown/markdownItParser.ts rename src/lib/utils/{ => markdown}/markdownTestfile.md (96%) create mode 100644 src/routes/contact/ContactForm.svelte diff --git a/.vscode/settings.json b/.vscode/settings.json index ce072c8..1d24f94 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,5 @@ { - "editor.tabSize": 2 + "editor.tabSize": 2, + "css.validate": false, + "tailwindCSS.validate": true } diff --git a/README.md b/README.md index 3248ab3..d7c27c7 100644 --- a/README.md +++ b/README.md @@ -114,4 +114,59 @@ npm run test For the Playwright end-to-end (e2e) tests: ```bash npx playwright test -``` \ No newline at end of file +``` + +## Markdown Support + +In addition to the [standard Asciidoc](https://asciidoc.org/) support for publication and wiki events, Alexandria supports a rich set of Markdown features for content creation: + +### Text Formatting +- **Bold**: `*text*` or `**text**` +- **Italic**: `_text_` or `__text__` +- **Strikethrough**: `~text~` or `~~text~~` +- **Inline Code**: `` `code` `` +- **Links**: `[text](url)` +- **Images**: `![alt](url)` + +### Structure +- **Headings**: + - ATX style: `# Heading 1` through `###### Heading 6` + - Setext style: + ```markdown + Heading 1 + ======== + ``` +- **Lists**: + - Unordered: `* item` + - Ordered: `1. item`, `2. item` + - Nested lists supported +- **Code Blocks with language-specific highlighting**: + ```markdown + ```javascript + const code = 'example'; + ``` + ``` +- **Blockquotes**: `> Quote text` +- **Horizontal Rules**: `---` +- **Tables**: + ```markdown + | Header 1 | Header 2 | + |----------|----------| + | Cell 1 | Cell 2 | + ``` + +### Special Features +- **Footnotes**: `[^1]` and `[^1]: definition` +- **Emojis**: `:smile:` +- **Hashtags**: `#tag` +- **Nostr Identifiers**: + - Profiles: `npub...` or `nprofile...` + - Notes: `note...`, `nevent...`, or `naddr...` + +### Media Support +- **YouTube Videos**: Automatically embedded +- **Video Files**: mp4, webm, mov, avi +- **Audio Files**: mp3, wav, ogg, m4a +- **Images**: jpg, jpeg, gif, png, webp + +All media URLs are automatically cleaned of tracking parameters for privacy. \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index deb52d2..98a4486 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,19 +15,25 @@ "@tailwindcss/typography": "0.5.x", "asciidoctor": "3.0.x", "d3": "^7.9.0", + "easymde": "^2.20.0", "he": "1.2.x", "highlight.js": "^11.11.1", - "nostr-tools": "2.10.x" + "markdown-it": "^14.1.0", + "markdown-it-emoji": "^3.0.0", + "markdown-it-footnote": "^4.0.0", + "nostr-tools": "2.10.x", + "svelte-heros": "^7.0.2" }, "devDependencies": { "@playwright/test": "^1.50.1", "@sveltejs/adapter-auto": "3.x", "@sveltejs/adapter-node": "^5.2.12", "@sveltejs/adapter-static": "3.x", - "@sveltejs/kit": "2.x", + "@sveltejs/kit": "^2.16.0", "@sveltejs/vite-plugin-svelte": "4.x", "@types/d3": "^7.4.3", "@types/he": "1.2.x", + "@types/markdown-it": "^14.1.2", "@types/node": "22.x", "autoprefixer": "10.x", "eslint-plugin-svelte": "2.x", @@ -65,7 +71,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -1526,6 +1531,15 @@ "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20" } }, + "node_modules/@types/codemirror": { + "version": "5.60.15", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.15.tgz", + "integrity": "sha512-dTOvwEQ+ouKJ/rE9LT1Ue2hmP6H1mZv5+CCnNWu2qtiOe2LQa9lCprEY20HxiDmV/Bxh+dXjywmy5aKvoGjULA==", + "license": "MIT", + "dependencies": { + "@types/tern": "*" + } + }, "node_modules/@types/cookie": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", @@ -1821,7 +1835,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true, "license": "MIT" }, "node_modules/@types/geojson": { @@ -1846,6 +1859,37 @@ "license": "MIT", "peer": true }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/marked": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.3.2.tgz", + "integrity": "sha512-a79Yc3TOk6dGdituy8hmTTJXjOkZ7zsFYV10L337ttq/rec8lRMDBpV7fL3uLx6TgbFCa5DU/h8FmIBQPSbU0w==", + "license": "MIT" + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "22.10.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", @@ -1863,6 +1907,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/tern": { + "version": "0.23.9", + "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz", + "integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/@vitest/expect": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.6.tgz", @@ -2003,7 +2056,6 @@ "version": "8.14.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", - "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -2026,7 +2078,6 @@ "version": "1.4.13", "resolved": "https://registry.npmjs.org/acorn-typescript/-/acorn-typescript-1.4.13.tgz", "integrity": "sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==", - "dev": true, "license": "MIT", "peerDependencies": { "acorn": ">=8.9.0" @@ -2131,15 +2182,12 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0", - "peer": true + "license": "Python-2.0" }, "node_modules/aria-query": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">= 0.4" @@ -2237,7 +2285,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">= 0.4" @@ -2520,6 +2567,21 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/codemirror": { + "version": "5.65.19", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.19.tgz", + "integrity": "sha512-+aFkvqhaAVr1gferNMuN8vkTSrWIFvzlMV9I2KBLCWS2WpZ2+UAkZjlMZmEuT+gcXTi6RrGQCkWq1/bDtGqhIA==", + "license": "MIT" + }, + "node_modules/codemirror-spell-checker": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/codemirror-spell-checker/-/codemirror-spell-checker-1.1.2.tgz", + "integrity": "sha512-2Tl6n0v+GJRsC9K3MLCdLaMOmvWL0uukajNJseorZJsslaxZyZMgENocPU8R0DyoTAiKsyqiemSOZo7kjGV0LQ==", + "license": "MIT", + "dependencies": { + "typo-js": "*" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3134,6 +3196,19 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "license": "MIT" }, + "node_modules/easymde": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/easymde/-/easymde-2.20.0.tgz", + "integrity": "sha512-V1Z5f92TfR42Na852OWnIZMbM7zotWQYTddNaLYZFVKj7APBbyZ3FYJ27gBw2grMW3R6Qdv9J8n5Ij7XRSIgXQ==", + "license": "MIT", + "dependencies": { + "@types/codemirror": "^5.60.10", + "@types/marked": "^4.0.7", + "codemirror": "^5.65.15", + "codemirror-spell-checker": "1.1.2", + "marked": "^4.1.0" + } + }, "node_modules/ejs": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", @@ -3162,6 +3237,18 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -3513,7 +3600,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", - "dev": true, "license": "MIT" }, "node_modules/esniff": { @@ -3568,7 +3654,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.3.2.tgz", "integrity": "sha512-C4PXusxYhFT98GjLSmb20k9PREuUdporer50dhzGuJu9IJXktbMddVCMLAERl5dAHyAi73GWWCE4FVHGP1794g==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" @@ -4339,7 +4424,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", - "dev": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.6" @@ -4553,11 +4637,19 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "license": "MIT" }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/locate-character": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", - "dev": true, "license": "MIT" }, "node_modules/locate-path": { @@ -4612,12 +4704,52 @@ "version": "0.30.17", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-it-emoji": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-emoji/-/markdown-it-emoji-3.0.0.tgz", + "integrity": "sha512-+rUD93bXHubA4arpEZO3q80so0qgoFJEKRkRbjKX8RTdca89v2kfyF+xR3i2sQTwql9tpPZPOQN5B+PunspXRg==", + "license": "MIT" + }, + "node_modules/markdown-it-footnote": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-footnote/-/markdown-it-footnote-4.0.0.tgz", + "integrity": "sha512-WYJ7urf+khJYl3DqofQpYfEYkZKbmXmwxQV8c8mO/hGIhgZ1wOe7R4HLFNwqx7TjILbnC98fuyeSsin19JdFcQ==", + "license": "MIT" + }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -4627,6 +4759,12 @@ "node": ">= 0.4" } }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "license": "MIT" + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -5550,6 +5688,15 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -6009,7 +6156,6 @@ "version": "5.14.4", "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.14.4.tgz", "integrity": "sha512-2iR/UHHA2Dsldo4JdXDcdqT+spueuh+uNYw1FoTKBbpnFEECVISeqSo0uubPS4AfBE0xI6u7DGHxcdq3DTDmoQ==", - "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.3.0", @@ -6160,6 +6306,19 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/svelte-heros": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/svelte-heros/-/svelte-heros-7.0.2.tgz", + "integrity": "sha512-JsnGvthDn2EJq+1JbRqebHnUIJTLMFtPJt7IpjdHoY2Ei24DQOdQ9QQDmFZ/7oUB6/d6Wwne4G+vnp4mvvYSDg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0", + "npm": ">=7.0.0" + }, + "peerDependencies": { + "svelte": "^5.0.0" + } + }, "node_modules/svg.draggable.js": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz", @@ -6522,6 +6681,18 @@ "integrity": "sha512-Jp57Qyy8wXeMkdNuZiglE6v2Cypg13eDA1chHwDG6kq51X7gk4K7P7HaDdzZKCxkegXkVHNcPD0n5aW6OZH3aA==", "license": "MIT" }, + "node_modules/typo-js": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/typo-js/-/typo-js-1.2.5.tgz", + "integrity": "sha512-F45vFWdGX8xahIk/sOp79z2NJs8ETMYsmMChm9D5Hlx3+9j7VnCyQyvij5MOCrNY3NNe8noSyokRjQRfq+Bc7A==", + "license": "BSD-3-Clause" + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" + }, "node_modules/uglify-js": { "version": "3.19.3", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", @@ -7023,7 +7194,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz", "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==", - "dev": true, "license": "MIT" } } diff --git a/package.json b/package.json index 3774cd4..812ae00 100644 --- a/package.json +++ b/package.json @@ -21,9 +21,14 @@ "@tailwindcss/typography": "0.5.x", "asciidoctor": "3.0.x", "d3": "^7.9.0", + "easymde": "^2.20.0", "he": "1.2.x", "highlight.js": "^11.11.1", - "nostr-tools": "2.10.x" + "markdown-it": "^14.1.0", + "markdown-it-emoji": "^3.0.0", + "markdown-it-footnote": "^4.0.0", + "nostr-tools": "2.10.x", + "svelte-heros": "^7.0.2" }, "devDependencies": { "@playwright/test": "^1.50.1", @@ -34,6 +39,7 @@ "@sveltejs/vite-plugin-svelte": "4.x", "@types/d3": "^7.4.3", "@types/he": "1.2.x", + "@types/markdown-it": "^14.1.2", "@types/node": "22.x", "autoprefixer": "10.x", "eslint-plugin-svelte": "2.x", diff --git a/src/app.css b/src/app.css index cbfbb43..fa7fc68 100644 --- a/src/app.css +++ b/src/app.css @@ -2,361 +2,610 @@ @import './styles/publications.css'; @import './styles/visualize.css'; -/* Custom styles */ +/* Base styles */ @layer base { - .leather { - @apply bg-primary-0 dark:bg-primary-1000 text-gray-800 dark:text-gray-200; + /* Common text colors and typography */ + .text-primary { + @apply text-gray-800 dark:text-gray-300; } - .btn-leather.text-xs { - @apply px-2 py-1; + .text-secondary { + @apply text-gray-600 dark:text-gray-400; } - .btn-leather.text-xs svg { - @apply h-3 w-3; + .text-sm-secondary { + @apply text-sm text-gray-600 dark:text-gray-400; } - .btn-leather.text-sm { - @apply px-3 py-2; + /* Common link styles */ + .link { + @apply underline cursor-pointer hover:text-primary-700 dark:hover:text-primary-400; } - .btn-leather.text-sm svg { - @apply h-4 w-4; + .link-secondary { + @apply text-gray-800 hover:text-primary-700 dark:text-gray-300 dark:hover:text-primary-400; } - div[role='tooltip'] button.btn-leather { - @apply hover:text-primary-400 dark:hover:text-primary-500 hover:border-primary-400 dark:hover:border-primary-500 hover:bg-gray-200 dark:hover:bg-gray-700; + /* Common container styles */ + .container-base { + @apply w-full flex justify-center; } - .image-border { - @apply border border-primary-700; + .container-main { + @apply main-leather flex flex-col space-y-4 max-w-2xl w-full my-6 px-4; } - div.card-leather { - @apply shadow-none text-primary-1000 border-s-4 bg-highlight border-primary-200 has-[:hover]:border-primary-700; - @apply dark:bg-primary-1000 dark:border-primary-800 dark:has-[:hover]:bg-primary-950 dark:has-[:hover]:border-primary-500; + .container-main-wide { + @apply container-main max-w-3xl; } - div.card-leather h1, - div.card-leather h2, - div.card-leather h3, - div.card-leather h4, - div.card-leather h5, - div.card-leather h6 { - @apply text-gray-800 hover:text-primary-400 dark:text-gray-300 dark:hover:text-primary-500; + /* Common form styles */ + .form-base { + @apply space-y-4 mt-6; } - div.card-leather .font-thin { - @apply text-gray-900 hover:text-primary-600 dark:text-gray-200 dark:hover:text-primary-200; + .form-input { + @apply w-full; } - main { - @apply max-w-full; + .form-textarea { + @apply w-full h-full resize-none border-0 focus:ring-0 bg-white dark:bg-gray-800 p-4; } - main.main-leather, - article.article-leather { - @apply bg-primary-0 dark:bg-primary-1000 text-gray-800 dark:text-gray-300; + .form-preview { + @apply absolute inset-0 p-4 prose dark:prose-invert max-w-none bg-white dark:bg-gray-800 prose-content; } - div.note-leather, - p.note-leather, - section.note-leather { - @apply bg-primary-0 dark:bg-primary-1000 text-gray-800 dark:text-gray-300 p-2 rounded; + /* Common button styles */ + .btn-base { + @apply btn-leather !w-fit; } - div.note-leather:hover:not(:has(.note-leather:hover)), - p.note-leather:hover:not(:has(.note-leather:hover)), - section.note-leather:hover:not(:has(.note-leather:hover)) { - @apply hover:bg-primary-100 dark:hover:bg-primary-800; + .btn-secondary { + @apply btn-base outline; } - h1.h-leather, - h2.h-leather, - h3.h-leather, - h4.h-leather, - h5.h-leather, - h6.h-leather { - @apply text-gray-800 dark:text-gray-300; + .btn-sm { + @apply text-sm px-3 py-2; } - h1.h-leather { - @apply text-4xl font-bold; + .btn-xs { + @apply text-xs px-2 py-1; } - h2.h-leather { - @apply text-3xl font-bold; + /* Common message styles */ + .message-base { + @apply p-4 mb-4 text-sm rounded-lg; } - h3.h-leather { - @apply text-2xl font-bold; + .message-success { + @apply message-base bg-success-200 dark:bg-success-700 border border-success-300 dark:border-success-600 relative; } - h4.h-leather { - @apply text-xl font-bold; + .message-error { + @apply message-base text-red-700 bg-red-100; } - h5.h-leather { - @apply text-lg font-semibold; + /* Common image styles */ + .image-container { + @apply flex flex-col items-center space-y-4 my-4; } - h6.h-leather { - @apply text-base font-semibold; + .image-bordered { + @apply border border-primary-700 rounded-lg; } - div.modal-leather>div { - @apply bg-primary-0 dark:bg-primary-950 border-b-[1px] border-primary-100 dark:border-primary-600; + /* Common heading styles */ + .heading-base { + @apply text-gray-800 dark:text-gray-300 font-bold; } - div.modal-leather>div>h1, - div.modal-leather>div>h2, - div.modal-leather>div>h3, - div.modal-leather>div>h4, - div.modal-leather>div>h5, - div.modal-leather>div>h6 { - @apply text-gray-800 hover:text-gray-800 dark:text-gray-300 dark:hover:text-gray-300; + .heading-1 { + @apply heading-base text-4xl; } - div.modal-leather button { - @apply bg-primary-0 hover:bg-primary-0 dark:bg-primary-950 dark:hover:bg-primary-950 text-gray-800 hover:text-primary-400 dark:text-gray-300 dark:hover:text-primary-500; + .heading-2 { + @apply heading-base text-3xl; } - nav.navbar-leather { - @apply bg-primary-0 dark:bg-primary-1000 z-10; + .heading-3 { + @apply heading-base text-2xl; } - nav.navbar-leather svg { - @apply fill-gray-800 hover:fill-primary-400 dark:fill-gray-300 dark:hover:fill-primary-500; + .heading-4 { + @apply heading-base text-xl; } - nav.navbar-leather h1, - nav.navbar-leather h2, - nav.navbar-leather h3, - nav.navbar-leather h4, - nav.navbar-leather h5, - nav.navbar-leather h6 { - @apply text-gray-800 hover:text-primary-400 dark:text-gray-300 dark:hover:text-primary-500; + .heading-5 { + @apply heading-base text-lg font-semibold; } - aside.sidebar-leather>div { - @apply bg-primary-0 dark:bg-primary-1000; + .heading-6 { + @apply heading-base text-base font-semibold; } - a.sidebar-item-leather { - @apply hover:bg-primary-100 dark:hover:bg-primary-800; + /* Update link colors for better contrast */ + .link { + @apply underline cursor-pointer hover:text-primary-700 dark:hover:text-primary-400; + } + + /* Update secondary text colors for better contrast */ + .text-gray-500 { + @apply text-gray-600 dark:text-gray-400; + } + + /* Update link colors in notes */ + .note-leather p a { + @apply underline hover:text-primary-700 dark:hover:text-primary-400; + } + + /* Update link colors in lists */ + .ol-leather li a, + .ul-leather li a { + @apply text-gray-800 hover:text-primary-700 dark:text-gray-300 dark:hover:text-primary-400; + } } - div.skeleton-leather div { - @apply bg-primary-100 dark:bg-primary-800; +/* Component styles */ +@layer components { + /* Page containers */ + .about-container, + .contact-container, + .edit-container, + .visualize-container, + .not-found-container { + @apply container-base; } - div.textarea-leather { - @apply bg-primary-0 dark:bg-primary-1000; + .about-main, + .contact-main { + @apply container-main-wide; } - div.textarea-leather>div:nth-child(1), - div.toolbar-leather { - @apply border-none; + .edit-main { + @apply container-main; } - div.textarea-leather>div:nth-child(2) { - @apply bg-primary-0 dark:bg-primary-1000; + /* About page */ + .about-header { + @apply flex justify-between items-center; } - div.textarea-leather, - div.textarea-leather textarea { - @apply text-gray-800 dark:text-gray-300; + .about-version { + @apply text-sm-secondary bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-nowrap; } - div.tooltip-leather { - @apply text-gray-800 dark:text-gray-300; + .about-image-container { + @apply image-container; } - div[role='tooltip'] button.btn-leather .tooltip-leather { - @apply bg-primary-100 dark:bg-primary-800; + .about-image { + @apply image-bordered; } - /* Network visualization */ - .network-link-leather { - @apply stroke-primary-200 fill-primary-200; + /* Contact page */ + .contact-form { + @apply form-base; } - .network-node-leather { - @apply stroke-primary-600; + .contact-form-input { + @apply form-input; } - .network-node-content { - @apply fill-primary-100; + .contact-form-textarea-container { + @apply relative border border-gray-300 dark:border-gray-600 rounded-lg transition-all duration-200 sm:w-[95vw] md:w-full; } -} -/* Utilities can be applied via the @apply directive. */ -@layer utilities { - .h-leather { - @apply text-gray-800 dark:text-gray-300 pt-4; + .contact-form-textarea-container.expanded { + @apply h-[800px]; } - .h1-leather { - @apply text-4xl font-bold; + .contact-form-textarea-container.collapsed { + @apply h-[200px]; } - .h2-leather { - @apply text-3xl font-bold; + .contact-form-tabs { + @apply flex flex-wrap -mb-px text-sm font-medium text-center; } - .h3-leather { - @apply text-2xl font-bold; + .contact-form-tab { + @apply inline-block p-4 rounded-t-lg; } - .h4-leather { - @apply text-xl font-bold; + .contact-form-tab.active { + @apply border-b-2 border-primary-600 text-primary-600; } - .h5-leather { - @apply text-lg font-semibold; + .contact-form-tab.inactive { + @apply hover:text-gray-600 hover:border-gray-300; } - .h6-leather { - @apply text-base font-semibold; + .contact-form-tab-content { + @apply absolute inset-0; } - /* Lists */ - .ol-leather li a, - .ul-leather li a { - @apply text-gray-800 hover:text-primary-400 dark:text-gray-300 dark:hover:text-primary-500; + .contact-form-textarea { + @apply form-textarea; } - .link { - @apply underline cursor-pointer hover:text-primary-400 dark:hover:text-primary-500; + .contact-form-preview { + @apply form-preview; } -} -@layer components { + .contact-form-toggle { + @apply absolute bottom-2 right-2 z-10 opacity-60 hover:opacity-100; + } + + .contact-form-actions { + @apply flex justify-end space-x-4; + } + + .contact-form-success { + @apply message-success; + } + + .contact-form-error { + @apply message-error; + } + + /* Edit page */ + .edit-preview-form { + @apply border border-gray-400 dark:border-gray-600 rounded-lg flex flex-col space-y-2 h-fit; + } + + .edit-preview-toolbar { + @apply toolbar-leather rounded-b-none bg-gray-200 dark:bg-gray-800; + } + + /* Visualize page */ + .visualize-header { + @apply flex items-center mb-4; + } + + .visualize-loading { + @apply flex justify-center items-center h-64; + } + + .visualize-error { + @apply message-error; + } + + .visualize-error-title { + @apply font-bold mb-2; + } + + .visualize-error-retry { + @apply btn-base text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:ring-red-300 dark:bg-red-600 dark:hover:bg-red-700 focus:outline-none dark:focus:ring-red-800; + } - /* Legend */ - .leather-legend { - @apply relative m-4 sm:m-0 sm:absolute sm:top-1 sm:left-1 flex-shrink-0 p-2 rounded; - @apply shadow-none text-primary-1000 border border-s-4 bg-highlight border-primary-200 has-[:hover]:border-primary-700; - @apply dark:bg-primary-1000 dark:border-primary-800 dark:has-[:hover]:bg-primary-950 dark:has-[:hover]:border-primary-500; + /* 404 page */ + .not-found-container { + @apply leather flex flex-col items-center justify-center min-h-screen text-center px-4; } - /* Tooltip */ - .tooltip-leather { - @apply fixed p-4 rounded shadow-lg bg-primary-0 dark:bg-primary-1000 text-gray-800 dark:text-gray-300 border border-gray-200 dark:border-gray-700 transition-colors duration-200; - max-width: 400px; - z-index: 1000; + .not-found-title { + @apply heading-1 mb-4; } - .leather-legend button { - @apply dark:text-white; + .not-found-message { + @apply text-secondary mb-6; } - /* Rendered publication content */ - .publication-leather { + .not-found-actions { + @apply flex space-x-4; + } + + .not-found-button { + @apply btn-base; + } + + /* Publication component styles */ + .publication-container { @apply flex flex-col space-y-4; + } - h1, - h2, - h3, - h4, - h5, - h6 { - @apply h-leather; - } + .publication-header { + @apply flex flex-col space-y-2; + } - h1 { - @apply h1-leather; - } + .publication-title { + @apply heading-1; + } - h2 { - @apply h2-leather; - } + .publication-metadata { + @apply text-sm-secondary; + } - h3 { - @apply h3-leather; - } + .publication-content { + @apply flex flex-col space-y-4; + } - h4 { - @apply h4-leather; - } + .publication-section { + @apply flex flex-col space-y-4; + } - h5 { - @apply h5-leather; - } + .publication-section-title { + @apply heading-2; + } - h6 { - @apply h6-leather; - } + .publication-section-content { + @apply text-secondary; + } - div { - @apply flex flex-col space-y-4; - } + /* Login component styles */ + .login-container { + @apply flex flex-col items-center justify-center min-h-screen p-4; + } - .olist { - @apply flex flex-col space-y-4; + .login-form { + @apply form-base w-full max-w-md; + } - ol { - @apply ol-leather list-decimal px-6 flex flex-col space-y-2; + .login-input { + @apply form-input; + } - li { - .paragraph { - @apply py-2; - } - } - } - } + .login-button { + @apply btn-base w-full; + } - .ulist { - @apply flex flex-col space-y-4; + .login-error { + @apply message-error; + } - ul { - @apply ul-leather list-disc px-6 flex flex-col space-y-2; + /* Modal component styles */ + .modal-container { + @apply fixed inset-0 z-50 overflow-y-auto; + } - li { - .paragraph { - @apply py-2; - } - } - } - } + .modal-backdrop { + @apply fixed inset-0 bg-black bg-opacity-50 transition-opacity; + } - a { - @apply link; - } + .modal-content { + @apply relative bg-white dark:bg-gray-800 rounded-lg shadow-xl mx-auto my-8 max-w-lg p-6; + } - .imageblock { - @apply flex flex-col items-center; + .modal-header { + @apply flex items-center justify-between mb-4; + } - .title { - @apply text-sm text-center; - } - } + .modal-title { + @apply heading-2; + } - .stemblock { - @apply bg-gray-100 dark:bg-gray-900 p-4 rounded-lg; - } + .modal-close { + @apply text-gray-400 hover:text-gray-500 dark:hover:text-gray-300; + } - .literalblock { - pre { - @apply text-wrap; - } - } + .modal-body { + @apply text-secondary; + } - table { - @apply w-full overflow-x-auto; + .modal-footer { + @apply flex justify-end space-x-4 mt-6; + } - caption { - @apply text-sm; - } + /* Navigation component styles */ + .nav-container { + @apply bg-primary-0 dark:bg-primary-1000 z-10; + } - thead, - tbody { + .nav-content { + @apply flex items-center justify-between p-4; + } - th, - td { - @apply border border-gray-200 dark:border-gray-700; - } - } - } + .nav-brand { + @apply heading-3; + } + + .nav-links { + @apply flex items-center space-x-4; + } + + .nav-link { + @apply link-secondary; + } + + /* Table of Contents styles */ + .toc-container { + @apply fixed top-4 left-4 z-40 bg-white dark:bg-gray-800 rounded-lg shadow-lg p-4 max-w-xs; + } + + .toc-title { + @apply heading-3 mb-2; + } + + .toc-list { + @apply space-y-2; + } + + .toc-item { + @apply link-secondary text-sm; + } + + /* Event control styles */ + .event-control-container { + @apply flex items-center space-x-4 p-4 bg-gray-100 dark:bg-gray-800 rounded-lg; + } + + .event-control-label { + @apply text-sm-secondary; + } + + .event-control-input { + @apply form-input max-w-24; + } + + /* Preview component styles */ + .preview-container { + @apply flex flex-col space-y-4; + } + + .preview-header { + @apply flex items-center justify-between; + } + + .preview-title { + @apply heading-2; + } + + .preview-content { + @apply text-secondary; + } + + /* Publication Feed styles */ + .feed-container { + @apply flex flex-col space-y-4; + } + + .feed-header { + @apply flex items-center justify-between; + } + + .feed-title { + @apply heading-2; + } + + .feed-list { + @apply grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4; + } + + .feed-item { + @apply card-leather p-4; + } + + .feed-item-title { + @apply heading-3; + } + + .feed-item-metadata { + @apply text-sm-secondary mt-2; + } + } + +/* Keep existing utility classes */ +@layer utilities { + .h-leather { + @apply text-gray-800 dark:text-gray-300 pt-4; + } + + .h1-leather { + @apply text-4xl font-bold; + } + + .h2-leather { + @apply text-3xl font-bold; + } + + .h3-leather { + @apply text-2xl font-bold; + } + + .h4-leather { + @apply text-xl font-bold; + } + + .h5-leather { + @apply text-lg font-semibold; + } + + .h6-leather { + @apply text-base font-semibold; + } + + /* Lists */ + .ol-leather li a, + .ul-leather li a { + @apply text-gray-800 hover:text-primary-400 dark:text-gray-300 dark:hover:text-primary-500; } + + .link { + @apply underline cursor-pointer hover:text-primary-400 dark:hover:text-primary-500; + } + + .avatar-small { + @apply w-6 h-6 cursor-pointer; + } + + .toc-toggle-btn { + @apply fixed top-20 left-4 h-6 w-6; + } + + .no-padding { + @apply p-0; + } + + .flex { @apply flex; } + .flex-col { @apply flex-col; } + .flex-row { @apply flex-row; } + .space-x-2 { @apply space-x-2; } + .space-y-2 { @apply space-y-2; } + .justify-between { @apply justify-between; } + .justify-end { @apply justify-end; } + .justify-start { @apply justify-start; } + .w-full { @apply w-full; } + .min-w-fit { @apply min-w-fit; } + .visible { @apply visible; } + .invisible { @apply invisible; } + .break-words { @apply break-words; } + .text-wrap { @apply text-wrap; } + .whitespace-normal { @apply whitespace-normal; } + + .w-lg { @apply w-[32rem]; } + .col { @apply flex-col; } + .align-middle { @apply align-middle; } + .max-h-36 { @apply max-h-36; } + .max-w-24 { @apply max-w-24; } + .overflow-hidden { @apply overflow-hidden; } + .rounded { @apply rounded; } + .object-cover { @apply object-cover; } + .text-lg { @apply text-lg; } + .text-base { @apply text-base; } + .font-bold { @apply font-bold; } + .font-normal { @apply font-normal; } + .font-thin { @apply font-thin; } + .line-clamp-2 { @apply line-clamp-2; } + + .mb-2 { @apply mb-2; } + .mb-3 { @apply mb-3; } + .mt-4 { @apply mt-4; } + .mr-2 { @apply mr-2; } + .flex-1 { @apply flex-1; } + .min-h-0 { @apply min-h-0; } + .relative { @apply relative; } + .border-b { @apply border-b; } + .border-gray-300 { @apply border-gray-300; } + .dark\:border-gray-600 { @apply dark:border-gray-600; } + .text-gray-500 { @apply text-gray-500; } + .text-red-500 { @apply text-red-500; } + + .w-5 { @apply w-5; } + .h-5 { @apply h-5; } + .items-center { @apply items-center; } + .font-semibold { @apply font-semibold; } + .mt-1 { @apply mt-1; } + .hover\:underline:hover { @apply underline; } + .text-primary-600 { @apply text-primary-600; } + .dark\:text-primary-500 { @apply dark:text-primary-500; } + .break-all { @apply break-all; } + .text-sm { @apply text-sm; } + .list-disc { @apply list-disc; } + .list-inside { @apply list-inside; } + .text-success-700 { @apply text-success-700; } + .dark\:text-success-300 { @apply dark:text-success-300; } + } + +.backdrop { + @apply fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50; + } +.Modal { + @apply bg-white dark:bg-gray-800 rounded-lg shadow-xl p-8 max-w-lg w-full; + } + +.toc { + @apply p-4 bg-white dark:bg-gray-800 rounded-lg shadow-lg max-w-xs mx-auto; + } +.toc-title { + text-align: center; } \ No newline at end of file diff --git a/src/lib/components/EmoticonPicker.svelte b/src/lib/components/EmoticonPicker.svelte new file mode 100644 index 0000000..77f8f82 --- /dev/null +++ b/src/lib/components/EmoticonPicker.svelte @@ -0,0 +1,80 @@ + + +
+ +
+ {#each filteredHeroicons as emoticon} + + {/each} +
+ + {#if showMore} +
+ {#each filteredUnicode as emoticon} + + {/each} +
+ {/if} +
+ + \ No newline at end of file diff --git a/src/lib/components/EventLimitControl.svelte b/src/lib/components/EventLimitControl.svelte index d8c28be..75324a9 100644 --- a/src/lib/components/EventLimitControl.svelte +++ b/src/lib/components/EventLimitControl.svelte @@ -29,23 +29,23 @@ } -
-