diff --git a/package-lock.json b/package-lock.json index c652c3c5..44c4d739 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,17 @@ { "name": "solid-panes", - "version": "4.4.2-4", + "version": "4.4.2-5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "solid-panes", - "version": "4.4.2-4", + "version": "4.4.2-5", "license": "MIT", "dependencies": { "@solid/better-simple-slideshow": "^0.1.0", "activitystreams-pane": "1.0.3-4", - "chat-pane": "3.0.4-2", + "chat-pane": "3.0.4-3", "contacts-pane": "3.2.1-5", "dompurify": "^3.4.4", "folder-pane": "3.1.1-2", @@ -21,12 +21,12 @@ "meeting-pane": "3.0.3-1", "mime-types": "^3.0.2", "pane-registry": "3.1.2-2", - "profile-pane": "3.2.3-3", + "profile-pane": "3.2.3-4", "rdflib": "2.4.0", "solid-logic": "4.0.8-1", "solid-namespace": "^0.5.4", "solid-ui": "3.1.3-13", - "source-pane": "3.1.1-4" + "source-pane": "3.1.1-5" }, "devDependencies": { "@iconify/json": "2.2.494", @@ -2103,9 +2103,9 @@ } }, "node_modules/@codemirror/view": { - "version": "6.43.6", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.6.tgz", - "integrity": "sha512-EVunGSYN1wz1p75WY1s3Xg7t3i8Yol0kGZGizNdX9BUFgMFILYVe8/u6EVpo7Ff5PwbZuILb4QAq7IZoKzIEQA==", + "version": "6.43.7", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.7.tgz", + "integrity": "sha512-FZsExxkoxnAN+d9TgqXLg5g4A1oQwzX9WlkOT5i2PKkcW7xx3Bmu0vs90g6fo9Mpdsb/l96dnAraQ8932aO4/g==", "license": "MIT", "dependencies": { "@codemirror/state": "^6.7.0", @@ -2325,30 +2325,30 @@ } }, "node_modules/@digitalbazaar/http-client/node_modules/undici": { - "version": "6.27.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz", - "integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==", + "version": "6.28.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.28.0.tgz", + "integrity": "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==", "license": "MIT", "engines": { "node": ">=18.17" } }, "node_modules/@emnapi/core": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", - "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", + "version": "2.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-2.0.0-alpha.3.tgz", + "integrity": "sha512-AZypUeJ/yByuxyS7BlSNRDOMLMlROYtjYdIAuBmJssVz1UJDSeYxLrdizhXCFYhedC5bqd/ASy8EuNXbVVXp9g==", "license": "MIT", "optional": true, "peer": true, "dependencies": { - "@emnapi/wasi-threads": "1.2.2", + "@emnapi/wasi-threads": "2.0.1", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", - "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", + "version": "2.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-2.0.0-alpha.3.tgz", + "integrity": "sha512-hFPAhMUjJD9BSyCANEISPOogeXC9Zo9ZQl7L6vKnaVsMkCtzznaW/naYypeyl0Gv5rYfWYsZbpixTMpjDJzQeA==", "license": "MIT", "optional": true, "peer": true, @@ -2357,11 +2357,12 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", - "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-2.0.1.tgz", + "integrity": "sha512-9DsSk+o5NBX0CCJT8s0EROGSGxjR/tKu6aBTaVyq+SjAEQH4XcdcRxPBRzsBLizTTJ49MJjF+jgu3qnO9GLQcQ==", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -2441,9 +2442,9 @@ "license": "MIT" }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -2516,9 +2517,9 @@ "license": "MIT" }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -2787,9 +2788,9 @@ } }, "node_modules/@konnorr/qr-creator": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@konnorr/qr-creator/-/qr-creator-1.0.1.tgz", - "integrity": "sha512-EmRR9rny1ENBtQy7TLOguO/79h1EpzXUmqIdMTGp2BW8NkZtRRPr5hmQcE+n9QXYo4T8NjcaJ14hnZg+s/+K+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@konnorr/qr-creator/-/qr-creator-1.1.0.tgz", + "integrity": "sha512-6Ae3AfG45MOqF9Qde+1YxIxKf/GUsRmcriV7iCb/HaR+Mk1YDFYP3RINDRMI8z8YMWW3BnSthOujX9RoOex/Kw==", "license": "MIT" }, "node_modules/@lezer/common": { @@ -3002,21 +3003,24 @@ "license": "MIT" }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", - "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.1.tgz", + "integrity": "sha512-KjZdi8Q1wh89gsVmghvbrMgWl6ZWmRmHV6wjB7/g4Zf0dyO+hH3neZUtuDNPO00qq5YE5RITVWvrIZKRaAmzGQ==", "license": "MIT", "optional": true, "dependencies": { "@tybys/wasm-util": "^0.10.3" }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, "funding": { "type": "github", "url": "https://github.com/sponsors/Brooooooklyn" }, "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.3", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.3" } }, "node_modules/@noble/curves": { @@ -3047,9 +3051,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.140.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.140.0.tgz", - "integrity": "sha512-h5LUOzGArYemnW1NMz/DuuQhBi96J6JL2Bk8zE4kvqxB5Sg3jxmCiH4uyOWHDkiKSt5vWlG4FIwCR/DbstcNRQ==", + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.142.0.tgz", + "integrity": "sha512-7W+2q5AKQVU36fkaryontrHn3YDt1RyUYXatw9i5H8ocYe2sPKSFB6eS8WNPeRKiN1qAWWZUPm7gwFzJGrccqQ==", "dev": true, "license": "MIT", "peer": true, @@ -3100,9 +3104,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.0.tgz", - "integrity": "sha512-9yB1l95IrJuNGDFdOYe79vdApdz6WWBCObE+rQ2LUliYUlcyFwSYIb2xb5/Ifw7dAtMy2ZqNyd8QTSOc7duAKw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.1.tgz", + "integrity": "sha512-02hOeOSryYxVrOIphmLAsqnCJWxwlzFk+pEt/N/i6OgT3lShHO7xGCU5cpgchRDHboAEbSjzgGh+O/u1GswQmA==", "cpu": [ "arm64" ], @@ -3118,9 +3122,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.0.tgz", - "integrity": "sha512-pexNaW9ACLUOaBITOpU6qVu4VrsOFIjTv6bzgu0YUATo4eUJx0V605PxwZfndpPOn0ilqGqvGQ0M8UW0IE24jg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.1.tgz", + "integrity": "sha512-fMsTOnN0OjFm3CyppWPitKnc8UlliVARUULW6cfU6AIqjdtgmSFWSk9vecHzZduv/yMWIHDlRhM1e8Iff9uAfA==", "cpu": [ "arm64" ], @@ -3136,9 +3140,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.0.tgz", - "integrity": "sha512-NqKYaq0355ZmNMG4QGpxtEDxsc7tGDhjhCm4PpE0cwnBW+5Il95LJyq414niEiaKLVjnVHBEjSo1wngKxJNiFw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.1.tgz", + "integrity": "sha512-1wjKdz/XLGKHaTNHjQveQ/B23TKx4ItAqm1JbyVuvNPc4Ze0Fb48s49TAd/2zcplPl8okE/UbTgmlVfwT7eFeQ==", "cpu": [ "x64" ], @@ -3154,9 +3158,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.0.tgz", - "integrity": "sha512-3vPoHzh6eBTz9IbB0/qZdSr0Qeks2echn+I4cHu2joV74VriPDdldswksEDzrl1mBB+oPRi+67+3Ib59paxIPQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.1.tgz", + "integrity": "sha512-Fa0jHR07E7YBN4vOEsbVf2briYNsuOowfLJaXULZM0ldMlaCaj2LJgLMbMe4iacRyZmvR8efFhgR9wKuGclQUg==", "cpu": [ "x64" ], @@ -3172,9 +3176,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.0.tgz", - "integrity": "sha512-E6NNefZ1bUVmKJq2tJkf45J4Zyczj7qm9rUT7NY+Xo2474Y13qWAwc2tvBt0BAVbmtXR1llkxXg0Ou1jbDf2SQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.1.tgz", + "integrity": "sha512-pzkgu1SSHGgRRyRZ4fbmSgmajbVt+epaLP99NDjFft69v/ypfTi6swBMiVdh2EkQ0OSnHE1lZDM7DRGkyAzUpA==", "cpu": [ "arm" ], @@ -3190,9 +3194,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.0.tgz", - "integrity": "sha512-D+TgkdgM1vu+7/Fpf8+v0ARW+RXEP9Ccazgm8zQ4JFFd9Q7SrYQ2TakU5S5ihazQDgpKyAgZDOcIFsvoHmTZ8w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.1.tgz", + "integrity": "sha512-QI5SEDY8cbiYWHx0VO4vIc3UlS6a32vXHjU8Qy/17adEmZIPuByJg13UEvo9c/UCiUkdcVWY83C+b+JrwnNyUg==", "cpu": [ "arm64" ], @@ -3208,9 +3212,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.0.tgz", - "integrity": "sha512-wUqdwJBbAv0APN87GecstdMUtLjjNTs0hBALpxETD73mccFxdmt/XeizXDtN5RAlBwNKmI+Tg+blect2G+8IeQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.1.tgz", + "integrity": "sha512-Sm41FyCeXqmYcERoYOCbGIL5hNfd8w9LQ7Y61Bev48HkcjaJqV/iiVOaiDxjVTRMS+QKrZmD8cfPt4uMVnvM+A==", "cpu": [ "arm64" ], @@ -3226,9 +3230,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.0.tgz", - "integrity": "sha512-9DtF35qR9/NrfhM4oxLplCzVVjE+KKm8Pjemi0i/sdhAWkUasjmSo8WTTubNJClhSHCfyk2yeyoXDQEDPtDAAw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.1.tgz", + "integrity": "sha512-2x+WhXTGl9yJYPbltW/BSEPTVz9OIWQyER4N+gJEDWkkn904eRcBzELqh/Hf7K0w/ubGbKNMv0ZC+94QK/IFEg==", "cpu": [ "ppc64" ], @@ -3244,9 +3248,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.0.tgz", - "integrity": "sha512-RzuHrBh8X8Hntd2N4VR02QGEciq/9JhcZoTpR/Cee6otRrlILGCf3cg2ygHuih+ZebUnWmMrDX6ITI85btO6rQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.1.tgz", + "integrity": "sha512-eEjmQpuRQayHPWWnywaWHkFT3ToPbP3RYy42VVd/B9aBGDA+Ol25EIWHxKQST3IiWJjikCWUF7KtbfqwZrzVwQ==", "cpu": [ "s390x" ], @@ -3262,9 +3266,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.0.tgz", - "integrity": "sha512-MK7L0018jjh1jR3mh21G2j1zAVcpscJBlPo2z19pRjv2XOYGRhaV4LyiD8HO6nCDdZln9IFgCMIV5yt4E3klGQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.1.tgz", + "integrity": "sha512-/Orga1fZYkLc/56jBICcHrKchl8Z2UKdDSr3LG9ToWO1lQ6a4Livk9Xz+9WN91zsz5QR3XQz2NNoSDEvP6qadw==", "cpu": [ "x64" ], @@ -3280,9 +3284,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.0.tgz", - "integrity": "sha512-gyrxLQ9NfGb/9LoVnC4kb9miUghw1mghnkfYvNHSnVIXriabnfgGPUP4RLcJm87q3KgYz4FYUG8IDiWUT+CpSw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.1.tgz", + "integrity": "sha512-xxBJRL+0q0Kce7orznGWLuylHDY65vuARXZRpX+hPdv+DqK2c3NlCsVA98tlWzWNEE7yPqA/1NQ5nnCrj49Y5A==", "cpu": [ "x64" ], @@ -3298,9 +3302,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.0.tgz", - "integrity": "sha512-/6VFMQGRmrhP77KXDC+StIxGzcNp5JOIyYtw0CQ8gPlzhpiIRucYfoM5FaFamHd5BJYIdH86yfP46l1p3WdrFA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.1.tgz", + "integrity": "sha512-M6AdXIXw3s+/8XpKMzdGDEXGS1S7kwUsy+rcTIUIOx5Ge4nXKCtAFHFV9YKkXvGcC5WMoTjAteLzlsQROVI0Yw==", "cpu": [ "arm64" ], @@ -3316,29 +3320,26 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.2.0.tgz", - "integrity": "sha512-rwdbUL465kisF24WEJLvP3JrEG6E5GRuIHt5wpMwHGERtHe4Wm2CIvtf5gTBgr2tGOHKh5NdKEAFS2VkOPE91g==", - "cpu": [ - "wasm32" - ], + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.2.1.tgz", + "integrity": "sha512-/TX0SoRGojHzSAHpfVBbavRVSazg5U3h3Y3VXfcc0cdugq6kxdqw8LPGFiPr+/7gE/60zRcsOY2Vi9b9eT0jww==", "dev": true, "license": "MIT", "optional": true, "peer": true, "dependencies": { - "@emnapi/core": "1.11.2", - "@emnapi/runtime": "1.11.2", - "@napi-rs/wasm-runtime": "^1.1.6" + "@emnapi/core": "2.0.0-alpha.3", + "@emnapi/runtime": "2.0.0-alpha.3", + "@napi-rs/wasm-runtime": "^1.2.0" }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.0.tgz", - "integrity": "sha512-+5suHwRiKGmhwyUaNT8a5QbrBvLFh2DbO910TEmGRH1aSxwrCezodvGQnulv4uiWEIv1Kq4ypRsJ5+O+ry1DiA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.1.tgz", + "integrity": "sha512-EvRrivJieyHG+AO9lleZWgq+g0+S7oV2C51yuqlcyU/R9net+sI4Pj0F+lUoP2bEr6TWX3SqFaaS0SzfLxSzkw==", "cpu": [ "arm64" ], @@ -3354,9 +3355,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.0.tgz", - "integrity": "sha512-WfFv6/qGufotqBSBzBYwgpCkJBk8Nj7697LL9vTz/XWc67e0r3oewu8iMRwQj3AUL45GVD7wVsPjCsAAtW66Wg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.1.tgz", + "integrity": "sha512-Z4eCmn5QJ/5+azF9knpLWKfVd9aidn0mAe9TpJgvBLId9Ax3t0+JVxBmT25Bv7NBbVW1TZyKjQjQReouMeH5UQ==", "cpu": [ "x64" ], @@ -4105,9 +4106,9 @@ } }, "node_modules/acorn": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", - "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -4142,6 +4143,35 @@ "timeago.js": "^4.0.2" } }, + "node_modules/activitystreams-pane/node_modules/solid-ui": { + "version": "3.1.3-9", + "resolved": "https://registry.npmjs.org/solid-ui/-/solid-ui-3.1.3-9.tgz", + "integrity": "sha512-36as6RIBflm2gsIFnEPLH6hzykXxyc9yJlhJ+E0E6JSLOyjgENGxEj55hMH8lIXzBcR5tkym3Y61vgMm/LIU8Q==", + "license": "MIT", + "dependencies": { + "@awesome.me/webawesome": "^3.9.0", + "@lit/context": "^1.1.6", + "@noble/curves": "^2.2.0", + "@noble/hashes": "^2.2.0", + "escape-html": "^1.0.3", + "lit": "^3.3.3", + "mime-types": "^3.0.2", + "pane-registry": "3.1.2-1", + "rdflib": "2.4.0", + "solid-logic": "4.0.8-1", + "solid-namespace": "^0.5.4", + "uuid": "^14.0.0" + }, + "optionalDependencies": { + "fsevents": "*" + } + }, + "node_modules/activitystreams-pane/node_modules/solid-ui/node_modules/pane-registry": { + "version": "3.1.2-1", + "resolved": "https://registry.npmjs.org/pane-registry/-/pane-registry-3.1.2-1.tgz", + "integrity": "sha512-aibuyF8pAgHDnmywsMEKUddIcqC0oPF8fNx2TP7zRpRW9aYk2iv06td+br8wenbmu2V/l6Y6aJmCkckHWN/GpA==", + "license": "MIT" + }, "node_modules/agent-base": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", @@ -4490,9 +4520,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.1.tgz", - "integrity": "sha512-HYXq73DDpCtNzOmrFsm9eSwCvWCql0RzqjpDzXN9EadiLJ4DNat0nsZ/Bzmy+Ud12mb4/zKDY0cQ805ZzN+i0A==", + "version": "2.11.7", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.7.tgz", + "integrity": "sha512-APw5YuIQAg6L9w4sHDI6j26DGFJI6RpYOhnkMPdC9lWbkKvsyPHzDsve1yd73lk21yz7Y09Kci8B2Pp9FonzWA==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4513,9 +4543,9 @@ } }, "node_modules/brace-expansion": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz", - "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -4727,15 +4757,19 @@ } }, "node_modules/chat-pane": { - "version": "3.0.4-2", - "resolved": "https://registry.npmjs.org/chat-pane/-/chat-pane-3.0.4-2.tgz", - "integrity": "sha512-KKIPG6KMcsbo3FKYiYqQ8PkHPUxAelak4GaCPAzI0WInkW5s2ms4QxfWwxELLOYqI0Aj6CICTe52w04Phl9DCQ==", + "version": "3.0.4-3", + "resolved": "https://registry.npmjs.org/chat-pane/-/chat-pane-3.0.4-3.tgz", + "integrity": "sha512-m099X1Lb1qaOtaYNAaJ+NfqD/TMRnhX3Gfx5Xgb2HoZYllaxn1xN3Y5Am4Un21k6tLoPaiq1OIkBe09/gHN/sw==", "license": "MIT", "dependencies": { + "pane-registry": "3.1.2-2", "patch-package": "^8.0.1", - "rdflib": "^2.4.0", - "solid-logic": "^4.0.8-1", - "solid-ui": "^3.1.3-9" + "rdflib": "^2.3.9", + "solid-logic": "^4.0.8-0", + "solid-ui": "3.1.3-13", + "vite": "^8.0.16", + "vitest": "^4.0.18", + "vitest-axe": "^0.1.0" } }, "node_modules/ci-info": { @@ -5248,9 +5282,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.396", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.396.tgz", - "integrity": "sha512-yHiw2Y3C3H9U6TMbOfoWK/BPreiOPXRfTWPBwQBoZG6/8TB6eOPnsy5oaRYuatR7Fw2SJ4kKforgufeo7fq0EQ==", + "version": "1.5.398", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.398.tgz", + "integrity": "sha512-AsvhAxopJGh6museTDMIjn6JpDYOfgu4RLlygomt87MUwBUqTfd/1EiPtx10/LZE8xpTvkP2E9Gafq7lkLtodQ==", "dev": true, "license": "ISC" }, @@ -5261,9 +5295,9 @@ "license": "MIT" }, "node_modules/enhanced-resolve": { - "version": "5.24.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.3.tgz", - "integrity": "sha512-PwKooW9JUzh5chmYfHM3IQl5OkK2u2Nm011MgeZrss3JmFraUx/fqrf78kk8GUMYoibx/14MdwTl/1WKkG7TpQ==", + "version": "5.24.5", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz", + "integrity": "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -5731,9 +5765,9 @@ "license": "MIT" }, "node_modules/eslint-plugin-react/node_modules/brace-expansion": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", "dev": true, "license": "MIT", "dependencies": { @@ -5799,9 +5833,9 @@ "license": "MIT" }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -5950,9 +5984,9 @@ } }, "node_modules/exsolve": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.1.0.tgz", - "integrity": "sha512-D+42+T12DdIlJM3uepa55qGiL3sYdLBOxIl2ifQCzCHz4c7eiolaHsi3BIqEr7JxBzxv2pYZQX9kw16ziMcEmw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.1.1.tgz", + "integrity": "sha512-9U/jZUgjnSGyntRr6y5Muu1MJcwFl6kPu7k8qLF0IMNfLqvw0NZ4nnVDq0RVoZ0RvCyumib4Ez3KYrVfilrw+g==", "dev": true, "license": "MIT" }, @@ -6077,9 +6111,9 @@ } }, "node_modules/flatted": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.3.tgz", - "integrity": "sha512-/zipXxyO6rGvuNGDiULY9MvEGSkb2gaG4GGH4ygMi0ZZzyMHdUZBmntJmx5x1G2VuPytCwGN4xsJP6cw+sK+vQ==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", + "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", "license": "ISC" }, "node_modules/folder-pane": { @@ -6096,6 +6130,30 @@ "vitest-axe": "^0.1.0" } }, + "node_modules/folder-pane/node_modules/solid-ui": { + "version": "3.1.3-11", + "resolved": "https://registry.npmjs.org/solid-ui/-/solid-ui-3.1.3-11.tgz", + "integrity": "sha512-VrGdKow2Xg6lmHLRJmRb2rqU2UA/kj75H0o9PYt9DRVBjTWXBfiXFnIqJqst49xBPKIxLPkKGvE0butzL1RwXQ==", + "license": "MIT", + "dependencies": { + "@awesome.me/webawesome": "^3.9.0", + "@lit/context": "^1.1.6", + "@lit/task": "^1.0.3", + "@noble/curves": "^2.2.0", + "@noble/hashes": "^2.2.0", + "escape-html": "^1.0.3", + "lit": "^3.3.3", + "mime-types": "^3.0.2", + "pane-registry": "3.1.2-2", + "rdflib": "2.4.0", + "solid-logic": "4.0.8-1", + "solid-namespace": "^0.5.4", + "uuid": "^14.0.0" + }, + "optionalDependencies": { + "fsevents": "*" + } + }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", @@ -6371,9 +6429,9 @@ } }, "node_modules/globals": { - "version": "17.7.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.7.0.tgz", - "integrity": "sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==", + "version": "17.8.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.8.0.tgz", + "integrity": "sha512-Zz/LMDZScFmkakeL2cTHzf+PbWKdpU3uclqkZT7TjDG58j5WPt0PpA+n9uPI24fZtlw07q0OtEi84K+umsRzqQ==", "dev": true, "license": "MIT", "engines": { @@ -8301,12 +8359,12 @@ } }, "node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.5" + "brace-expansion": "^5.0.8" }, "engines": { "node": "18 || 20 || >=22" @@ -9178,9 +9236,9 @@ } }, "node_modules/postcss": { - "version": "8.5.22", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.22.tgz", - "integrity": "sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ==", + "version": "8.5.25", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz", + "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", "funding": [ { "type": "opencollective", @@ -9314,13 +9372,13 @@ "license": "MIT" }, "node_modules/profile-pane": { - "version": "3.2.3-3", - "resolved": "https://registry.npmjs.org/profile-pane/-/profile-pane-3.2.3-3.tgz", - "integrity": "sha512-sT/gcJInMlLTtLWrbmeoWFjIPKbfL6OWSVqASVYuBe6Nyb0x6GmVLkBNsBmDrdrJNqVyzVfE9KMAukXc4KEIaQ==", + "version": "3.2.3-4", + "resolved": "https://registry.npmjs.org/profile-pane/-/profile-pane-3.2.3-4.tgz", + "integrity": "sha512-mtbOfS37mFazMu+3h0YaUP4BMqVvzAB4Mvlt9jivl41XQIBxulKP+xhKw2GSI6A4wGs9SIMa8JB7ykQJqiC1bg==", "license": "MIT", "dependencies": { "@solid-data-modules/contacts-rdflib": "^0.7.1", - "chat-pane": "3.0.4-2", + "chat-pane": "3.0.4-3", "lit-html": "^3.3.3", "pane-registry": "3.1.2-2", "patch-package": "^8.0.1", @@ -9800,14 +9858,14 @@ } }, "node_modules/rolldown": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.0.tgz", - "integrity": "sha512-u7tgm5l4Yw1iTqUL4EcYOAt7fFvCgQMLeidrnD4GALlC6aOznCjezYajgxeyKw27u0Q5N7fwgCzjVyPIWzwuBA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.1.tgz", + "integrity": "sha512-4FKJhg8d3OiyQOA6Q1Q0hoFFpW9/OoX+VsHzpECsdsIZoOArrAK90gl59YK/Z+gnDel45bgJZK03ozH/9bCqEw==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@oxc-project/types": "=0.140.0", + "@oxc-project/types": "=0.142.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -9817,21 +9875,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.2.0", - "@rolldown/binding-darwin-arm64": "1.2.0", - "@rolldown/binding-darwin-x64": "1.2.0", - "@rolldown/binding-freebsd-x64": "1.2.0", - "@rolldown/binding-linux-arm-gnueabihf": "1.2.0", - "@rolldown/binding-linux-arm64-gnu": "1.2.0", - "@rolldown/binding-linux-arm64-musl": "1.2.0", - "@rolldown/binding-linux-ppc64-gnu": "1.2.0", - "@rolldown/binding-linux-s390x-gnu": "1.2.0", - "@rolldown/binding-linux-x64-gnu": "1.2.0", - "@rolldown/binding-linux-x64-musl": "1.2.0", - "@rolldown/binding-openharmony-arm64": "1.2.0", - "@rolldown/binding-wasm32-wasi": "1.2.0", - "@rolldown/binding-win32-arm64-msvc": "1.2.0", - "@rolldown/binding-win32-x64-msvc": "1.2.0" + "@rolldown/binding-android-arm64": "1.2.1", + "@rolldown/binding-darwin-arm64": "1.2.1", + "@rolldown/binding-darwin-x64": "1.2.1", + "@rolldown/binding-freebsd-x64": "1.2.1", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.1", + "@rolldown/binding-linux-arm64-gnu": "1.2.1", + "@rolldown/binding-linux-arm64-musl": "1.2.1", + "@rolldown/binding-linux-ppc64-gnu": "1.2.1", + "@rolldown/binding-linux-s390x-gnu": "1.2.1", + "@rolldown/binding-linux-x64-gnu": "1.2.1", + "@rolldown/binding-linux-x64-musl": "1.2.1", + "@rolldown/binding-openharmony-arm64": "1.2.1", + "@rolldown/binding-wasm32-wasi": "1.2.1", + "@rolldown/binding-win32-arm64-msvc": "1.2.1", + "@rolldown/binding-win32-x64-msvc": "1.2.1" } }, "node_modules/safe-array-concat": { @@ -10238,9 +10296,9 @@ } }, "node_modules/source-pane": { - "version": "3.1.1-4", - "resolved": "https://registry.npmjs.org/source-pane/-/source-pane-3.1.1-4.tgz", - "integrity": "sha512-MVl65r5eQKpzRdKZz3q2fGTo6vAsl4E3WAKJFOKk9Bu3NdkoLvVr6msvQzPlfhD52+978yfQjPLg/le3JgIhrA==", + "version": "3.1.1-5", + "resolved": "https://registry.npmjs.org/source-pane/-/source-pane-3.1.1-5.tgz", + "integrity": "sha512-pY0ieyRHpBjHRKHVKe7RL6Jv2f0grLuRe7VbiiIeV53FHKN7++dcTL6CKcWX1HYKygiWK7eg/04lRXwIwxYCiA==", "license": "MIT", "dependencies": { "@codemirror/commands": "^6.10.0", @@ -10261,7 +10319,7 @@ "pane-registry": "3.1.2-2", "rdflib": "2.4.0", "solid-logic": "4.0.8-1", - "solid-ui": "3.1.3-11", + "solid-ui": "3.1.3-13", "vite": "^8.0.16", "vitest": "^4.0.18", "vitest-axe": "^0.1.0" @@ -10613,9 +10671,9 @@ } }, "node_modules/tinyrainbow": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", + "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", "license": "MIT", "engines": { "node": ">=14.0.0" @@ -10903,9 +10961,9 @@ } }, "node_modules/undici": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", - "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz", + "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==", "devOptional": true, "license": "MIT", "engines": { @@ -11308,6 +11366,16 @@ "tslib": "^2.4.0" } }, + "node_modules/vite/node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/vite/node_modules/@oxc-project/types": { "version": "0.139.0", "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.139.0.tgz", diff --git a/package.json b/package.json index 0488fe62..36967d3c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "solid-panes", - "version": "4.4.2-4", + "version": "4.4.2-5", "description": "Solid-compatible Panes: applets and views for the mashlib and databrowser", "main": "dist/index.cjs.js", "types": "dist/index.d.ts", @@ -58,7 +58,7 @@ "dependencies": { "@solid/better-simple-slideshow": "^0.1.0", "activitystreams-pane": "1.0.3-4", - "chat-pane": "3.0.4-2", + "chat-pane": "3.0.4-3", "contacts-pane": "3.2.1-5", "dompurify": "^3.4.4", "folder-pane": "3.1.1-2", @@ -68,18 +68,12 @@ "meeting-pane": "3.0.3-1", "mime-types": "^3.0.2", "pane-registry": "3.1.2-2", - "profile-pane": "3.2.3-3", + "profile-pane": "3.2.3-4", "rdflib": "2.4.0", "solid-logic": "4.0.8-1", "solid-namespace": "^0.5.4", "solid-ui": "3.1.3-13", - "source-pane": "3.1.1-4" - }, - "overrides": { - "rdflib": "$rdflib", - "solid-logic": "$solid-logic", - "solid-ui": "$solid-ui", - "pane-registry": "$pane-registry" + "source-pane": "3.1.1-5" }, "devDependencies": { "@iconify/json": "2.2.494", diff --git a/src/components/navbar/Navbar.styles.css b/src/components/navbar/Navbar.styles.css new file mode 100644 index 00000000..faf67c84 --- /dev/null +++ b/src/components/navbar/Navbar.styles.css @@ -0,0 +1,36 @@ +:host { + display: block; +} + +:host(.navbar--hidden) { + display: none !important; +} + +.navbar { + border: 1px solid var(--color-border, #444); + border-radius: 5px; + display: flex; + background: var(--solid-ui-color-white, #fff); + overflow: hidden; +} + +button { + padding: 10px 25px; + border-bottom: 2px solid transparent; + font-weight: 500; + font-size: 90%; + background: transparent; + color: inherit; + cursor: pointer; +} + +button.selected, +button:active, +button:hover, +button:focus { + border-bottom-color: var(--solid-ui-color-primary, #7C4DFF); + border-radius: 0; + color: var(--solid-ui-color-primary, #7C4DFF); + text-transform: capitalize; + background: color-mix(in srgb, currentColor 25%, transparent); +} diff --git a/src/components/navbar/Navbar.ts b/src/components/navbar/Navbar.ts new file mode 100644 index 00000000..c4508171 --- /dev/null +++ b/src/components/navbar/Navbar.ts @@ -0,0 +1,51 @@ +import { customElement, WebComponent } from 'solid-ui' +import { html, TemplateResult } from 'lit' +import { property } from 'lit/decorators.js' + +import 'solid-ui/components/account' +import 'solid-ui/components/button' +import 'solid-ui/components/menu-item' +import 'solid-ui/components/menu' +import 'solid-ui/components/solid-emblem' +import '~icons/lucide/help-circle' + +import styles from './Navbar.styles.css' + +export interface NavbarMenuItem { + label: string | TemplateResult + selected?: boolean + onSelected?(): void +} + +@customElement('solid-panes-navbar') +export default class Navbar extends WebComponent { + static styles = styles + + @property({ type: Array }) + accessor navbarItems: NavbarMenuItem[] = [] + + private selectItem (item: NavbarMenuItem) { + this.navbarItems = this.navbarItems.map(menuItem => ({ + ...menuItem, + selected: menuItem === item + })) + item.onSelected?.() + } + + render () { + return html` + + ` + } +} diff --git a/src/components/navbar/index.ts b/src/components/navbar/index.ts new file mode 100644 index 00000000..ded2575b --- /dev/null +++ b/src/components/navbar/index.ts @@ -0,0 +1,4 @@ +import Navbar from './Navbar' + +export { Navbar } +export default Navbar diff --git a/src/dashboard/homepage.ts b/src/dashboard/homepage.ts index e52842bd..40e735b9 100644 --- a/src/dashboard/homepage.ts +++ b/src/dashboard/homepage.ts @@ -1,12 +1,12 @@ import { Fetcher, IndexedFormula, NamedNode } from 'rdflib' -import { loadProfileFromURI, getName } from '../profileUtils/ownerProfile' +import { loadProfileFromURI, getName } from '../utils/webIdUtils' export async function generateHomepage ( uri: NamedNode, store: IndexedFormula, fetcher: Fetcher ): Promise { - const ownersProfile = await loadProfileFromURI(uri, store, fetcher) + const ownersProfile = await loadProfileFromURI(uri) const name = getName(store, ownersProfile) const wrapper = document.createElement('div') diff --git a/src/mainPage/header.ts b/src/mainPage/header.ts index c2ac2ec8..4b45bb8e 100644 --- a/src/mainPage/header.ts +++ b/src/mainPage/header.ts @@ -9,6 +9,8 @@ import '~icons/lucide/folder-open' import '~icons/lucide/layout-dashboard' import '~icons/lucide/settings-2' import '../components/header' +import { getProfilePaneFromURI, getSocialPaneFromURI, getFolderPanesFromURI } from '../utils/paneUtils' +import { sym } from 'rdflib' export async function createHeader (outliner: OutlineManager) { const existingHeader = document.querySelector('solid-panes-header') @@ -17,56 +19,72 @@ export async function createHeader (outliner: OutlineManager) { return existingHeader } + const me = authn.currentUser() + const main = document.getElementById('MainContent') + const outlineView = document.getElementById('OutlineView') const tmpContainer = document.createElement('div') + + function hideNavbar () { + const navbar = document.querySelector('solid-panes-navbar') + if (navbar) { + navbar.classList.add('navbar--hidden') + } + } + + const storagePanes = me ? await getFolderPanesFromURI(me) : [] + const storageMenuItems: AccountMenuItem[] = storagePanes.map(pane => ({ + label: html` ${pane.label()}`, + async onSelected () { + hideNavbar() + if (me) { + outliner.GotoSubject(sym(window.location.href), true, pane, true, undefined, outlineView, false) + } + } + })) const menuItems: AccountMenuItem[] = [ { label: html` Profile`, - onSelected () { - const currentUser = authn.currentUser() - - if (currentUser) { - outliner.showDashboard(currentUser, { pane: 'profile' }) + async onSelected () { + hideNavbar() + if (me) { + const profilePane = await getProfilePaneFromURI(me) + outliner.GotoSubject(sym(window.location.href), true, profilePane, true, undefined, outlineView, false) } } }, { label: html` Friends`, - onSelected () { - const currentUser = authn.currentUser() - - if (currentUser) { - outliner.showDashboard(currentUser, { pane: 'social' }) - } - } - }, - { - label: html` Storage`, - onSelected () { - const currentUser = authn.currentUser() - - if (currentUser) { - outliner.showDashboard(currentUser, { pane: 'folder' }) + async onSelected () { + hideNavbar() + if (me) { + const socialPane = await getSocialPaneFromURI(me) + outliner.GotoSubject(sym(window.location.href), true, socialPane, true, undefined, outlineView, false) } } }, + ...storageMenuItems, { label: html` Dashboard`, onSelected () { - const currentUser = authn.currentUser() - - if (currentUser) { - outliner.showDashboard(currentUser, { pane: 'home' }) + hideNavbar() + if (me) { + const pane = outliner.context.session.paneRegistry.byName('home') + if (pane) { + outliner.GotoSubject(sym(window.location.href), true, pane, true, undefined, outlineView, false) + } } } }, { label: html` Preferences`, onSelected () { - const currentUser = authn.currentUser() - - if (currentUser) { - outliner.showDashboard(currentUser, { pane: 'basicPreferences' }) + hideNavbar() + if (me) { + const pane = outliner.context.session.paneRegistry.byName('basicPreferences') + if (pane) { + outliner.GotoSubject(sym(window.location.href), true, pane, true, undefined, outlineView, false) + } } } }, diff --git a/src/mainPage/index.ts b/src/mainPage/index.ts index e19cd646..bf0030c5 100644 --- a/src/mainPage/index.ts +++ b/src/mainPage/index.ts @@ -7,6 +7,9 @@ import { LiveStore, NamedNode } from 'rdflib' import type { RenderEnvironment } from 'pane-registry' import { getOutliner, OutlineManager } from '../index' import { createHeader } from './header' +import { createNavbar } from './navbar' +import { getProfilePaneFromURI } from '../utils/paneUtils' +import { isWebIdUri } from '../utils/webIdUtils' // Symbol used to stash the last render-relevant env snapshot on the outliner // so refreshUI can skip a full GotoSubject re-render when nothing changed. @@ -40,10 +43,16 @@ export async function initMainPage ( ;(outliner as any)[LAST_RENDER_ENV_KEY] = renderEnvSignature(environment) uri = uri || window.location.href const subject: NamedNode = typeof uri === 'string' ? store.sym(uri) : uri - outliner.GotoSubject(subject, true, undefined, true, undefined) + const historyPane = window.history.state?.paneName + const initialPane = !historyPane && isWebIdUri(subject) + ? await getProfilePaneFromURI(subject) + : undefined + + outliner.GotoSubject(subject, true, initialPane, true, undefined) const header = await createHeader(outliner) - return Promise.all([header]) + const navbar = await createNavbar(outliner) + return Promise.all([header, navbar]) } export async function refreshUI (outliner: OutlineManager) { diff --git a/src/mainPage/navbar.ts b/src/mainPage/navbar.ts new file mode 100644 index 00000000..d04152f3 --- /dev/null +++ b/src/mainPage/navbar.ts @@ -0,0 +1,114 @@ +import { store } from 'solid-logic' +import { NamedNode } from 'rdflib' +import { getSocialPaneFromURI, getProfilePaneFromURI, getFolderPanesFromURI } from '../utils/paneUtils' +import { html, render } from 'lit-html' +import type { OutlineManager } from '../outline/manager' +import { isWebIdUri, loadProfileFromURI } from '../utils/webIdUtils' + +import '~icons/lucide/user' +import '~icons/lucide/users' +import '~icons/lucide/folder-open' +import '../components/navbar' + +import type { NavbarMenuItem } from '../components/navbar/Navbar' + +function showNavbar () { + const navbar = document.querySelector('solid-panes-navbar') + if (navbar) { + navbar.classList.remove('navbar--hidden') + } +} + +function createNavItem ( + label: string, + onSelected: () => void, + selected = false +): NavbarMenuItem { + return { + label, + onSelected () { + showNavbar() + return onSelected() + }, + selected + } +} + +async function createNavbarMenuItems ( + outliner: OutlineManager, + subject: NamedNode, + outlineView: HTMLElement | null, + selectedPaneName?: string +): Promise { + const webId = await loadProfileFromURI(subject) + const selectedPane = selectedPaneName || (isWebIdUri(subject) ? 'profile' : undefined) + + const menuItems: NavbarMenuItem[] = [] + + if (webId) { + menuItems.push( + createNavItem('Profile', async () => { + const profilePane = await getProfilePaneFromURI(webId) + outliner.GotoSubject(subject, true, profilePane, true, undefined, outlineView) + }, selectedPane === 'profile'), + createNavItem('Friends', async () => { + const socialPane = await getSocialPaneFromURI(webId) + outliner.GotoSubject(subject, true, socialPane, true, undefined, outlineView) + }, selectedPane === 'social') + ) + } + + const storagePanes = await getFolderPanesFromURI(subject) + storagePanes.forEach(pane => { + menuItems.push( + createNavItem( + pane.label(), + async () => { + outliner.GotoSubject(subject, true, pane, true, undefined, outlineView) + }, + selectedPane === pane.paneName + ) + ) + }) + + return menuItems +} + +export async function createNavbar (outliner: OutlineManager) { + const existingNavbar = document.querySelector('solid-panes-navbar') + + if (existingNavbar) { + existingNavbar.classList.remove('navbar--hidden') + return existingNavbar + } + + const OutlineView = document.getElementById('OutlineView') + const mainContent = document.getElementById('MainContent') + const tmpContainer = document.createElement('div') + const uri = window.location.href + const subject: NamedNode = typeof uri === 'string' ? store.sym(uri) : uri + const selectedPaneName = window.history.state?.paneName + const menuItems = await createNavbarMenuItems(outliner, subject, OutlineView, selectedPaneName).catch((err) => { + console.error('Failed to build navbar menu items:', err) + return [] + }) + + render( + html``, + tmpContainer + ) + + const navbar = tmpContainer.firstElementChild as HTMLElement | null + + if (!navbar) { + throw new Error('Failed to create nav bar') + } + + if (mainContent) { + mainContent.insertBefore(navbar, mainContent.firstChild) + } else { + document.body.prepend(navbar) + } + + return navbar +} diff --git a/src/outline/manager.css b/src/outline/manager.css index c1da1ff7..8cfc5614 100644 --- a/src/outline/manager.css +++ b/src/outline/manager.css @@ -68,11 +68,12 @@ } .tdFlex { - margin: var(--spacing-xxxs, 0.2rem); - border: none; - padding: 0; + border: 1px solid var(--color-border, #444); + border-radius: 5px; vertical-align: top; display: flex; justify-content: space-between; flex-direction: row; + background: var(--solid-ui-color-white, #fff); + overflow: hidden; } diff --git a/src/outline/manager.js b/src/outline/manager.js index 124de4ca..a764f190 100644 --- a/src/outline/manager.js +++ b/src/outline/manager.js @@ -6,26 +6,17 @@ import * as paneRegistry from 'pane-registry' import './manager.css' import * as $rdf from 'rdflib' import * as UI from 'solid-ui' -import { authn, authSession, store } from 'solid-logic' +import { store } from 'solid-logic' import { propertyViews } from './propertyViews' import { outlineIcons } from './outlineIcons.js' // @@ chec import { UserInput } from './userInput.js' import * as queryByExample from './queryByExample.js' -import { getNameOfPodOwner } from '../profileUtils/ownerProfile' +import { loadContainerRepresentation } from '../utils/podUtils' import personIcon from '../icons/person.svg' import friendsIcon from '../icons/friends.svg' -import folderIcon from '../icons/folder.svg' -import dashboardIcon from '../icons/dashboard.svg' const PERSON_ICON = personIcon const FRIENDS_ICON = friendsIcon -const FOLDER_ICON = folderIcon -const DASHBOARD_ICON = dashboardIcon - -/* global alert XPathResult sourceWidget */ -// XPathResult? - -// const iconHeight = '24px' export default function (context) { const dom = context.dom @@ -311,259 +302,19 @@ export default function (context) { return predicateTD } // outlinePredicateTD - /** - * Render Tabbed set of home app panes - * - * @param {Object} [options] A set of options you can provide - * @param {string} [options.selectedTab] To open a specific dashboard pane - * @param {Function} [options.onClose] If given, will present an X for the dashboard, and call this method when clicked - * @returns Promise<{Element}> - the div that holds the dashboard - */ - async function globalAppTabs (options = {}) { - console.log('globalAppTabs @@') - const div = dom.createElement('div') - const me = authn.currentUser() - if (!me) { - alert('Must be logged in for this') - throw new Error('Not logged in') - } - const items = await getDashboardItems() - - const selectedItem = options.selectedTab - ? items.find( - item => item.paneName === options.selectedTab || item.tabName === options.selectedTab - ) - : items[0] - - if (!selectedItem) { - return div - } - - div.dataset.globalPaneName = selectedItem.tabName || selectedItem.paneName - - const content = div.appendChild(dom.createElement('div')) - const pane = paneRegistry.byName(selectedItem.paneName) // 20190701 - const table = content.appendChild(dom.createElement('table')) - thisOutline.GotoSubject( - selectedItem.subject || me, - true, - pane, - false, - undefined, - table - ) - - return div - } - this.getDashboard = globalAppTabs - - async function getDashboardItems () { - const me = authn.currentUser() - if (!me) return [] - const div = dom.createElement('div') - const panes = [ - { - paneName: 'profile', - subject: me, - label: 'Your profile', - icon: PERSON_ICON - }, - { - paneName: 'social', // loads socialPane - subject: me, - label: 'Your friends', - icon: FRIENDS_ICON - } - ] - - const [pods] = await Promise.all([getPods()]) - - panes.push(...pods) - - panes.push( - /* not in use since redesign of profile-pane - { - paneName: 'editProfile', - label: 'Edit your Profile', - icon: UI.icons.iconBase + 'noun_492246.svg' - }, - */ - { - paneName: 'home', - label: 'Your dashboard', - icon: DASHBOARD_ICON - }, - { - paneName: 'basicPreferences', - label: 'Your preferences', - icon: UI.icons.iconBase + 'noun_Sliders_341315_000000.svg' - } - ) - - return panes - - async function getPods () { - async function addPodStorage (pod) { // namedNode - await loadContainerRepresentation(pod) - if (kb.holds(pod, ns.rdf('type'), ns.space('Storage'), pod.doc())) { - pods.push(pod) - return true - } - return false - } - async function addPodStorageFromUrl (url) { - const podStorage = new URL(url) - // check for predicate pim:Storage in containers up the path tree - let pathStorage = podStorage.pathname - while (pathStorage.length) { - pathStorage = pathStorage.substring(0, pathStorage.lastIndexOf('/')) - if (await addPodStorage(kb.sym(`${podStorage.origin}${pathStorage}/`))) return - } - // TODO should url.origin be added to pods list when there are no pim:Storage ??? - } - - try { - // need to make sure that profile is loaded - await kb.fetcher.load(me.doc()) - } catch (err) { - console.error('Unable to load profile', err) - return [] - } - // load pod's storages from profile - let pods = kb.each(me, ns.space('storage'), null, me.doc()) - await Promise.all( - pods.map(async (pod) => { - // TODO use addPodStorageFromUrl(pod.uri) to check for pim:Storage ??? - await loadContainerRepresentation(pod) - }) - ) - - try { - // if uri then SolidOS is a browse.html web app - const uri = (new URL(window.location.href)).searchParams.get('uri') - const podUrl = uri || window.location.href - await addPodStorageFromUrl(podUrl) - } catch (err) { - console.error('cannot load container', err) - } - // remove namedNodes duplicates - function uniques (nodes) { - const uniqueNodes = [] - nodes.forEach(node => { - if (!uniqueNodes.find(uniqueNode => uniqueNode.equals(node))) uniqueNodes.push(node) - }) - return uniqueNodes - } - pods = uniques(pods) - if (!pods.length) return [] - return Promise.all( - pods.map(async (pod, index) => { - function split (item) { return item.uri.split('//')[1].slice(0, -1) } - const ownerName = (await getNameOfPodOwner(pod, kb, sf)) || '' - const label = split(me).startsWith(split(pod)) - ? 'Your storage' - : ownerName.trim() !== '' - ? ownerName + '\'s storage' - : split(pod) - return { - paneName: 'folder', - tabName: `folder-${index}`, - label, - subject: pod, - icon: FOLDER_ICON - } - }) - ) - } - - async function getAddressBooks () { - try { - const context = await UI.login.findAppInstances( - { me, div, dom }, - ns.vcard('AddressBook') - ) - return (context.instances || []).map((book, index) => ({ - paneName: 'contact', - tabName: `contact-${index}`, - label: 'Contacts', - subject: book, - icon: UI.icons.iconBase + 'noun_15695.svg' - })) - } catch (err) { - console.error('oops in globalAppTabs AddressBook') - } - return [] - } - } - this.getDashboardItems = getDashboardItems - - /** - * Call this method to show the global dashboard. - * - * @param {Object} [options] A set of options that can be passed - * @param {string} [options.pane] To open a specific dashboard pane - * @returns {Promise} - */ - function closeDashboard () { - const dashboardContainer = getDashboardContainer() - const outlineContainer = getOutlineContainer() - dashboardContainer.innerHTML = '' - hideGlobalContainer(dashboardContainer) - showGlobalContainer(outlineContainer) - } - - // Register the closeDashboard listener only once - authSession.events.on('logout', closeDashboard) - - function showGlobalContainer (container) { - container.removeAttribute('hidden') - container.style.display = '' + function getOutlineContainer () { + return getOrCreateContainer('OutlineView', 'Resource browser') } - function hideGlobalContainer (container) { - container.setAttribute('hidden', '') - container.style.display = 'none' + function getNavbarElement () { + return document.querySelector('solid-panes-navbar') } - async function showDashboard (subject, options = {}) { - const dashboardContainer = getDashboardContainer() - const outlineContainer = getOutlineContainer() - - // reuse existing dashboard if already rendered for the same pane and subject - if (dashboardContainer.childNodes.length > 0) { - const existingDashboard = dashboardContainer.firstElementChild - if ( - existingDashboard && - options.pane && - existingDashboard.dataset.globalPaneName === options.pane && - existingDashboard.dataset.subject === ((subject && subject.value) || '') - ) { - hideGlobalContainer(outlineContainer) - showGlobalContainer(dashboardContainer) - return - } - dashboardContainer.innerHTML = '' + function showSolidPanesNavbar () { + const navbar = getNavbarElement() + if (navbar) { + navbar.classList.remove('navbar--hidden') } - - // create a new dashboard if not already present - const dashboard = await globalAppTabs({ - selectedTab: options.pane, - // onClose: closeDashboard - }) - - // finally - switch to showing dashboard - hideGlobalContainer(outlineContainer) - showGlobalContainer(dashboardContainer) - dashboardContainer.appendChild(dashboard) - } - this.showDashboard = showDashboard - - function getDashboardContainer () { - return getOrCreateContainer('GlobalDashboard', 'Dashboard') - } - - function getOutlineContainer () { - return getOrCreateContainer('OutlineView', 'Resource browser') } /** @@ -575,9 +326,7 @@ export default function (context) { */ function getOrCreateContainer (id) { const containerHost = - document.getElementById('app-view') || document.getElementById('MainContent') || - document.querySelector('[role="main"]') || document.body // OutlineView is a table @@ -587,6 +336,10 @@ export default function (context) { return existingOutline } + const containerHost = + document.getElementById('MainContent') || + document.body + if (containerHost) { const OutlineView = document.createElement('table') OutlineView.id = 'OutlineView' @@ -596,27 +349,6 @@ export default function (context) { return OutlineView } } - - // or we deal with the section GlobalDashboard - return ( - document.getElementById(id) || - (() => { - const GlobalDashboard = document.createElement('section') - GlobalDashboard.id = id - GlobalDashboard.setAttribute('aria-label', 'Dashboard') - GlobalDashboard.classList.add('global-dashboard') - return containerHost.appendChild(GlobalDashboard) - })() - ) - } - - async function loadContainerRepresentation (subject) { - // force reload for index.html with RDFa - if (!kb.any(subject, ns.ldp('contains'), undefined, subject.doc())) { - const response = await kb.fetcher.webOperation('GET', subject.uri, kb.fetcher.initFetchOptions(subject.uri, { headers: { accept: 'text/turtle' } })) - const containerTurtle = response.responseText - $rdf.parse(containerTurtle, kb, subject.uri, 'text/turtle') - } } async function getRelevantPanes (subject, context) { @@ -652,7 +384,17 @@ export default function (context) { } async function expandedHeaderTR (subject, requiredPane, options) { + async function determineFirstPane (options = {}) { + const relevantPanes = options.hideList + ? [] + : await getRelevantPanes(subject, context) + tr.firstPane = requiredPane || getPane(relevantPanes, subject) + } + async function renderPaneIconTray (td, options = {}) { + // Icon tray removed: this UI is no longer needed. + // The tray previously populated pane selection buttons, + // but pane selection itself is retained via tr.firstPane. const paneShownStyle = 'width: 24px; border-radius: 0.5em; border-top: solid #222 1px; border-left: solid #222 0.1em; border-bottom: solid #eee 0.1em; border-right: solid #eee 0.1em; margin-left: 1em; padding: 3px; background-color: #ffd;' const paneHiddenStyle = @@ -813,12 +555,7 @@ export default function (context) { tr.setAttribute('class', 'hoverControl') } const td = tr.appendChild(dom.createElement('td')) - td.setAttribute( - 'style', - 'margin: 0.2em; border: none; padding-top: 0; padding-bottom: 0; vertical-align: top;' + - 'display:flex; justify-content: space-between; flex-direction: row;' + - 'background-color: var(--color-background, #F8F9FB);' - ) + td.classList.add('tdFlex') td.setAttribute('notSelectable', 'true') td.setAttribute('about', subject.toNT()) td.setAttribute('colspan', '2') @@ -847,21 +584,29 @@ export default function (context) { 'font-size: 150%; margin: 0 0.6em 0 0; padding: 0.1em 0.4em;' + 'background-color: var(--color-background, #F8F9FB);' UI.widgets.makeDraggable(strong, subject) + + header.appendChild( + await renderPaneIconTray(td, { + hideList: showHeader + }) + ) } - header.appendChild( - await renderPaneIconTray(td, { - hideList: showHeader - }) - ) + // Pane icon tray removed: preserve first-pane selection without rendering the tray. + await determineFirstPane({ hideList: showHeader }) - // set DOM methods + // Hide the header row when the header div has no rendered children. + if (header.childNodes.length === 0) { + tr.style.display = 'none' + } + + /* // set DOM methods tr.firstChild.tabulatorSelect = function () { setSelected(this, true) } tr.firstChild.tabulatorDeselect = function () { setSelected(this, false) - } + } */ return tr } // expandedHeaderTR @@ -1261,64 +1006,6 @@ export default function (context) { // Summarize a thing as a table cell - /********************** - - query global vars - - ***********************/ - - // const doesn't work in Opera - // const BLANK_QUERY = { pat: kb.formula(), vars: [], orderBy: [] }; - // @ pat: the query pattern in an RDFIndexedFormula. Statements are in pat.statements - // @ vars: the free variables in the query - // @ orderBy: the variables to order the table - - function QueryObj () { - this.pat = kb.formula() - this.vars = [] - // this.orderBy = [] - } - - const queries = [] - queries[0] = new QueryObj() - /* - function querySave () { - queries.push(queries[0]) - var choices = dom.getElementById('queryChoices') - var next = dom.createElement('option') - var box = dom.createElement('input') - var index = queries.length - 1 - box.setAttribute('type', 'checkBox') - box.setAttribute('value', index) - choices.appendChild(box) - choices.appendChild(dom.createTextNode('Saved query #' + index)) - choices.appendChild(dom.createElement('br')) - next.setAttribute('value', index) - next.appendChild(dom.createTextNode('Saved query #' + index)) - dom.getElementById('queryJump').appendChild(next) - } -*/ - /* - function resetQuery () { - function resetOutliner (pat) { - var n = pat.statements.length - var pattern, tr - for (let i = 0; i < n; i++) { - pattern = pat.statements[i] - tr = pattern.tr - // UI.log.debug('tr: ' + tr.AJAR_statement); - if (typeof tr !== 'undefined') { - delete tr.AJAR_pattern - delete tr.AJAR_variable - } - } - for (let x in pat.optional) { resetOutliner(pat.optional[x]) } - } - resetOutliner(myQuery.pat) - UI.utils.clearVariableNames() - queries[0] = myQuery = new QueryObj() - } -*/ function addButtonCallbacks (target, fireOn) { UI.log.debug('Button callbacks for ' + fireOn + ' added') const makeIconCallback = function (icon) { @@ -1434,6 +1121,8 @@ export default function (context) { } } + /* global alert XPathResult sourceWidget */ + this.showSource = function showSource () { if (typeof sourceWidget === 'undefined') return // deselect all before going on, this is necessary because you would switch tab, @@ -1795,28 +1484,6 @@ export default function (context) { } // end of switch showURI(UI.utils.getAbout(kb, selection[0])) - // alert(window);alert(doc); - /* - var wm = Components.classes['@mozilla.org/appshell/window-mediator;1'] - .getService(Components.interfaces.nsIWindowMediator); - var gBrowser = wm.getMostRecentWindow('navigator:browser') */ - // gBrowser.addTab('http://www.w3.org/'); - // alert(gBrowser.addTab);alert(gBrowser.scroll);alert(gBrowser.scrollBy) - // gBrowser.scrollBy(0,100); - - // var thisHtml=selection[0].owner - if (selection[0]) { - const PosY = UI.utils.findPos(selection[0])[1] - if ( - PosY + selection[0].clientHeight > - window.scrollY + window.innerHeight - ) { - UI.utils.getEyeFocus(selection[0], true, true, window) - } - if (PosY < window.scrollY + 54) { - UI.utils.getEyeFocus(selection[0], true, undefined, window) - } - } } this.OutlinerMouseclickPanel = function (e) { switch (thisOutline.UserInput._tabulatorMode) { @@ -2352,15 +2019,21 @@ export default function (context) { /** Display the subject in an outline view - @param subject -- RDF term for teh thing to be presented + @param subject -- RDF term for the thing to be presented @param expand -- flag -- open the subject rather than keep folded closed @param pane -- optional -- pane to be used for expanded display @param solo -- optional -- the window will be cleared out and only the subject displayed @param referer -- optional -- where did we hear about this from anyway? @param table -- option -- default is an HTML table element in which to put the outline. + @param showNavbar -- optional -- when false, suppress automatic navbar reveal */ - this.GotoSubject = function (subject, expand, pane, solo, referrer, table) { - table = table || getOutlineContainer('OutlineView') // if does not exist create a compatible host in the current shell + this.GotoSubject = function (subject, expand, pane, solo, referrer, table, showNavbar = true) { + const outlineContainer = getOutlineContainer() + if (showNavbar && (!table || table === outlineContainer)) { + showSolidPanesNavbar() + } + + table = table || outlineContainer // if does not exist create a compatible host in the current shell if (solo) { UI.utils.emptyNode(table) table.style.width = '100%' @@ -2420,8 +2093,6 @@ export default function (context) { // // / ///////////////////////////////////////////////////// - const ns = UI.ns - const views = propertyViews(dom) // var thisOutline = this dup diff --git a/src/profileUtils/ownerProfile.ts b/src/profileUtils/ownerProfile.ts deleted file mode 100644 index 57c9c348..00000000 --- a/src/profileUtils/ownerProfile.ts +++ /dev/null @@ -1,96 +0,0 @@ -/* -* Utility functions to help load the profile -* especially when I am not logged in -*/ - -import { Fetcher, IndexedFormula, NamedNode, sym } from 'rdflib' -import { ns } from 'solid-ui' - -const DEFAULT_PROFILE_PATH = 'profile/card#me' - -export async function loadProfileFromURI ( - uri: NamedNode, - store: IndexedFormula, - fetcher: Fetcher -): Promise { - const pod = uri.site().uri - // TODO: This is a hack - we cannot assume that the profile is at this document, but we will live with it for now - const webId = sym(`${pod}${DEFAULT_PROFILE_PATH}`) - try { - await fetcher.load(webId) - return webId - } catch (err) { - // continue - } - - // we try a prefixed pod structure - try { - const uriUrl = new URL(uri.uri) - const pathSegments = uriUrl.pathname.split('/').filter(Boolean) - if (pathSegments.length > 0) { - const derivedPod = `${uriUrl.origin}/${pathSegments[0]}/` - const derivedWebId = sym(`${derivedPod}${DEFAULT_PROFILE_PATH}`) - await fetcher.load(derivedWebId) - return derivedWebId - } - } catch (err) { - // continue - } - - try { - await fetcher.load(uri) - } catch (err) { - return uri - } - - const primaryTopic = store.any(uri, ns.foaf('primaryTopic'), null, uri.doc()) - if (primaryTopic && primaryTopic.termType === 'NamedNode') { - try { - await fetcher.load(primaryTopic as NamedNode) - return primaryTopic as NamedNode - } catch (err) { - return uri - } - } - - return uri -} - -export async function getNameOfPodOwner ( - pod: NamedNode, - store: IndexedFormula, - fetcher: Fetcher -): Promise { - // TODO: This is a hack - we cannot assume that the profile is at this document, but we will live with it for now - const webId = sym(`${pod.uri}${DEFAULT_PROFILE_PATH}`) - try { - await fetcher.load(webId) - return getName(store, webId) - } catch (err) { - // continue - } - - // we try a prefixed pod structure - try { - const uriUrl = new URL(pod.uri) - const pathSegments = uriUrl.pathname.split('/').filter(Boolean) - if (pathSegments.length > 0) { - const derivedPod = `${uriUrl.origin}/${pathSegments[0]}/` - const derivedWebId = sym(`${derivedPod}${DEFAULT_PROFILE_PATH}`) - await fetcher.load(derivedWebId) - return getName(store, derivedWebId) - } - } catch (err) { - // continue - } - - return '' -} - -export function getName (store: IndexedFormula, ownersProfile: NamedNode): string { - return ( - store.anyValue(ownersProfile, ns.vcard('fn'), null, ownersProfile.doc()) || - store.anyValue(ownersProfile, ns.foaf('name'), null, ownersProfile.doc()) || - new URL(ownersProfile.uri).host.split('.')[0] - ) -} diff --git a/src/social/socialPane.css b/src/social/socialPane.css index 8a49b846..054dd9db 100644 --- a/src/social/socialPane.css +++ b/src/social/socialPane.css @@ -9,7 +9,7 @@ min-width: 100%; box-sizing: border-box; max-width: none; - margin: 0; + margin-top: 20px; } .social-pane__header-content { @@ -982,12 +982,6 @@ /* From tabbedtab.css */ /* ***************** Social Pane **********/ -div.social-pane { - padding-top: 0; - padding-bottom: 0; - margin: 0; -} - .social-pane a { color: var(--color-primary, #7C4DFF); text-decoration: none; diff --git a/src/utils/paneUtils.ts b/src/utils/paneUtils.ts new file mode 100644 index 00000000..6e23026b --- /dev/null +++ b/src/utils/paneUtils.ts @@ -0,0 +1,95 @@ +import * as paneRegistry from 'pane-registry' +import folderIcon from '../icons/folder.svg' +import personIcon from '../icons/person.svg' +import friendsIcon from '../icons/friends.svg' +import { loadProfileFromURI } from './webIdUtils' +import { getPodStorages } from './podUtils' +import { NamedNode, sym } from 'rdflib' + +const FOLDER_ICON = folderIcon +const PERSON_ICON = personIcon +const FRIENDS_ICON = friendsIcon + +export type PaneItem = { + name: string + paneName: string + tabName?: string + label: () => string + render: (subject: NamedNode, context: any, options: any) => any + shouldGetFocus: () => boolean + requireQueryButton: boolean + subject: NamedNode + icon: string +} + +export function createPaneItem ( + pane: any, + subject: NamedNode, + paneName: string, + labelText: string, + icon: string, + tabName?: string +): PaneItem { + return { + name: pane.name, + paneName, + tabName, + label: function () { + return labelText + }, + render: function (_subject, context, options) { + return pane.render(subject, context, options) + }, + shouldGetFocus: function () { + return false + }, + requireQueryButton: !!pane.requireQueryButton, + subject, + icon + } +} + +export async function getPaneItemFromURI ( + paneName: string, + subject?: NamedNode, + labelText = 'Pane', + icon = '' +): Promise { + const windowHref = new URL(window.location.href) + const finalURL = subject || sym(windowHref.toString()) + const webId = await loadProfileFromURI(finalURL) + if (!webId || !webId.value) return null + + const pane = paneRegistry.byName(paneName) + if (!pane) return null + + return createPaneItem(pane, webId, paneName, labelText, icon) +} + +export async function getProfilePaneFromURI (subject?: NamedNode) { + return getPaneItemFromURI('profile', subject, 'Profile', PERSON_ICON) +} + +export async function getSocialPaneFromURI (subject?: NamedNode) { + return getPaneItemFromURI('social', subject, 'Social', FRIENDS_ICON) +} + +export async function getFolderPaneforStorage (podUrl: NamedNode, label?: string): Promise { + const folderPane = paneRegistry.byName('folder') + if (!folderPane) return null + + return createPaneItem(folderPane, podUrl, folderPane.name, label || 'Storage', FOLDER_ICON) +} +export async function getFolderPanesFromURI (subject: NamedNode): Promise { + const podStorages = await getPodStorages(subject) + if (podStorages.length === 0) return [] + + return Promise.all( + podStorages.map((pod, index) => + getFolderPaneforStorage( + pod, + podStorages.length > 1 ? `Storage ${index + 1}` : 'Storage' + ) + ) + ).then(panes => panes.filter((pane): pane is PaneItem => pane !== null)) +} diff --git a/src/utils/podUtils.ts b/src/utils/podUtils.ts new file mode 100644 index 00000000..aa7b4aaa --- /dev/null +++ b/src/utils/podUtils.ts @@ -0,0 +1,58 @@ +import { store } from 'solid-logic' +import { ns } from 'solid-ui' +import { NamedNode, parse } from 'rdflib' +import { isWebIdUri } from './webIdUtils' + +export async function getPodStorages (url: NamedNode): Promise { + if (isWebIdUri(url)) { + try { + await store.fetcher.load(url.doc()) + } catch (err) { + console.warn('Unable to load profile document for WebID', url.doc().uri, err) + } + const podStorages = store.each(url, ns.space('storage')) + const results = await Promise.all(podStorages.map(async pod => await isPodStorage(pod as NamedNode) ? pod as NamedNode : null)) + return results.filter(pod => pod !== null) as NamedNode[] + } + try { + const storage = await findPodStorageFromUrl(url) + return storage ? [storage] : [] + } catch (err) { + console.error('cannot load container', err) + return [] + } +} + +async function findPodStorageFromUrl (url: NamedNode): Promise { + const podStorage = new URL(url.value || url.uri) + let pathStorage = podStorage.pathname + + while (pathStorage.length) { + pathStorage = pathStorage.substring(0, pathStorage.lastIndexOf('/')) + const candidate = store.sym(`${podStorage.origin}${pathStorage}/`) + if (await isPodStorage(candidate)) return candidate + } + + // TODO should url.origin be added to pods list when there are no pim:Storage ??? + return null +} + +async function isPodStorage (pod: NamedNode): Promise { + await loadContainerRepresentation(pod) + return store.holds(pod, ns.rdf('type'), ns.space('Storage'), pod.doc()) +} + +export async function loadContainerRepresentation (subject) { + // force reload for index.html with RDFa + if (!store.any(subject, ns.ldp('contains'), undefined, subject.doc())) { + try { + const response = await store.fetcher.webOperation('GET', subject.uri, store.fetcher.initFetchOptions(subject.uri, { headers: { accept: 'text/turtle' } })) + const containerTurtle = response.responseText + if (subject.uri && containerTurtle) { + parse(containerTurtle, store, subject.uri, 'text/turtle') + } + } catch (err) { + console.warn('Unable to load container representation for', subject.uri, err) + } + } +} diff --git a/src/utils/webIdUtils.ts b/src/utils/webIdUtils.ts new file mode 100644 index 00000000..a961dcb5 --- /dev/null +++ b/src/utils/webIdUtils.ts @@ -0,0 +1,117 @@ +/* +* Utility functions to help load the profile +* especially when I am not logged in +*/ + +import { IndexedFormula, NamedNode, sym } from 'rdflib' +import { ns } from 'solid-ui' +import { store } from 'solid-logic' + +const DEFAULT_PROFILE_PATH = 'profile/card#me' + +export async function loadProfileFromURI ( + uri: NamedNode +): Promise { + try { + const pod = uri.site().uri + // TODO: This is a hack - we cannot assume that the profile is at this document, but we will live with it for now + const webId = sym(`${pod}${DEFAULT_PROFILE_PATH}`) + try { + await store.fetcher.load(webId) + return webId + } catch (err) { + // ignore any failure and continue fallback lookup + } + + // we try a prefixed pod structure + try { + const uriUrl = new URL(uri.uri) + const pathSegments = uriUrl.pathname.split('/').filter(Boolean) + if (pathSegments.length > 0) { + const derivedPod = `${uriUrl.origin}/${pathSegments[0]}/` + const derivedWebId = sym(`${derivedPod}${DEFAULT_PROFILE_PATH}`) + await store.fetcher.load(derivedWebId) + return derivedWebId + } + } catch (err) { + // ignore any failure and continue fallback lookup + } + + try { + await store.fetcher.load(uri) + } catch (err) { + return uri + } + + const primaryTopic = store.any(uri, ns.foaf('primaryTopic'), null, uri.doc()) + if (primaryTopic && primaryTopic.termType === 'NamedNode') { + try { + await store.fetcher.load(primaryTopic as NamedNode) + return primaryTopic as NamedNode + } catch (err) { + return uri + } + } + + return uri + } catch (err) { + return uri + } +} + +export function isWebIdUri (uri: NamedNode): boolean { + try { + const parsedURL = new URL(uri.uri) + return parsedURL.hash === '#me' + } catch (err) { + return false + } +} + +export async function getNameOfPodOwner ( + pod: NamedNode +): Promise { + // TODO: This is a hack - we cannot assume that the profile is at this document, but we will live with it for now + const webId = sym(`${pod.uri}${DEFAULT_PROFILE_PATH}`) + try { + await store.fetcher.load(webId) + return getName(store, webId) + } catch (err) { + if (!isFetchErrorStatus(err, 403)) { + console.error('getNameOfPodOwner failed on default profile:', err) + } + } + + // we try a prefixed pod structure + try { + const uriUrl = new URL(pod.uri) + const pathSegments = uriUrl.pathname.split('/').filter(Boolean) + if (pathSegments.length > 0) { + const derivedPod = `${uriUrl.origin}/${pathSegments[0]}/` + const derivedWebId = sym(`${derivedPod}${DEFAULT_PROFILE_PATH}`) + await store.fetcher.load(derivedWebId) + return getName(store, derivedWebId) + } + } catch (err) { + if (!isFetchErrorStatus(err, 403)) { + console.error('getNameOfPodOwner failed on derived profile:', err) + } + } + + return '' +} + +export function getName (store: IndexedFormula, ownersProfile: NamedNode): string { + return ( + store.anyValue(ownersProfile, ns.vcard('fn'), null, ownersProfile.doc()) || + store.anyValue(ownersProfile, ns.foaf('name'), null, ownersProfile.doc()) || + new URL(ownersProfile.uri).host.split('.')[0] + ) +} + +function isFetchErrorStatus (err: unknown, status: number): boolean { + if (!err || typeof err !== 'object') return false + const statusCode = (err as any)?.response?.status ?? (err as any)?.status + const parsedStatus = Number(statusCode) + return Number.isFinite(parsedStatus) && parsedStatus === status +} diff --git a/test/unit/outline/manager.test.ts b/test/unit/outline/manager.test.ts index 36799e48..6224f5eb 100644 --- a/test/unit/outline/manager.test.ts +++ b/test/unit/outline/manager.test.ts @@ -1,9 +1,24 @@ -import { beforeAll, beforeEach, describe, expect, it } from 'vitest' +import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest' + +vi.mock('solid-ui', async () => { + const actual = await vi.importActual('solid-ui') + return { + ...actual, + login: { + ...actual.login, + filterAvailablePanes: async panes => panes + } + } +}) + import OutlineManager from '../../../src/outline/manager' import { lit, NamedNode, sym, blankNode } from 'rdflib' import { findByText, getByText } from '@testing-library/dom' const MockPane = { + name: 'mock', + icon: 'data:image/svg+xml,', + label: () => 'Mock Pane', render: (subject: NamedNode) => { const div = document.createElement('div') div.appendChild(document.createTextNode(`Mock Pane for ${subject.uri}`)) @@ -12,10 +27,11 @@ const MockPane = { } const mockPaneRegistry = { - list: [], + list: [MockPane], byName: () => MockPane } + describe('manager', () => { describe('outline object td', () => { describe('for a named node', () => { diff --git a/vite.config.mts b/vite.config.mts index b8ff98ea..03829748 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -1,11 +1,54 @@ import { fileURLToPath } from 'node:url' +import type { PluginOption } from 'vite' import { solidPane, buildConfig } from 'solidos-toolkit/vite' import { defineConfig } from 'vitest/config' -export default defineConfig({ - build: buildConfig({ - entry: "src/index.ts", +// `vite build --watch` re-runs every plugin's generateBundle on each change. +// solidos-toolkit's solidPane() bundles unplugin-dts (adds ~4-5s per rebuild) +// and buildConfig() emits both ESM and CJS outputs (two rebuild cycles per +// change — noisy for downstream watchers like mashlib/webpack). During watch +// we strip both so the inner loop is fast and downstream sees a single wave +// of file writes. Full builds (npm run build) are unaffected. +const isWatch = process.argv.includes('--watch') + +const build = buildConfig({ entry: 'src/index.ts' }) +if (isWatch && build && Array.isArray(build.rolldownOptions?.output)) { + build.rolldownOptions.output = build.rolldownOptions.output.filter( + (o: { format?: string }) => o.format === 'es', + ) +} + +type ConcretePlugin = Extract + +// solidPane() returns a nested plugin array that includes an ASYNC plugin +// factory (@rolldown/plugin-babel is a Promise). The previous flatten helper +// dropped Promise entries, which silently removed the babel plugin — leaving +// TC39 decorator / `accessor` syntax in the built output (Header.esm.js etc.) +// and breaking downstream consumers (mashlib's babel-loader). Await Promises +// before flattening so every plugin makes it into the final list. +const flattenPlugins = async (input: unknown): Promise => { + if (!input) return [] + const resolved = await input + if (!resolved) return [] + if (Array.isArray(resolved)) { + const nested = await Promise.all(resolved.map(flattenPlugins)) + return nested.flat() + } + return [resolved as ConcretePlugin] +} + +const plugins = (await flattenPlugins( + solidPane({ + litDecoratorPaths: ['src/components'], + sandbox: { + subject: 'https://testingsolidos.solidcommunity.net/profile/card#me', + entry: './src/dev.ts', + }, }), +)).filter((p) => !(isWatch && /dts/i.test(p.name))) + +export default defineConfig({ + build, resolve: { tsconfigPaths: true, @@ -17,13 +60,7 @@ export default defineConfig({ UI: fileURLToPath(new URL('./node_modules/solid-ui/dist/index.esm.js', import.meta.url)), }, }, - plugins: solidPane({ - litDecoratorPaths: ['src/components'], - sandbox: { - subject: "https://testingsolidos.solidcommunity.net/profile/card#me", - entry: "./src/dev.ts", - } - }), + plugins, test: { environment: 'jsdom', setupFiles: ['test/setup.ts'],