diff --git a/doc/settings_panel.org b/doc/settings_panel.org
new file mode 100644
index 0000000..3730929
--- /dev/null
+++ b/doc/settings_panel.org
@@ -0,0 +1,124 @@
+* Settings Panel Documentation
+
+** Overview
+The settings panel controls how events are fetched and displayed in the visualization. It has several sections that work together to create an efficient and user-friendly experience.
+
+** Event Types Configuration
+
+*** Purpose
+Controls which types of Nostr events are fetched and how many of each type.
+
+*** Key Event Types
+- *Kind 30040* (Index Events): Publication indices
+- *Kind 30041* (Content Events): Publication content
+- *Kind 30818* (Content Events): Alternative content format
+- *Kind 30023* (Content Events): Alternative content format
+
+*** How Limits Work
+Each event kind has a limit number that controls different things:
+
+**** For Kind 0 (Profiles)
+- Limit controls how many profiles to fetch from discovered pubkeys
+- These profiles are used for:
+ - Displaying names instead of pubkeys
+ - Showing profile pictures in tooltips
+ - When "People" tag anchors are selected, this limit controls how many people anchors to display
+
+**** For Kind 3 (Follow Lists)
+- =limit = 1=: Only fetch the current user's follow list
+- =limit > 1=: Fetch the user's follow list PLUS (limit-1) follow lists from people they follow
+- The depth selector controls traversal:
+ - =Direct= (0): Just the immediate follows
+ - =2 degrees= (1): Follows of follows
+ - =3 degrees= (2): Three levels deep
+
+**** For Kind 30040/30041/30818
+- Limit controls maximum number of these events to fetch
+
+** Tag Anchors
+
+*** What Are Tag Anchors?
+Tag anchors are special nodes in the graph that act as gravity points for events sharing common attributes. They help organize the visualization by grouping related content.
+
+*** Tag Types Available
+- *Hashtags* (t): Groups events by hashtag
+- *Authors*: Groups events by author
+- *People* (p): Shows people from follow lists as anchor points
+- *Event References* (e): Groups events that reference each other
+- *Titles*: Groups events by title
+- *Summaries*: Groups events by summary
+
+*** How People Tag Anchors Work
+When "People" is selected as the tag type:
+
+1. The system looks at all loaded follow lists (kind 3 events)
+2. Extracts all pubkeys (people) from those follow lists
+3. Creates tag anchors for those people (up to the kind 0 limit)
+4. Connects each person anchor to:
+ - Events they authored (where pubkey matches)
+ - Events where they're mentioned in "p" tags
+
+*** Display Limiting and Auto-Disable
+- Tag anchors are created for ALL discovered tags
+- But only displayed up to the configured limit
+- When > 20 tag anchors exist, they're all auto-disabled
+- Users can selectively enable specific anchors
+- The legend becomes scrollable for many anchors
+
+*** "Only show people with publications" Checkbox
+When checked (default):
+- Only shows people who have events in the current visualization
+
+When unchecked:
+- Shows ALL people from follow lists, even if they have no events displayed
+- Useful for seeing your complete social graph
+
+** Display Limits Section
+
+*** Max Publication Indices (30040)
+Controls display filtering for publication indices after they're fetched.
+
+*** Max Events per Index
+Limits how many content events to show per publication index.
+
+*** Fetch if not found
+When enabled, automatically fetches missing referenced events.
+
+** Graph Traversal Section
+
+*** Search through already fetched
+When enabled, tag expansion only searches through events already loaded (more efficient).
+
+*** Append mode
+When enabled, new fetches add to the existing graph instead of replacing it.
+
+** Current Implementation Questions
+
+1. *Profile Fetching*: Should we fetch profiles for:
+ - Only event authors?
+ - All pubkeys in follow lists?
+ - All pubkeys mentioned anywhere?
+
+2. *People Tag Anchors*: Should they connect to:
+ - Only events where the person is tagged with "p"?
+ - Events they authored?
+ - Both?
+
+3. *Display Limits*: Should limits control:
+ - How many to fetch from relays?
+ - How many to display (fetch all, display subset)?
+ - Both with separate controls?
+
+4. *Auto-disable Threshold*: Is 20 the right number for auto-disabling tag anchors?
+
+** Ideal User Flow
+
+1. User loads the visualization
+2. Their follow list is fetched (kind 3, limit 1)
+3. Profiles are fetched for people they follow (kind 0, respecting limit)
+4. Publications are fetched (kind 30040/30041/30818)
+5. User enables "People" tag anchors
+6. Sees their follows as anchor points
+7. Can see which follows have authored content
+8. Can selectively enable/disable specific people
+9. Can increase limits to see more content/people
diff --git a/package-lock.json b/package-lock.json
index f256933..f171292 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,13 +1,15 @@
{
"name": "alexandria",
- "version": "0.0.6",
+ "version": "0.0.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "alexandria",
- "version": "0.0.6",
+ "version": "0.0.2",
"dependencies": {
+ "@noble/curves": "^1.9.4",
+ "@noble/hashes": "^1.8.0",
"@nostr-dev-kit/ndk": "^2.14.32",
"@nostr-dev-kit/ndk-cache-dexie": "2.6.x",
"@popperjs/core": "2.11.x",
@@ -24,33 +26,34 @@
"qrcode": "^1.5.4"
},
"devDependencies": {
- "@playwright/test": "^1.50.1",
- "@sveltejs/adapter-auto": "3.x",
+ "@playwright/test": "^1.54.1",
+ "@sveltejs/adapter-auto": "^6.0.1",
"@sveltejs/adapter-node": "^5.2.13",
"@sveltejs/adapter-static": "3.x",
"@sveltejs/kit": "^2.25.0",
- "@sveltejs/vite-plugin-svelte": "5.x",
+ "@sveltejs/vite-plugin-svelte": "^6.1.0",
"@types/d3": "^7.4.3",
"@types/he": "1.2.x",
- "@types/node": "22.x",
+ "@types/mathjax": "^0.0.40",
+ "@types/node": "^24.0.15",
"@types/qrcode": "^1.5.5",
- "autoprefixer": "10.x",
- "eslint-plugin-svelte": "2.x",
+ "autoprefixer": "^10.4.21",
+ "eslint-plugin-svelte": "^3.11.0",
"flowbite": "2.x",
"flowbite-svelte": "0.48.x",
"flowbite-svelte-icons": "2.1.x",
"playwright": "^1.50.1",
- "postcss": "8.x",
+ "postcss": "^8.5.6",
"postcss-load-config": "6.x",
- "prettier": "3.x",
- "prettier-plugin-svelte": "3.x",
- "svelte": "5.x",
+ "prettier": "^3.6.2",
+ "prettier-plugin-svelte": "^3.4.0",
+ "svelte": "^5.36.8",
"svelte-check": "4.x",
- "tailwind-merge": "^3.3.0",
- "tailwindcss": "3.x",
+ "tailwind-merge": "^3.3.1",
+ "tailwindcss": "^3.4.17",
"tslib": "2.8.x",
- "typescript": "5.8.x",
- "vite": "6.x",
+ "typescript": "^5.8.3",
+ "vite": "^7.0.5",
"vitest": "^3.1.3"
}
},
@@ -585,6 +588,7 @@
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
"integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"eslint-visitor-keys": "^3.4.3"
},
@@ -603,6 +607,7 @@
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
@@ -615,6 +620,7 @@
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
"integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
"dev": true,
+ "license": "MIT",
"peer": true,
"engines": {
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
@@ -625,6 +631,7 @@
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz",
"integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==",
"dev": true,
+ "license": "Apache-2.0",
"peer": true,
"dependencies": {
"@eslint/object-schema": "^2.1.6",
@@ -640,6 +647,7 @@
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz",
"integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==",
"dev": true,
+ "license": "Apache-2.0",
"peer": true,
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -650,6 +658,7 @@
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz",
"integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==",
"dev": true,
+ "license": "Apache-2.0",
"peer": true,
"dependencies": {
"@types/json-schema": "^7.0.15"
@@ -663,6 +672,7 @@
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz",
"integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
"dev": true,
+ "license": "MIT",
"peer": true,
"dependencies": {
"ajv": "^6.12.4",
@@ -687,6 +697,7 @@
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.31.0.tgz",
"integrity": "sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==",
"dev": true,
+ "license": "MIT",
"peer": true,
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -700,6 +711,7 @@
"resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz",
"integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==",
"dev": true,
+ "license": "Apache-2.0",
"peer": true,
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -710,6 +722,7 @@
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.3.tgz",
"integrity": "sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==",
"dev": true,
+ "license": "Apache-2.0",
"peer": true,
"dependencies": {
"@eslint/core": "^0.15.1",
@@ -749,6 +762,7 @@
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
"integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
"dev": true,
+ "license": "Apache-2.0",
"peer": true,
"engines": {
"node": ">=18.18.0"
@@ -759,6 +773,7 @@
"resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz",
"integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==",
"dev": true,
+ "license": "Apache-2.0",
"peer": true,
"dependencies": {
"@humanfs/core": "^0.19.1",
@@ -773,6 +788,7 @@
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz",
"integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==",
"dev": true,
+ "license": "Apache-2.0",
"peer": true,
"engines": {
"node": ">=18.18"
@@ -787,6 +803,7 @@
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
"integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
"dev": true,
+ "license": "Apache-2.0",
"peer": true,
"engines": {
"node": ">=12.22"
@@ -801,6 +818,7 @@
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
"integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
"dev": true,
+ "license": "Apache-2.0",
"peer": true,
"engines": {
"node": ">=18.18"
@@ -1541,13 +1559,11 @@
}
},
"node_modules/@sveltejs/adapter-auto": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-3.3.1.tgz",
- "integrity": "sha512-5Sc7WAxYdL6q9j/+D0jJKjGREGlfIevDyHSQ2eNETHcB1TKlQWHcAo8AS8H1QdjNvSXpvOwNjykDUHPEAyGgdQ==",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-6.0.1.tgz",
+ "integrity": "sha512-mcWud3pYGPWM2Pphdj8G9Qiq24nZ8L4LB7coCUckUEy5Y7wOWGJ/enaZ4AtJTcSm5dNK1rIkBRoqt+ae4zlxcQ==",
"dev": true,
- "dependencies": {
- "import-meta-resolve": "^4.1.0"
- },
+ "license": "MIT",
"peerDependencies": {
"@sveltejs/kit": "^2.0.0"
}
@@ -1608,41 +1624,43 @@
}
},
"node_modules/@sveltejs/vite-plugin-svelte": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.1.1.tgz",
- "integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-6.1.0.tgz",
+ "integrity": "sha512-+U6lz1wvGEG/BvQyL4z/flyNdQ9xDNv5vrh+vWBWTHaebqT0c9RNggpZTo/XSPoHsSCWBlYaTlRX8pZ9GATXCw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1",
+ "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0-next.1",
"debug": "^4.4.1",
"deepmerge": "^4.3.1",
"kleur": "^4.1.5",
"magic-string": "^0.30.17",
- "vitefu": "^1.0.6"
+ "vitefu": "^1.1.1"
},
"engines": {
- "node": "^18.0.0 || ^20.0.0 || >=22"
+ "node": "^20.19 || ^22.12 || >=24"
},
"peerDependencies": {
"svelte": "^5.0.0",
- "vite": "^6.0.0"
+ "vite": "^6.3.0 || ^7.0.0"
}
},
"node_modules/@sveltejs/vite-plugin-svelte-inspector": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-4.0.1.tgz",
- "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-5.0.0.tgz",
+ "integrity": "sha512-iwQ8Z4ET6ZFSt/gC+tVfcsSBHwsqc6RumSaiLUkAurW3BCpJam65cmHw0oOlDMTO0u+PZi9hilBRYN+LZNHTUQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "debug": "^4.3.7"
+ "debug": "^4.4.1"
},
"engines": {
- "node": "^18.0.0 || ^20.0.0 || >=22"
+ "node": "^20.19 || ^22.12 || >=24"
},
"peerDependencies": {
- "@sveltejs/vite-plugin-svelte": "^5.0.0",
+ "@sveltejs/vite-plugin-svelte": "^6.0.0-next.0",
"svelte": "^5.0.0",
- "vite": "^6.0.0"
+ "vite": "^6.3.0 || ^7.0.0"
}
},
"node_modules/@tailwindcss/forms": {
@@ -1967,15 +1985,24 @@
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
"dev": true,
+ "license": "MIT",
"peer": true
},
+ "node_modules/@types/mathjax": {
+ "version": "0.0.40",
+ "resolved": "https://registry.npmjs.org/@types/mathjax/-/mathjax-0.0.40.tgz",
+ "integrity": "sha512-rHusx08LCg92WJxrsM3SPjvLTSvK5C+gealtSuhKbEOcUZfWlwigaFoPLf6Dfxhg4oryN5qP9Sj7zOQ4HYXINw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/node": {
- "version": "22.16.4",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.16.4.tgz",
- "integrity": "sha512-PYRhNtZdm2wH/NT2k/oAJ6/f2VD2N2Dag0lGlx2vWgMSJXGNmlce5MiTQzoWAiIJtso30mjnfQCOKVH+kAQC/g==",
+ "version": "24.0.15",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.15.tgz",
+ "integrity": "sha512-oaeTSbCef7U/z7rDeJA138xpG3NuKc64/rZ2qmUFkFJmnMsAPaluIifqyWd8hSSMxyP9oie3dLAqYPblag9KgA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "undici-types": "~6.21.0"
+ "undici-types": "~7.8.0"
}
},
"node_modules/@types/qrcode": {
@@ -2138,6 +2165,7 @@
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
"dev": true,
+ "license": "MIT",
"peerDependencies": {
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
@@ -2147,6 +2175,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
+ "license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
@@ -2234,6 +2263,7 @@
"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
},
"node_modules/aria-query": {
@@ -2461,6 +2491,7 @@
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true,
+ "license": "MIT",
"peer": true,
"engines": {
"node": ">=6"
@@ -2559,18 +2590,39 @@
}
},
"node_modules/chokidar": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
- "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
- "devOptional": true,
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "license": "MIT",
"dependencies": {
- "readdirp": "^4.0.1"
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
},
"engines": {
- "node": ">= 14.16.0"
+ "node": ">= 8.10.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/chokidar/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
}
},
"node_modules/cliui": {
@@ -3077,6 +3129,7 @@
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"dev": true,
+ "license": "MIT",
"peer": true
},
"node_modules/deepmerge": {
@@ -3262,6 +3315,7 @@
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true,
+ "license": "MIT",
"peer": true,
"engines": {
"node": ">=10"
@@ -3275,6 +3329,7 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.31.0.tgz",
"integrity": "sha512-QldCVh/ztyKJJZLr4jXNUByx3gR+TDYZCRXEktiZoUR3PGy4qCmSbkxcIle8GEwGpb5JBZazlaJ/CxLidXdEbQ==",
"dev": true,
+ "license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
@@ -3331,47 +3386,32 @@
}
}
},
- "node_modules/eslint-compat-utils": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz",
- "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==",
- "dev": true,
- "dependencies": {
- "semver": "^7.5.4"
- },
- "engines": {
- "node": ">=12"
- },
- "peerDependencies": {
- "eslint": ">=6.0.0"
- }
- },
"node_modules/eslint-plugin-svelte": {
- "version": "2.46.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.46.1.tgz",
- "integrity": "sha512-7xYr2o4NID/f9OEYMqxsEQsCsj4KaMy4q5sANaKkAb6/QeCjYFxRmDm2S3YC3A3pl1kyPZ/syOx/i7LcWYSbIw==",
+ "version": "3.11.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-3.11.0.tgz",
+ "integrity": "sha512-KliWlkieHyEa65aQIkRwUFfHzT5Cn4u3BQQsu3KlkJOs7c1u7ryn84EWaOjEzilbKgttT4OfBURA8Uc4JBSQIw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@eslint-community/eslint-utils": "^4.4.0",
- "@jridgewell/sourcemap-codec": "^1.4.15",
- "eslint-compat-utils": "^0.5.1",
+ "@eslint-community/eslint-utils": "^4.6.1",
+ "@jridgewell/sourcemap-codec": "^1.5.0",
"esutils": "^2.0.3",
- "known-css-properties": "^0.35.0",
- "postcss": "^8.4.38",
+ "globals": "^16.0.0",
+ "known-css-properties": "^0.37.0",
+ "postcss": "^8.4.49",
"postcss-load-config": "^3.1.4",
- "postcss-safe-parser": "^6.0.0",
- "postcss-selector-parser": "^6.1.0",
- "semver": "^7.6.2",
- "svelte-eslint-parser": "^0.43.0"
+ "postcss-safe-parser": "^7.0.0",
+ "semver": "^7.6.3",
+ "svelte-eslint-parser": "^1.3.0"
},
"engines": {
- "node": "^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://github.com/sponsors/ota-meshi"
},
"peerDependencies": {
- "eslint": "^7.0.0 || ^8.0.0-0 || ^9.0.0-0",
+ "eslint": "^8.57.1 || ^9.0.0",
"svelte": "^3.37.0 || ^4.0.0 || ^5.0.0"
},
"peerDependenciesMeta": {
@@ -3380,6 +3420,19 @@
}
}
},
+ "node_modules/eslint-plugin-svelte/node_modules/globals": {
+ "version": "16.3.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-16.3.0.tgz",
+ "integrity": "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/eslint-plugin-svelte/node_modules/lilconfig": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
@@ -3418,17 +3471,14 @@
}
}
},
- "node_modules/eslint-plugin-svelte/node_modules/postcss-selector-parser": {
- "version": "6.1.2",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
- "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
+ "node_modules/eslint-plugin-svelte/node_modules/yaml": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
"dev": true,
- "dependencies": {
- "cssesc": "^3.0.0",
- "util-deprecate": "^1.0.2"
- },
+ "license": "ISC",
"engines": {
- "node": ">=4"
+ "node": ">= 6"
}
},
"node_modules/eslint-scope": {
@@ -3436,7 +3486,7 @@
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
"integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
"dev": true,
- "peer": true,
+ "license": "BSD-2-Clause",
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
@@ -3453,7 +3503,7 @@
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
"dev": true,
- "peer": true,
+ "license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
@@ -3472,7 +3522,7 @@
"resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
"integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
"dev": true,
- "peer": true,
+ "license": "BSD-2-Clause",
"dependencies": {
"acorn": "^8.15.0",
"acorn-jsx": "^5.3.2",
@@ -3490,6 +3540,7 @@
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
"integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
"dev": true,
+ "license": "BSD-3-Clause",
"peer": true,
"dependencies": {
"estraverse": "^5.1.0"
@@ -3512,6 +3563,7 @@
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
"estraverse": "^5.2.0"
},
@@ -3524,6 +3576,7 @@
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
"dev": true,
+ "license": "BSD-2-Clause",
"engines": {
"node": ">=4.0"
}
@@ -3539,6 +3592,7 @@
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true,
+ "license": "BSD-2-Clause",
"engines": {
"node": ">=0.10.0"
}
@@ -3557,6 +3611,7 @@
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true,
+ "license": "MIT",
"peer": true
},
"node_modules/fast-glob": {
@@ -3590,6 +3645,7 @@
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
"dev": true,
+ "license": "MIT",
"peer": true
},
"node_modules/fast-levenshtein": {
@@ -3597,6 +3653,7 @@
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true,
+ "license": "MIT",
"peer": true
},
"node_modules/fastq": {
@@ -3626,6 +3683,7 @@
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
"integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
"dev": true,
+ "license": "MIT",
"peer": true,
"dependencies": {
"flat-cache": "^4.0.0"
@@ -3677,6 +3735,7 @@
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
"dev": true,
+ "license": "MIT",
"peer": true,
"dependencies": {
"locate-path": "^6.0.0",
@@ -3694,6 +3753,7 @@
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
"integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
"dev": true,
+ "license": "MIT",
"peer": true,
"dependencies": {
"flatted": "^3.2.9",
@@ -3708,6 +3768,7 @@
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
"dev": true,
+ "license": "ISC",
"peer": true
},
"node_modules/flowbite": {
@@ -3943,6 +4004,7 @@
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
"dev": true,
+ "license": "MIT",
"peer": true,
"engines": {
"node": ">=18"
@@ -4058,6 +4120,7 @@
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
"dev": true,
+ "license": "MIT",
"peer": true,
"engines": {
"node": ">= 4"
@@ -4068,6 +4131,7 @@
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
"integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
"dev": true,
+ "license": "MIT",
"peer": true,
"dependencies": {
"parent-module": "^1.0.0",
@@ -4080,21 +4144,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/import-meta-resolve": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz",
- "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==",
- "dev": true,
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
"node_modules/imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
"dev": true,
+ "license": "MIT",
"peer": true,
"engines": {
"node": ">=0.8.19"
@@ -4300,6 +4355,7 @@
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
+ "license": "MIT",
"peer": true,
"dependencies": {
"argparse": "^2.0.1"
@@ -4313,6 +4369,7 @@
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
"dev": true,
+ "license": "MIT",
"peer": true
},
"node_modules/json-schema-traverse": {
@@ -4320,6 +4377,7 @@
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true,
+ "license": "MIT",
"peer": true
},
"node_modules/json-stable-stringify-without-jsonify": {
@@ -4327,6 +4385,7 @@
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
"dev": true,
+ "license": "MIT",
"peer": true
},
"node_modules/jstransformer": {
@@ -4343,6 +4402,7 @@
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
"dev": true,
+ "license": "MIT",
"peer": true,
"dependencies": {
"json-buffer": "3.0.1"
@@ -4358,16 +4418,18 @@
}
},
"node_modules/known-css-properties": {
- "version": "0.35.0",
- "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz",
- "integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==",
- "dev": true
+ "version": "0.37.0",
+ "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.37.0.tgz",
+ "integrity": "sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
"integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
"dev": true,
+ "license": "MIT",
"peer": true,
"dependencies": {
"prelude-ls": "^1.2.1",
@@ -4423,6 +4485,7 @@
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
"dev": true,
+ "license": "MIT",
"peer": true,
"dependencies": {
"p-locate": "^5.0.0"
@@ -4598,6 +4661,7 @@
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true,
+ "license": "MIT",
"peer": true
},
"node_modules/neo-async": {
@@ -4774,6 +4838,7 @@
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
"integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
"dev": true,
+ "license": "MIT",
"peer": true,
"dependencies": {
"deep-is": "^0.1.3",
@@ -4792,6 +4857,7 @@
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"dev": true,
+ "license": "MIT",
"peer": true,
"dependencies": {
"yocto-queue": "^0.1.0"
@@ -4808,6 +4874,7 @@
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
"dev": true,
+ "license": "MIT",
"peer": true,
"dependencies": {
"p-limit": "^3.0.2"
@@ -4837,6 +4904,7 @@
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
"dev": true,
+ "license": "MIT",
"peer": true,
"dependencies": {
"callsites": "^3.0.0"
@@ -5112,19 +5180,30 @@
}
},
"node_modules/postcss-safe-parser": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz",
- "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==",
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz",
+ "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==",
"dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
"engines": {
- "node": ">=12.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
+ "node": ">=18.0"
},
"peerDependencies": {
- "postcss": "^8.3.3"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-scss": {
@@ -5146,6 +5225,7 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "license": "MIT",
"engines": {
"node": ">=12.0"
},
@@ -5175,6 +5255,7 @@
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
"dev": true,
+ "license": "MIT",
"peer": true,
"engines": {
"node": ">= 0.8.0"
@@ -5330,6 +5411,7 @@
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
"dev": true,
+ "license": "MIT",
"peer": true,
"engines": {
"node": ">=6"
@@ -5488,16 +5570,27 @@
}
},
"node_modules/readdirp": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
- "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
- "devOptional": true,
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "license": "MIT",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
"engines": {
- "node": ">= 14.18.0"
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
},
"funding": {
- "type": "individual",
- "url": "https://paulmillr.com/funding/"
+ "url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/require-directory": {
@@ -5537,6 +5630,7 @@
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
"dev": true,
+ "license": "MIT",
"peer": true,
"engines": {
"node": ">=4"
@@ -5644,6 +5738,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
+ "license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
@@ -5806,6 +5901,7 @@
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
"dev": true,
+ "license": "MIT",
"peer": true,
"engines": {
"node": ">=8"
@@ -5966,76 +6062,77 @@
"typescript": ">=5.0.0"
}
},
- "node_modules/svelte-eslint-parser": {
- "version": "0.43.0",
- "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.43.0.tgz",
- "integrity": "sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA==",
+ "node_modules/svelte-check/node_modules/chokidar": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "eslint-scope": "^7.2.2",
- "eslint-visitor-keys": "^3.4.3",
- "espree": "^9.6.1",
- "postcss": "^8.4.39",
- "postcss-scss": "^4.0.9"
+ "readdirp": "^4.0.1"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": ">= 14.16.0"
},
"funding": {
- "url": "https://github.com/sponsors/ota-meshi"
- },
- "peerDependencies": {
- "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0"
- },
- "peerDependenciesMeta": {
- "svelte": {
- "optional": true
- }
+ "url": "https://paulmillr.com/funding/"
}
},
- "node_modules/svelte-eslint-parser/node_modules/eslint-scope": {
- "version": "7.2.2",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
- "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "node_modules/svelte-check/node_modules/readdirp": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+ "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
"dev": true,
- "dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^5.2.0"
- },
+ "license": "MIT",
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": ">= 14.18.0"
},
"funding": {
- "url": "https://opencollective.com/eslint"
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
}
},
- "node_modules/svelte-eslint-parser/node_modules/eslint-visitor-keys": {
- "version": "3.4.3",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
- "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "node_modules/svelte-eslint-parser": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-1.3.0.tgz",
+ "integrity": "sha512-VCgMHKV7UtOGcGLGNFSbmdm6kEKjtzo5nnpGU/mnx4OsFY6bZ7QwRF5DUx+Hokw5Lvdyo8dpk8B1m8mliomrNg==",
"dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-scope": "^8.2.0",
+ "eslint-visitor-keys": "^4.0.0",
+ "espree": "^10.0.0",
+ "postcss": "^8.4.49",
+ "postcss-scss": "^4.0.9",
+ "postcss-selector-parser": "^7.0.0"
+ },
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
- "url": "https://opencollective.com/eslint"
+ "url": "https://github.com/sponsors/ota-meshi"
+ },
+ "peerDependencies": {
+ "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "svelte": {
+ "optional": true
+ }
}
},
- "node_modules/svelte-eslint-parser/node_modules/espree": {
- "version": "9.6.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
- "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+ "node_modules/svelte-eslint-parser/node_modules/postcss-selector-parser": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
+ "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "acorn": "^8.9.0",
- "acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.4.1"
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
+ "node": ">=4"
}
},
"node_modules/svelte/node_modules/is-reference": {
@@ -6184,51 +6281,6 @@
"node": ">=14.0.0"
}
},
- "node_modules/tailwindcss/node_modules/chokidar": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
- "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
- "dependencies": {
- "anymatch": "~3.1.2",
- "braces": "~3.0.2",
- "glob-parent": "~5.1.2",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.6.0"
- },
- "engines": {
- "node": ">= 8.10.0"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.2"
- }
- },
- "node_modules/tailwindcss/node_modules/chokidar/node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/tailwindcss/node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "engines": {
- "node": ">=8.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
"node_modules/tailwindcss/node_modules/postcss-load-config": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
@@ -6275,28 +6327,6 @@
"node": ">=4"
}
},
- "node_modules/tailwindcss/node_modules/readdirp": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
- "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "dependencies": {
- "picomatch": "^2.2.1"
- },
- "engines": {
- "node": ">=8.10.0"
- }
- },
- "node_modules/tailwindcss/node_modules/yaml": {
- "version": "2.8.0",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz",
- "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==",
- "bin": {
- "yaml": "bin.mjs"
- },
- "engines": {
- "node": ">= 14.6"
- }
- },
"node_modules/thenify": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
@@ -6417,6 +6447,7 @@
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
"integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
"dev": true,
+ "license": "MIT",
"peer": true,
"dependencies": {
"prelude-ls": "^1.2.1"
@@ -6456,10 +6487,11 @@
}
},
"node_modules/undici-types": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
- "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
- "dev": true
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
+ "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/unicode-emoji-modifier-base": {
"version": "1.0.0",
@@ -6512,6 +6544,7 @@
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"dev": true,
+ "license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"punycode": "^2.1.0"
@@ -6523,23 +6556,24 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"node_modules/vite": {
- "version": "6.3.5",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
- "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.5.tgz",
+ "integrity": "sha512-1mncVwJxy2C9ThLwz0+2GKZyEXuC3MyWtAAlNftlZZXZDP3AJt5FmwcMit/IGGaNZ8ZOB2BNO/HFUB+CpN0NQw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"esbuild": "^0.25.0",
- "fdir": "^6.4.4",
+ "fdir": "^6.4.6",
"picomatch": "^4.0.2",
- "postcss": "^8.5.3",
- "rollup": "^4.34.9",
- "tinyglobby": "^0.2.13"
+ "postcss": "^8.5.6",
+ "rollup": "^4.40.0",
+ "tinyglobby": "^0.2.14"
},
"bin": {
"vite": "bin/vite.js"
},
"engines": {
- "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ "node": "^20.19.0 || >=22.12.0"
},
"funding": {
"url": "https://github.com/vitejs/vite?sponsor=1"
@@ -6548,14 +6582,14 @@
"fsevents": "~2.3.3"
},
"peerDependencies": {
- "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+ "@types/node": "^20.19.0 || >=22.12.0",
"jiti": ">=1.21.0",
- "less": "*",
+ "less": "^4.0.0",
"lightningcss": "^1.21.0",
- "sass": "*",
- "sass-embedded": "*",
- "stylus": "*",
- "sugarss": "*",
+ "sass": "^1.70.0",
+ "sass-embedded": "^1.70.0",
+ "stylus": ">=0.54.8",
+ "sugarss": "^5.0.0",
"terser": "^5.16.0",
"tsx": "^4.8.1",
"yaml": "^2.4.2"
@@ -6780,6 +6814,7 @@
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
"dev": true,
+ "license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
@@ -6837,12 +6872,15 @@
}
},
"node_modules/yaml": {
- "version": "1.10.2",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
- "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
- "dev": true,
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz",
+ "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==",
+ "license": "ISC",
+ "bin": {
+ "yaml": "bin.mjs"
+ },
"engines": {
- "node": ">= 6"
+ "node": ">= 14.6"
}
},
"node_modules/yargs": {
@@ -6875,6 +6913,7 @@
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
"dev": true,
+ "license": "MIT",
"peer": true,
"engines": {
"node": ">=10"
diff --git a/src/app.css b/src/app.css
index 7a55d9d..4e2c9b2 100644
--- a/src/app.css
+++ b/src/app.css
@@ -201,6 +201,20 @@
.network-node-content {
@apply fill-primary-100;
}
+
+ /* Person link colors */
+ .person-link-signed {
+ @apply stroke-green-500;
+ }
+
+ .person-link-referenced {
+ @apply stroke-blue-400;
+ }
+
+ /* Person anchor node */
+ .person-anchor-node {
+ @apply fill-green-400 stroke-green-600;
+ }
}
/* Utilities can be applied via the @apply directive. */
diff --git a/src/lib/components/EventKindFilter.svelte b/src/lib/components/EventKindFilter.svelte
new file mode 100644
index 0000000..5f7b992
--- /dev/null
+++ b/src/lib/components/EventKindFilter.svelte
@@ -0,0 +1,204 @@
+
+
+
+
+ {#each $visualizationConfig.eventConfigs as ec}
+ {@const isEnabled = ec.enabled !== false}
+ {@const isLoaded = (eventCounts[ec.kind] || 0) > 0}
+ {@const borderColor = isLoaded ? 'border-green-500' : 'border-red-500'}
+
+ {/each}
+
+ {#if !showAddInput}
+
showAddInput = true}
+ class="gap-1"
+ >
+ +
+ Add Kind
+
+ {/if}
+
+
+
+ Reload
+
+
+
+ {#if showAddInput}
+
+ {
+ const value = (e.target as HTMLInputElement).value;
+ validateKind(value);
+ }}
+ />
+
+ Add
+
+ {
+ showAddInput = false;
+ newKind = '';
+ inputError = '';
+ }}
+ >
+ Cancel
+
+
+ {#if inputError}
+
+ {inputError}
+
+ {/if}
+ {/if}
+
+
+
+
+ Green border = Events loaded
+
+
+
+ Red border = Not loaded (click Reload to fetch)
+
+
+
+
+
\ No newline at end of file
diff --git a/src/lib/components/EventLimitControl.svelte b/src/lib/components/EventLimitControl.svelte
deleted file mode 100644
index 9a32a56..0000000
--- a/src/lib/components/EventLimitControl.svelte
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-
-
-
-
- Update
-
-
diff --git a/src/lib/components/EventTypeConfig.svelte b/src/lib/components/EventTypeConfig.svelte
new file mode 100644
index 0000000..4d7bfc7
--- /dev/null
+++ b/src/lib/components/EventTypeConfig.svelte
@@ -0,0 +1,274 @@
+
+
+
+
+ Showing {Object.values(eventCounts).reduce((a: any, b: any) => a + b, 0)} of {Object.values(eventCounts).reduce((a: any, b: any) => a + b, 0)} events
+
+
+
+
+
+
+ {#if showAddInput}
+
+ {
+ const validation = validateEventKind(e.currentTarget.value, existingKinds);
+ inputError = validation.error;
+ }}
+ />
+
+ Add
+
+ {
+ showAddInput = false;
+ newKind = '';
+ inputError = '';
+ }}
+ >
+ Cancel
+
+
+ {#if inputError}
+
+ {inputError}
+
+ {/if}
+ {:else}
+
showAddInput = true}
+ class="gap-1"
+ >
+ +
+ Add Event Type
+
+ {/if}
+
+
+
+
+ Reload
+
+
+
+
+
+
+ Green = Events loaded
+
+
+
+ Red = Not loaded (click Reload)
+
+
+
\ No newline at end of file
diff --git a/src/lib/components/util/ArticleNav.svelte b/src/lib/components/util/ArticleNav.svelte
index 1ab1655..f2c986c 100644
--- a/src/lib/components/util/ArticleNav.svelte
+++ b/src/lib/components/util/ArticleNav.svelte
@@ -4,12 +4,14 @@
CaretLeftOutline,
CloseOutline,
GlobeOutline,
+ ChartOutline,
} from "flowbite-svelte-icons";
import { Button } from "flowbite-svelte";
import { publicationColumnVisibility } from "$lib/stores";
import { userBadge } from "$lib/snippets/UserSnippets.svelte";
import type { NDKEvent } from "@nostr-dev-kit/ndk";
import { onDestroy, onMount } from "svelte";
+ import { goto } from "$app/navigation";
let { publicationType, indexEvent } = $props<{
rootId: any;
@@ -102,6 +104,11 @@
}
}
+ function visualizePublication() {
+ const eventId = indexEvent.id;
+ goto(`/visualize?event=${eventId}`);
+ }
+
let unsubscribe: () => void;
onMount(() => {
window.addEventListener("scroll", handleScroll);
@@ -186,6 +193,16 @@
Discussion
{/if}
+
+ Visualize Publication
+
diff --git a/src/lib/consts.ts b/src/lib/consts.ts
index ef41e0d..90afa53 100644
--- a/src/lib/consts.ts
+++ b/src/lib/consts.ts
@@ -2,7 +2,7 @@
export const wikiKind = 30818;
export const indexKind = 30040;
-export const zettelKinds = [30041, 30818];
+export const zettelKinds = [30041, 30818, 30023];
export const communityRelays = [
"wss://theforest.nostr1.com",
@@ -29,18 +29,18 @@ export const secondaryRelays = [
export const anonymousRelays = [
"wss://freelay.sovbit.host",
- "wss://thecitadel.nostr1.com"
+ "wss://thecitadel.nostr1.com",
];
export const lowbandwidthRelays = [
"wss://theforest.nostr1.com",
"wss://thecitadel.nostr1.com",
- "wss://aggr.nostr.land"
+ "wss://aggr.nostr.land",
];
export const localRelays: string[] = [
"wss://localhost:8080",
- "wss://localhost:4869"
+ "wss://localhost:4869",
];
export enum FeedType {
diff --git a/src/lib/navigator/EventNetwork/Legend.svelte b/src/lib/navigator/EventNetwork/Legend.svelte
index b553cab..1c49fe6 100644
--- a/src/lib/navigator/EventNetwork/Legend.svelte
+++ b/src/lib/navigator/EventNetwork/Legend.svelte
@@ -1,14 +1,61 @@
-
-
-
+
Legend
-
+
{#if expanded}
{:else}
{/if}
-
+
{#if expanded}
-
-
- -
-
-
- I
-
+
+
+
+
+
Node Types
+
+ {#if nodeTypesExpanded}
+
+ {:else}
+
+ {/if}
+
-
Index events (kind 30040) - Each with a unique pastel color
-
+
+ {#if nodeTypesExpanded}
+
+
+ {#each Object.entries(eventCounts).sort(([a], [b]) => Number(a) - Number(b)) as [kindStr, count]}
+ {@const kind = Number(kindStr)}
+ {@const countNum = count as number}
+ {@const color = getEventKindColor(kind)}
+ {@const name = getEventKindName(kind)}
+ {#if countNum > 0}
+ -
+
+
+
+
+
+ {kind} - {name} ({countNum})
+
+
+ {/if}
+ {/each}
+
+
+ -
+
+
+ {#if starMode}
+ Radial connections from centers to related events
+ {:else}
+ Arrows indicate relationships and sequence
+ {/if}
+
+
+
+
+ {#if showPersonNodes && personAnchors.length > 0}
+ -
+
+
+ Authored by person
+
+
+ -
+
+
+ References person
+
+
+ {/if}
+
+ {/if}
+
-
-
-
-
-
- C
-
+
+
+
tagControlsExpanded = !tagControlsExpanded}>
+
Tag Anchor Controls
+
+ {#if tagControlsExpanded}
+
+ {:else}
+
+ {/if}
+
-
Content events (kinds 30041, 30818) - Publication sections
-
+
+ {#if tagControlsExpanded}
+
+
+
+ {
+ showTagAnchors = !showTagAnchors;
+ onTagSettingsChange();
+ }}
+ class="px-2 py-1 border border-gray-300 dark:border-gray-700 rounded text-xs font-medium cursor-pointer transition min-w-[3rem] hover:bg-gray-200 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-primary-500 {showTagAnchors ? 'bg-blue-600 text-white border-blue-600 hover:bg-blue-700 dark:bg-blue-600 dark:text-white dark:border-blue-600 dark:hover:bg-blue-700' : 'bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300'}"
+ >
+ {showTagAnchors ? 'ON' : 'OFF'}
+
+ Show Tag Anchors
+
+
+ {#if showTagAnchors}
+
+
+
+
+
+
+ {/if}
+
+ {/if}
+
-
-
-
-
- Arrows indicate reading/sequence order
-
-
+
+ {#if showTags && tagAnchors.length > 0}
+
+
+
Active Tag Anchors: {tagAnchors[0].type}
+
+ {#if tagAnchorsExpanded}
+
+ {:else}
+
+ {/if}
+
+
+
+ {#if tagAnchorsExpanded}
+ {@const sortedAnchors = tagSortMode === 'count'
+ ? [...tagAnchors].sort((a, b) => b.count - a.count)
+ : [...tagAnchors].sort((a, b) => a.label.localeCompare(b.label))
+ }
+ {#if autoDisabledTags}
+
+ Note: All {tagAnchors.length} tags were auto-disabled to prevent graph overload. Click individual tags below to enable them.
+
+ {/if}
+
+
+
+
+
+ {#each sortedAnchors as anchor}
+ {@const tagId = `${anchor.type}-${anchor.label}`}
+ {@const isDisabled = disabledTags.has(tagId)}
+
onTagToggle(tagId)}
+ title={isDisabled ? `Click to show ${anchor.label}` : `Click to hide ${anchor.label}`}
+ >
+
+
+
+ {anchor.type === "t"
+ ? "#"
+ : anchor.type === "author"
+ ? "A"
+ : anchor.type.charAt(0).toUpperCase()}
+
+
+
+
+ {anchor.label.length > 25 ? anchor.label.slice(0, 22) + '...' : anchor.label}
+ {#if !isDisabled}
+ ({anchor.count})
+ {/if}
+
+
+ {/each}
+
+ {/if}
+
+ {/if}
+
+
+
+
personVisualizerExpanded = !personVisualizerExpanded}>
+
Person Visualizer
+
+ {#if personVisualizerExpanded}
+
+ {:else}
+
+ {/if}
+
+
+
+ {#if personVisualizerExpanded}
+
+
+
+
+ {#if showPersonNodes && personAnchors.length > 0}
+
+
+ {#if totalPersonCount > displayedPersonCount}
+ Displaying {displayedPersonCount} of {totalPersonCount} people found:
+ {:else}
+ {personAnchors.length} people found:
+ {/if}
+
+
+
+
+
+
+ {#each personAnchors as person}
+ {@const isDisabled = disabledPersons.has(person.pubkey)}
+
{
+ if (showPersonNodes) {
+ onPersonToggle(person.pubkey);
+ }
+ }}
+ disabled={!showPersonNodes}
+ title={!showPersonNodes ? 'Enable "Show Person Nodes" first' : isDisabled ? `Click to show ${person.displayName || person.pubkey}` : `Click to hide ${person.displayName || person.pubkey}`}
+ >
+
+
+
+
+ {person.displayName || person.pubkey.slice(0, 8) + '...'}
+ {#if !isDisabled}
+
+ ({person.signedByCount || 0}s/{person.referencedCount || 0}r)
+
+ {/if}
+
+
+ {/each}
+
+ {:else if showPersonNodes}
+
+ No people found in the current events.
+
+ {/if}
+
+ {/if}
+
+
{/if}
diff --git a/src/lib/navigator/EventNetwork/NodeTooltip.svelte b/src/lib/navigator/EventNetwork/NodeTooltip.svelte
index ef455bf..42c72d2 100644
--- a/src/lib/navigator/EventNetwork/NodeTooltip.svelte
+++ b/src/lib/navigator/EventNetwork/NodeTooltip.svelte
@@ -8,6 +8,12 @@
import type { NetworkNode } from "./types";
import { onMount } from "svelte";
import { getMatchingTags } from "$lib/utils/nostrUtils";
+ import { getEventKindName } from "$lib/utils/eventColors";
+ import {
+ getDisplayNameSync,
+ replacePubkeysWithDisplayNames,
+ } from "$lib/utils/profileCache";
+ import {indexKind, zettelKinds, wikiKind} from "$lib/consts";
// Component props
let {
@@ -16,12 +22,14 @@
x,
y,
onclose,
+ starMode = false,
} = $props<{
node: NetworkNode; // The node to display information for
selected?: boolean; // Whether the node is selected (clicked)
x: number; // X position for the tooltip
y: number; // Y position for the tooltip
onclose: () => void; // Function to call when closing the tooltip
+ starMode?: boolean; // Whether we're in star visualization mode
}>();
// DOM reference and positioning
@@ -32,6 +40,9 @@
// Maximum content length to display
const MAX_CONTENT_LENGTH = 200;
+ // Publication event kinds (text/article based)
+ const PUBLICATION_KINDS = [wikiKind, indexKind, ...zettelKinds];
+
/**
* Gets the author name from the event tags
*/
@@ -39,7 +50,11 @@
if (node.event) {
const authorTags = getMatchingTags(node.event, "author");
if (authorTags.length > 0) {
- return authorTags[0][1];
+ return getDisplayNameSync(authorTags[0][1]);
+ }
+ // Fallback to event pubkey
+ if (node.event.pubkey) {
+ return getDisplayNameSync(node.event.pubkey);
}
}
return "Unknown";
@@ -71,6 +86,34 @@
return "View Publication";
}
+ /**
+ * Checks if this is a publication event
+ */
+ function isPublicationEvent(kind: number): boolean {
+ return PUBLICATION_KINDS.includes(kind);
+ }
+
+ /**
+ * Gets the appropriate URL for the event
+ */
+ function getEventUrl(node: NetworkNode): string {
+ if (isPublicationEvent(node.kind)) {
+ return `/publication?id=${node.id}`;
+ }
+ return `/events?id=${node.id}`;
+ }
+
+ /**
+ * Gets display text for the link
+ */
+ function getLinkText(node: NetworkNode): string {
+ if (isPublicationEvent(node.kind)) {
+ return node.title || "Untitled Publication";
+ }
+ // For arbitrary events, show event kind name
+ return node.title || `Event ${node.kind}`;
+ }
+
/**
* Truncates content to a maximum length
*/
@@ -145,39 +188,92 @@
- {node.type} (kind: {node.kind})
+ {#if isPublicationEvent(node.kind)}
+ {node.type} (kind: {node.kind})
+ {:else}
+ {getEventKindName(node.kind)}
+ {#if node.event?.created_at}
+ · {new Date(node.event.created_at * 1000).toLocaleDateString()}
+ {/if}
+ {/if}
-
+
- Author: {getAuthorTag(node)}
+ Pub Author: {getAuthorTag(node)}
-
- {#if node.isContainer && getSummaryTag(node)}
-
diff --git a/src/lib/navigator/EventNetwork/Settings.svelte b/src/lib/navigator/EventNetwork/Settings.svelte
index 2cff9e2..584834b 100644
--- a/src/lib/navigator/EventNetwork/Settings.svelte
+++ b/src/lib/navigator/EventNetwork/Settings.svelte
@@ -1,58 +1,136 @@
-
-
+
Settings
-
+
{#if expanded}
{:else}
{/if}
-
+
{#if expanded}
- Showing {count} events from {$networkFetchLimit} headers
+ Showing {count} of {totalCount} events
-
-
+
+
+
+
+ {#if eventTypesExpanded}
+
+ {/if}
+
+
+
+
+
+
+
+ {#if visualSettingsExpanded}
+
+
+
+
+
+ Toggle between star clusters (on) and linear sequence (off)
+ visualization
+
+
+
+
+
+ {/if}
+
{/if}
diff --git a/src/lib/navigator/EventNetwork/TagTable.svelte b/src/lib/navigator/EventNetwork/TagTable.svelte
new file mode 100644
index 0000000..fa02295
--- /dev/null
+++ b/src/lib/navigator/EventNetwork/TagTable.svelte
@@ -0,0 +1,82 @@
+
+
+
+{#if uniqueTags.length > 0}
+
+
+ {tagTypeLabels[selectedTagType] || 'Tags'}
+
+
+
+
+ | Tag |
+ Count |
+
+
+
+ {#each uniqueTags as tag}
+
+ | {tag.value} |
+ {tag.count} |
+
+ {/each}
+
+
+
+{:else}
+
+ No {tagTypeLabels[selectedTagType]?.toLowerCase() || 'tags'} found
+
+{/if}
+
+
\ No newline at end of file
diff --git a/src/lib/navigator/EventNetwork/index.svelte b/src/lib/navigator/EventNetwork/index.svelte
index ffbb44a..c9a8149 100644
--- a/src/lib/navigator/EventNetwork/index.svelte
+++ b/src/lib/navigator/EventNetwork/index.svelte
@@ -11,6 +11,16 @@
import type { NDKEvent } from "@nostr-dev-kit/ndk";
import { levelsToRender } from "$lib/state";
import { generateGraph, getEventColor } from "./utils/networkBuilder";
+ import { getEventKindColor } from "$lib/utils/eventColors";
+ import {
+ generateStarGraph,
+ applyStarLayout,
+ } from "./utils/starNetworkBuilder";
+ import {
+ createStarSimulation,
+ applyInitialStarPositions,
+ createStarDragHandler,
+ } from "./utils/starForceSimulation";
import {
createSimulation,
setupDragHandlers,
@@ -22,7 +32,20 @@
import NodeTooltip from "./NodeTooltip.svelte";
import type { NetworkNode, NetworkLink } from "./types";
import Settings from "./Settings.svelte";
+ import {
+ enhanceGraphWithTags,
+ getTagAnchorColor,
+ } from "./utils/tagNetworkBuilder";
+ import {
+ extractUniquePersons,
+ createPersonAnchorNodes,
+ createPersonLinks,
+ extractPersonAnchorInfo,
+ } from "./utils/personNetworkBuilder";
import { Button } from "flowbite-svelte";
+ import { visualizationConfig } from "$lib/stores/visualizationConfig";
+ import { get } from "svelte/store";
+ import type { EventCounts } from "$lib/types";
// Type alias for D3 selections
type Selection = any;
@@ -45,9 +68,24 @@
}
// Component props
- let { events = [], onupdate } = $props<{
+ let {
+ events = [],
+ followListEvents = [],
+ totalCount = 0,
+ onupdate,
+ onclear = () => {},
+ onTagExpansionChange,
+ profileStats = { totalFetched: 0, displayLimit: 50 },
+ allEventCounts = {}
+ } = $props<{
events?: NDKEvent[];
+ followListEvents?: NDKEvent[];
+ totalCount?: number;
onupdate: () => void;
+ onclear?: () => void;
+ onTagExpansionChange?: (tags: string[]) => void;
+ profileStats?: { totalFetched: number; displayLimit: number };
+ allEventCounts?: EventCounts;
}>();
// Error state
@@ -81,10 +119,57 @@
let svgGroup: Selection;
let zoomBehavior: any;
let svgElement: Selection;
+
+ // Position cache to preserve node positions across updates
+ let nodePositions = new Map
();
// Track current render level
let currentLevels = $derived(levelsToRender);
+ // Star visualization state (default to true)
+ let starVisualization = $state(true);
+
+ // Tag anchors state
+ let showTagAnchors = $state(false);
+ let selectedTagType = $state("t"); // Default to hashtags
+ let tagAnchorInfo = $state([]);
+
+ // Store initial state to detect if component is being recreated
+ let componentId = Math.random();
+ debug("Component created with ID:", componentId);
+
+ // Event counts by kind - derived from events
+ let eventCounts = $derived.by(() => {
+ const counts: { [kind: number]: number } = {};
+ events.forEach((event: NDKEvent) => {
+ if (event.kind !== undefined) {
+ counts[event.kind] = (counts[event.kind] || 0) + 1;
+ }
+ });
+ return counts;
+ });
+
+ // Disabled tags state for interactive legend
+ let disabledTags = $state(new Set());
+
+ // Track if we've auto-disabled tags
+ let autoDisabledTags = $state(false);
+
+ // Maximum number of tag anchors before auto-disabling
+ const MAX_TAG_ANCHORS = 20;
+
+ // Person nodes state
+ let showPersonNodes = $state(false);
+ let personAnchorInfo = $state([]);
+ let disabledPersons = $state(new Set());
+ let showSignedBy = $state(true);
+ let showReferenced = $state(true);
+ let personMap = $state