diff --git a/package-lock.json b/package-lock.json index d8092231..b1ddd346 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "solid-panes", - "version": "4.4.2-5", + "version": "4.4.2-6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "solid-panes", - "version": "4.4.2-5", + "version": "4.4.2-6", "license": "MIT", "dependencies": { "@solid/better-simple-slideshow": "^0.1.0", @@ -14,7 +14,7 @@ "chat-pane": "3.0.4-3", "contacts-pane": "3.2.1-5", "dompurify": "^3.4.4", - "folder-pane": "3.1.1-2", + "folder-pane": "3.1.1-3", "issue-pane": "3.0.3-1", "lit-html": "^3.3.2", "marked": "^18.0.3", @@ -25,7 +25,7 @@ "rdflib": "2.4.0", "solid-logic": "4.0.8-2", "solid-namespace": "^0.5.4", - "solid-ui": "3.1.3-13", + "solid-ui": "3.1.3-15", "source-pane": "3.1.1-5" }, "devDependencies": { @@ -225,14 +225,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", - "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -579,13 +579,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", "devOptional": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.7" + "@babel/types": "^7.29.8" }, "bin": { "parser": "bin/babel-parser.js" @@ -1245,16 +1245,16 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.7.tgz", - "integrity": "sha512-TM2ZcQLoG2/y4HODiStCo10DibYhWhGWAwVv+EQKmG/7GFl0N+AAmUiXOMKM+aiJ9XBJ9AHVZBvTzMnJ2sM3cQ==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.8.tgz", + "integrity": "sha512-6iSnEK0zlkLKU4heofK/AdmRD4e2SHVpJMtrwnTCzhnaM98ria4rTrOXBBi45BTTYnJtO8txnPsX4fChYXkmeA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7", - "@babel/traverse": "^7.29.7" + "@babel/traverse": "^7.29.8" }, "engines": { "node": ">=6.9.0" @@ -1483,9 +1483,9 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.7.tgz", - "integrity": "sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.8.tgz", + "integrity": "sha512-0UpIXPtdDtMXfnV2OJAVMLpj3H/92vmkA6lpSRakmycJvj3VUy6Xs1dM8tXRugupykr5WB+LpiVl0J8LMVg2mg==", "dev": true, "license": "MIT", "dependencies": { @@ -1579,9 +1579,9 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.29.7.tgz", - "integrity": "sha512-/u5K1QWada7tbYNqTjMh96718g9NTwh9tfPJMsSmVsQwGT447FskV+KcfeXkXq2GWki4EM/MuTdmBec+hOuVTQ==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.29.8.tgz", + "integrity": "sha512-4S9ksMGVWUshvgK0mKfvZky7leuG5/uoFVwMpAomJ8bMoDJiNHRVmc1EglwW/CmGVSqqWpEbXm9FmbRit22qoA==", "dev": true, "license": "MIT", "dependencies": { @@ -1900,18 +1900,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", - "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", + "@babel/generator": "^7.29.8", "@babel/helper-globals": "^7.29.7", - "@babel/parser": "^7.29.7", + "@babel/parser": "^7.29.8", "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7", + "@babel/types": "^7.29.8", "debug": "^4.3.1" }, "engines": { @@ -1919,9 +1919,9 @@ } }, "node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1993,9 +1993,9 @@ } }, "node_modules/@codemirror/lang-html": { - "version": "6.4.11", - "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.11.tgz", - "integrity": "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==", + "version": "6.4.12", + "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.12.tgz", + "integrity": "sha512-pw2ReWKUqSkbvh76RAT4NYxiogRu+PWkR2ukAwO9uOgrm8uipkzjtKKtNpyeAQwHOqxEeSvAXZ6vr3AfyB9y/w==", "license": "MIT", "dependencies": { "@codemirror/autocomplete": "^6.0.0", @@ -2103,9 +2103,9 @@ } }, "node_modules/@codemirror/view": { - "version": "6.43.7", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.7.tgz", - "integrity": "sha512-FZsExxkoxnAN+d9TgqXLg5g4A1oQwzX9WlkOT5i2PKkcW7xx3Bmu0vs90g6fo9Mpdsb/l96dnAraQ8932aO4/g==", + "version": "6.43.8", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.8.tgz", + "integrity": "sha512-qtItTDssZ/5GFfi94hrILu9j/VUeFPDPkhovEfmWFj2ipTxnzPB8DdHgfbb8HYTzLTYhrndKmyQxXUz/PDLenw==", "license": "MIT", "dependencies": { "@codemirror/state": "^6.7.0", @@ -2333,37 +2333,6 @@ "node": ">=18.17" } }, - "node_modules/@emnapi/core": { - "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, - "dependencies": { - "@emnapi/wasi-threads": "2.0.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "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, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "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, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@emotion/is-prop-valid": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.7.3.tgz", @@ -2797,9 +2766,9 @@ "license": "MIT" }, "node_modules/@lezer/css": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.4.tgz", - "integrity": "sha512-N+tn9tej2hPvyKgHEApMOQfHczDJCwxrRFS3SPn9QjYN+uwHvEDnCgKRrb3mxDYxRS8sKMM8fhC3+lc04Abz5Q==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.6.tgz", + "integrity": "sha512-YJE78Wcg+zX8f10hiHWQ4Az48Qr/c13eId0VtRQYLBpxHDmDeSrXIlkbl+fJGW42rWC/uoUco9mhBZeVWP/A1g==", "license": "MIT", "dependencies": { "@lezer/common": "^1.2.0", @@ -2999,27 +2968,6 @@ "integrity": "sha512-FY+MKLBoTsLNJF/eLWaOsXGdz6uh3Iu1axjPf6TUq92IYumcTcXWHoS747JARLkcdlJ/Waiaxc5wQfFO8jC6NA==", "license": "MIT" }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.2.tgz", - "integrity": "sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==", - "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 || ^2.0.0-alpha.3", - "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.3" - } - }, "node_modules/@noble/curves": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.2.0.tgz", @@ -3099,9 +3047,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "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==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.2.tgz", + "integrity": "sha512-l7x215OGvo1s52JWmR8U/DAVzEDWBCIbTm28aeJV/WDTSHgcKXaZTuBT0hJMs5NggilfJTW3clZVvd24yfKJxA==", "cpu": [ "arm64" ], @@ -3115,9 +3063,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.1.tgz", - "integrity": "sha512-fMsTOnN0OjFm3CyppWPitKnc8UlliVARUULW6cfU6AIqjdtgmSFWSk9vecHzZduv/yMWIHDlRhM1e8Iff9uAfA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.2.tgz", + "integrity": "sha512-9u9Xv6c1AJZT0FfwH5vrMG5Jjcwhc1MlyrPu0XfTqkzsmqfks2M6W/o5XwAJgVVN/jHpqqngC1WevHKKTIUtIA==", "cpu": [ "arm64" ], @@ -3131,9 +3079,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "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==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.2.tgz", + "integrity": "sha512-9W1mbGZAfW3oqd85bhBkmpyHCCzL1TeG/zFFP3vg7b0rlly8cxOcre5nXwz+LHazCwac2MNWgPdPCHndABjpWQ==", "cpu": [ "x64" ], @@ -3147,9 +3095,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.1.tgz", - "integrity": "sha512-Fa0jHR07E7YBN4vOEsbVf2briYNsuOowfLJaXULZM0ldMlaCaj2LJgLMbMe4iacRyZmvR8efFhgR9wKuGclQUg==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.2.tgz", + "integrity": "sha512-0p1lhiCSCyaerFwtrdZQUx7NqGk6LQnaRKWX7tFQqwQgvX0rjM15cIkm3pax1UpEakK14C4mOxx/jSqCBdBRqQ==", "cpu": [ "x64" ], @@ -3163,9 +3111,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "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==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.2.tgz", + "integrity": "sha512-e+cOJXrJ2L3zx6YzqPg+f6Wbk3V1cKB8bOhbaYdVYN3DdquzNdRAmrbETz1qnt5yp/c7JNlNjmITiA2cVneQ7w==", "cpu": [ "arm" ], @@ -3179,9 +3127,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "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==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.2.tgz", + "integrity": "sha512-JsSMsj6sNat/MuhG5fnBD7QgbtpHKVe30x5/bAVirDHdhoQRXJkF6xc0Jqk8O4fiCUQAzMOoH9wZi3m60c8wtg==", "cpu": [ "arm64" ], @@ -3195,9 +3143,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "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==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.2.tgz", + "integrity": "sha512-B5G/zJdHaoJn9vD50eGHWkiWfmq8Uhi3IiLPJTzmZTrAalk1bztUikSXo0qga18ibE0IXboyeMUnhPjhAJ45wQ==", "cpu": [ "arm64" ], @@ -3211,9 +3159,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "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==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.2.tgz", + "integrity": "sha512-6mC/awzKka8W6EoekjegpfGkjz8jXWDX63pqu/HYVpyKtZfu65Jsh4QAH3Kej3CAv/c1oGX7psTmFEbr0mDxLA==", "cpu": [ "ppc64" ], @@ -3227,9 +3175,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "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==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.2.tgz", + "integrity": "sha512-412MX9fJLdA1IK28EZnc8jYv2HRTleOZgfLQumJ5zy7OeJLZlg/CETwFaXjNmGVxG51cFHpKLqb5LKvBC+HsHA==", "cpu": [ "s390x" ], @@ -3243,9 +3191,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "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==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.2.tgz", + "integrity": "sha512-Q/+HI/ToJafZ1iCqGgVQXUEkIjufHCTF0gBQ2a5o3cg7GJ2h0qyq3nvvSmU+bGda2/7ygXpTY4TM6gO9OhQ0ZA==", "cpu": [ "x64" ], @@ -3259,9 +3207,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "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==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.2.tgz", + "integrity": "sha512-ZKp/w41n6wCvxzxQHtQSbuphfX3Y4cCvbjkKHusrLx4lh+JWLTU7StSltO/DKARISzbj368d+qUaCjI8K2wzXw==", "cpu": [ "x64" ], @@ -3275,9 +3223,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "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==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.2.tgz", + "integrity": "sha512-pxE6xD4KS3eAROkKK5yrhB9/3+vhlhVGMvlQLbdpzrBGDbKrnzx3RLwPaHvasLo6jgaiBLn7e04Df9C4tYhjmA==", "cpu": [ "arm64" ], @@ -3290,25 +3238,10 @@ "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "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==", - "license": "MIT", - "optional": true, - "dependencies": { - "@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.13.0 || >=23.5.0" - } - }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "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==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.2.tgz", + "integrity": "sha512-4MqEue5re+xIZzAWsB8sj0P1kqZySWqIuN4t6QaIO/YA6SFwySOLruvWQFzfmqk8LBK2P30KCSJwf6mJCZZ5/A==", "cpu": [ "arm64" ], @@ -3322,9 +3255,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "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==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.2.tgz", + "integrity": "sha512-NweNxxD0Nf9t8v7kodun45Ijp3EIwYY+uydPP6qBEYvfBqhIjN6dZMzlQja3tqX/aLs3F3Uz+AxDpKgRhpOZQg==", "cpu": [ "x64" ], @@ -3535,16 +3468,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", - "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@types/aria-query": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", @@ -3606,17 +3529,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.65.0.tgz", - "integrity": "sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.66.0.tgz", + "integrity": "sha512-p088eaGrzYz1s+7cov0aMOCkNGTJlVxF4jgubf28c8L0Cv9Rloj8YBHnv4hXLq6IIEE1AsjNWavO+k+8kP2Y0A==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.65.0", - "@typescript-eslint/type-utils": "8.65.0", - "@typescript-eslint/utils": "8.65.0", - "@typescript-eslint/visitor-keys": "8.65.0", + "@typescript-eslint/scope-manager": "8.66.0", + "@typescript-eslint/type-utils": "8.66.0", + "@typescript-eslint/utils": "8.66.0", + "@typescript-eslint/visitor-keys": "8.66.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -3629,7 +3552,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.65.0", + "@typescript-eslint/parser": "^8.66.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } @@ -3645,15 +3568,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.65.0.tgz", - "integrity": "sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.66.0.tgz", + "integrity": "sha512-X6ypGChaWYk6PBtUg2BwuTZEFFcHJAtGTVJ9/lCTOufhZ4i9fNolQNnktq+kkMCwMj7V8Svsq7+TxSDslmhE0g==", "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.65.0", - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/typescript-estree": "8.65.0", - "@typescript-eslint/visitor-keys": "8.65.0", + "@typescript-eslint/scope-manager": "8.66.0", + "@typescript-eslint/types": "8.66.0", + "@typescript-eslint/typescript-estree": "8.66.0", + "@typescript-eslint/visitor-keys": "8.66.0", "debug": "^4.4.3" }, "engines": { @@ -3669,13 +3592,13 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.65.0.tgz", - "integrity": "sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.66.0.tgz", + "integrity": "sha512-7MthGPTt4BP69lSryqpqq8HQqxuzynssckL/jyDyk3+TNMQ3y2jFWkptCrktWvBrP+EH787Nl5N5Qpw7WZg+5g==", "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.65.0", - "@typescript-eslint/types": "^8.65.0", + "@typescript-eslint/tsconfig-utils": "^8.66.0", + "@typescript-eslint/types": "^8.66.0", "debug": "^4.4.3" }, "engines": { @@ -3690,13 +3613,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.65.0.tgz", - "integrity": "sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.66.0.tgz", + "integrity": "sha512-8TGcH25j9zqJ/IULB/ppyhRvxA8QYfFEZ7nfbg6/BN9spDgb8fPWQXlE5l8TWBL50EtUx007uZ1o9VOwrq2/9g==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/visitor-keys": "8.65.0" + "@typescript-eslint/types": "8.66.0", + "@typescript-eslint/visitor-keys": "8.66.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3707,9 +3630,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.65.0.tgz", - "integrity": "sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.66.0.tgz", + "integrity": "sha512-9D5gLYZG4rOjcoag8MQ/fWI8WqA9wcPDyOGyWtWFhvM1lHRbliqUSPIY5J3zqCU1tvSwzXxnnjhQhz5Ne7mJ4g==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3723,15 +3646,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.65.0.tgz", - "integrity": "sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.66.0.tgz", + "integrity": "sha512-LG2dWfjZQQp0ADtAu/EWJVayefGL2UEZ3CDeI44D9v3rXB/WYUqE/jpO28KrEKul5AySrmI+Zh1v6v+xW2U9+g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/typescript-estree": "8.65.0", - "@typescript-eslint/utils": "8.65.0", + "@typescript-eslint/types": "8.66.0", + "@typescript-eslint/typescript-estree": "8.66.0", + "@typescript-eslint/utils": "8.66.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -3748,9 +3671,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.65.0.tgz", - "integrity": "sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.66.0.tgz", + "integrity": "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3761,15 +3684,15 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.65.0.tgz", - "integrity": "sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.66.0.tgz", + "integrity": "sha512-8/x4INiiQb10jGgXYD7116/zQ+OL84ZIFn0za68wwFHCanT/VLbBEroWht8RV8fn0/ZCAoazHLQgwUC0UQcDfg==", "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.65.0", - "@typescript-eslint/tsconfig-utils": "8.65.0", - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/visitor-keys": "8.65.0", + "@typescript-eslint/project-service": "8.66.0", + "@typescript-eslint/tsconfig-utils": "8.66.0", + "@typescript-eslint/types": "8.66.0", + "@typescript-eslint/visitor-keys": "8.66.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -3788,16 +3711,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.65.0.tgz", - "integrity": "sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.66.0.tgz", + "integrity": "sha512-jasearZPolBw5NJNYGMwxzHMF83niVWmMU1VdHzG1CyfI2VS7f7nZltnKtHcg20hW+7Uo5GfK4MeDPoU3qI8EA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.65.0", - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/typescript-estree": "8.65.0" + "@typescript-eslint/scope-manager": "8.66.0", + "@typescript-eslint/types": "8.66.0", + "@typescript-eslint/typescript-estree": "8.66.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3812,12 +3735,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.65.0.tgz", - "integrity": "sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.66.0.tgz", + "integrity": "sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/types": "8.66.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -4498,9 +4421,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.8.tgz", - "integrity": "sha512-zAgkquC2WYF0PIc6XbNYkA2uuxxFavzgmX61R+dHDUa558V8Ejf8ozTZFR6QzM24RWu4kBcRkhJ5kpz77j9fnQ==", + "version": "2.11.12", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.12.tgz", + "integrity": "sha512-r7WnVImvVCeFpf2DOXfy41aPWzeNg3H/A2X4dKmy1QL0MSyyk/e7z8ihJ3N6Nn2PsdhkVlqnEfnUE4a05P2aTA==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4750,6 +4673,43 @@ "vitest-axe": "^0.1.0" } }, + "node_modules/chat-pane/node_modules/solid-logic": { + "version": "4.0.8-1", + "resolved": "https://registry.npmjs.org/solid-logic/-/solid-logic-4.0.8-1.tgz", + "integrity": "sha512-9Vtg9ukEaDTIvBPqECORWRtEJ3nTlEvInJzUCJZDp1qjN9VIdJG0mSiPTIP9RXOEOSAA+Q+cP3d7BzsNyI/RVA==", + "license": "MIT", + "dependencies": { + "@uvdsl/solid-oidc-client-browser": "^0.2.3", + "solid-namespace": "^0.5.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chat-pane/node_modules/solid-ui": { + "version": "3.1.3-13", + "resolved": "https://registry.npmjs.org/solid-ui/-/solid-ui-3.1.3-13.tgz", + "integrity": "sha512-0meJycoMXoelTD06W9A0S9Q4vg0I8BDSsui4BfwocfwFIpEZ02FBFZZf1LcanP7NNpAOs0So6HOQp4QlwSJE3w==", + "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/ci-info": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", @@ -5192,9 +5152,9 @@ "license": "MIT" }, "node_modules/dompurify": { - "version": "3.4.12", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.12.tgz", - "integrity": "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==", + "version": "3.4.13", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.13.tgz", + "integrity": "sha512-2vmYIoqjze2d+kakP8S/nS5shfsl587kzwEjcGlTdiksUVgFHnFCsLYDVj/JNqJVOQZGSYBTmuycv0PodwmnMQ==", "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" @@ -5260,9 +5220,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.399", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.399.tgz", - "integrity": "sha512-lEcqhErbHjXRvd41rnWLpzbyU/IXfIYo7QwaFWmxGeLiLyY2TBCdHnWY88vB+p3ubnihRypDm66panXl7TylLA==", + "version": "1.5.401", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.401.tgz", + "integrity": "sha512-H6ViHN68nGYlChEvlIU67fn8O2/tpbWQPwck98yaJmh+08LSvHiydzDQ6oXNccLU3kNRVIRS9A4mA7CG+i6fLQ==", "dev": true, "license": "ISC" }, @@ -6095,36 +6055,23 @@ "license": "ISC" }, "node_modules/folder-pane": { - "version": "3.1.1-2", - "resolved": "https://registry.npmjs.org/folder-pane/-/folder-pane-3.1.1-2.tgz", - "integrity": "sha512-gFxqQxc2bRP1Sx12zTn3fQaKPIhLjq3gcuRXHdOvkYMKH6wKlBfgVh/PVlXOmDVkqQWg7s5JPyWrWVWKzrB7eA==", + "version": "3.1.1-3", + "resolved": "https://registry.npmjs.org/folder-pane/-/folder-pane-3.1.1-3.tgz", + "integrity": "sha512-8k4//XS60QeOnCFaSNrmrsI551/YQ7lhCHnJzQFg/zeU6ZPrX80Ca+bnUwpj1Uojb09ChTaNYN+sqh1OpbuCFw==", "license": "MIT", "dependencies": { "rdflib": "2.4.0", - "solid-logic": "4.0.8-1", - "solid-ui": "3.1.3-11", + "solid-logic": "4.0.8-2", + "solid-ui": "3.1.3-14", "vite": "^8.0.16", "vitest": "^4.0.18", "vitest-axe": "^0.1.0" } }, - "node_modules/folder-pane/node_modules/solid-logic": { - "version": "4.0.8-1", - "resolved": "https://registry.npmjs.org/solid-logic/-/solid-logic-4.0.8-1.tgz", - "integrity": "sha512-9Vtg9ukEaDTIvBPqECORWRtEJ3nTlEvInJzUCJZDp1qjN9VIdJG0mSiPTIP9RXOEOSAA+Q+cP3d7BzsNyI/RVA==", - "license": "MIT", - "dependencies": { - "@uvdsl/solid-oidc-client-browser": "^0.2.3", - "solid-namespace": "^0.5.4" - }, - "engines": { - "node": ">=18" - } - }, "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==", + "version": "3.1.3-14", + "resolved": "https://registry.npmjs.org/solid-ui/-/solid-ui-3.1.3-14.tgz", + "integrity": "sha512-iroWIHNX1PJH70Rx9BkXDns0x06cibbdl8lQPsWx94Qbmg1WxrD7hCAxAwWy/OpfAypCEhxxU3hj0699elfqpA==", "license": "MIT", "dependencies": { "@awesome.me/webawesome": "^3.9.0", @@ -6137,7 +6084,7 @@ "mime-types": "^3.0.2", "pane-registry": "3.1.2-2", "rdflib": "2.4.0", - "solid-logic": "4.0.8-1", + "solid-logic": "4.0.8-2", "solid-namespace": "^0.5.4", "uuid": "^14.0.0" }, @@ -6338,9 +6285,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", - "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.1.tgz", + "integrity": "sha512-Dz/6HxkrxgNehhxLVeyv8sad9UzF2xBVeaKBQNDfJ5XiSXmp2gTR0eO0RWiT2NCKS5aGP9jjkOMggTN90qU50A==", "dev": true, "license": "MIT", "dependencies": { @@ -6420,9 +6367,9 @@ } }, "node_modules/globals": { - "version": "17.8.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.8.0.tgz", - "integrity": "sha512-Zz/LMDZScFmkakeL2cTHzf+PbWKdpU3uclqkZT7TjDG58j5WPt0PpA+n9uPI24fZtlw07q0OtEi84K+umsRzqQ==", + "version": "17.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.9.0.tgz", + "integrity": "sha512-m/MvAW61QVU5VDNF1Vj8axt016h8w7L5TU1e9zlab7XIttAT2YAlCwl75K1fOqvMM9apmD7lbCIRhpfkhmxhCg==", "dev": true, "license": "MIT", "engines": { @@ -7423,9 +7370,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", - "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", "funding": [ { "type": "github", @@ -8254,9 +8201,9 @@ } }, "node_modules/marked": { - "version": "18.0.7", - "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.7.tgz", - "integrity": "sha512-iDVQ5ldaiKXn6b2JroX5kgRfmwgqolW7NpaEzTl1k/2Zh1njIEN9yniyLV/mOvWwtsE8OGgkjsCYvijuPk1dtA==", + "version": "18.0.9", + "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.9.tgz", + "integrity": "sha512-/Sa4qiiHZxf0/FQdBBowr9q4r10krCwMvpK48FUBdXdUXScDxiQGR9zCPrFgRVR5LU3iySOiIjy09ZQvADir1w==", "license": "MIT", "bin": { "marked": "bin/marked.js" @@ -8412,9 +8359,9 @@ "license": "MIT" }, "node_modules/n3": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/n3/-/n3-2.1.1.tgz", - "integrity": "sha512-kqg8ers6Lc+uAmHeS+ycd3b8mC4x8wr8V8Fi6+w7l4hX6b0KZ5bT05Tf49qM2mujwaqZT3+08zcgtXgfxivbVQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/n3/-/n3-2.1.2.tgz", + "integrity": "sha512-8DD60rrjJDmeNgLV/zlTiWubxHXLj7te9+uh/IS611fUIgduz4SoeqkOwCQPPpHZ2E/Y26KE+9rm8q8A5mrWvQ==", "license": "MIT", "dependencies": { "buffer": "^6.0.3", @@ -8645,9 +8592,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.51", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", - "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", + "version": "2.0.52", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.52.tgz", + "integrity": "sha512-MRlTqhAfoMx/4mhEbPo3Hi02g9LJZaJkka69V6h67Cb1gjrAG0jsTE4CZX1eptNx+VCAwJmfpnDIF4P0Nh1A7A==", "dev": true, "license": "MIT", "engines": { @@ -9297,9 +9244,9 @@ } }, "node_modules/postcss/node_modules/nanoid": { - "version": "3.3.16", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", - "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "version": "3.3.17", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.17.tgz", + "integrity": "sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==", "funding": [ { "type": "github", @@ -9409,6 +9356,30 @@ "node": ">=18" } }, + "node_modules/profile-pane/node_modules/solid-ui": { + "version": "3.1.3-13", + "resolved": "https://registry.npmjs.org/solid-ui/-/solid-ui-3.1.3-13.tgz", + "integrity": "sha512-0meJycoMXoelTD06W9A0S9Q4vg0I8BDSsui4BfwocfwFIpEZ02FBFZZf1LcanP7NNpAOs0So6HOQp4QlwSJE3w==", + "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/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -9875,9 +9846,9 @@ } }, "node_modules/rolldown": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.1.tgz", - "integrity": "sha512-4FKJhg8d3OiyQOA6Q1Q0hoFFpW9/OoX+VsHzpECsdsIZoOArrAK90gl59YK/Z+gnDel45bgJZK03ozH/9bCqEw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.2.tgz", + "integrity": "sha512-opwpo1tQBAcpSUJDt94B7hhLNGOKjCdE//XXjeLrnx9b83bjnw45tXdg1b09yEw/VLFBJGZpwRULMmOZo7ol+A==", "license": "MIT", "dependencies": { "@oxc-project/types": "=0.142.0", @@ -9890,21 +9861,20 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@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" + "@rolldown/binding-android-arm64": "1.2.2", + "@rolldown/binding-darwin-arm64": "1.2.2", + "@rolldown/binding-darwin-x64": "1.2.2", + "@rolldown/binding-freebsd-x64": "1.2.2", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.2", + "@rolldown/binding-linux-arm64-gnu": "1.2.2", + "@rolldown/binding-linux-arm64-musl": "1.2.2", + "@rolldown/binding-linux-ppc64-gnu": "1.2.2", + "@rolldown/binding-linux-s390x-gnu": "1.2.2", + "@rolldown/binding-linux-x64-gnu": "1.2.2", + "@rolldown/binding-linux-x64-musl": "1.2.2", + "@rolldown/binding-openharmony-arm64": "1.2.2", + "@rolldown/binding-win32-arm64-msvc": "1.2.2", + "@rolldown/binding-win32-x64-msvc": "1.2.2" } }, "node_modules/safe-array-concat": { @@ -10230,9 +10200,9 @@ "license": "MIT" }, "node_modules/solid-ui": { - "version": "3.1.3-13", - "resolved": "https://registry.npmjs.org/solid-ui/-/solid-ui-3.1.3-13.tgz", - "integrity": "sha512-0meJycoMXoelTD06W9A0S9Q4vg0I8BDSsui4BfwocfwFIpEZ02FBFZZf1LcanP7NNpAOs0So6HOQp4QlwSJE3w==", + "version": "3.1.3-15", + "resolved": "https://registry.npmjs.org/solid-ui/-/solid-ui-3.1.3-15.tgz", + "integrity": "sha512-qX/IabG/Wets1w7ZQ+wLg9HIhBz3n8BTr36hC0whwfpjFBKe/62fow9CkrIVbRcSLz+fZ9+44SU5aUo4mFAoqg==", "license": "MIT", "dependencies": { "@awesome.me/webawesome": "^3.9.0", @@ -10245,7 +10215,7 @@ "mime-types": "^3.0.2", "pane-registry": "3.1.2-2", "rdflib": "2.4.0", - "solid-logic": "4.0.8-1", + "solid-logic": "4.0.8-2", "solid-namespace": "^0.5.4", "uuid": "^14.0.0" }, @@ -10253,19 +10223,6 @@ "fsevents": "*" } }, - "node_modules/solid-ui/node_modules/solid-logic": { - "version": "4.0.8-1", - "resolved": "https://registry.npmjs.org/solid-logic/-/solid-logic-4.0.8-1.tgz", - "integrity": "sha512-9Vtg9ukEaDTIvBPqECORWRtEJ3nTlEvInJzUCJZDp1qjN9VIdJG0mSiPTIP9RXOEOSAA+Q+cP3d7BzsNyI/RVA==", - "license": "MIT", - "dependencies": { - "@uvdsl/solid-oidc-client-browser": "^0.2.3", - "solid-namespace": "^0.5.4" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/solidos-toolkit": { "version": "0.0.0-dev.761b46f81590c0224a612fba4771aa9c84e7944a", "resolved": "https://registry.npmjs.org/solidos-toolkit/-/solidos-toolkit-0.0.0-dev.761b46f81590c0224a612fba4771aa9c84e7944a.tgz", @@ -10368,6 +10325,30 @@ "node": ">=18" } }, + "node_modules/source-pane/node_modules/solid-ui": { + "version": "3.1.3-13", + "resolved": "https://registry.npmjs.org/solid-ui/-/solid-ui-3.1.3-13.tgz", + "integrity": "sha512-0meJycoMXoelTD06W9A0S9Q4vg0I8BDSsui4BfwocfwFIpEZ02FBFZZf1LcanP7NNpAOs0So6HOQp4QlwSJE3w==", + "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/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -10689,9 +10670,9 @@ "license": "MIT" }, "node_modules/tinyexec": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", - "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.0.tgz", + "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==", "license": "MIT", "engines": { "node": ">=18" @@ -10824,13 +10805,6 @@ "typescript": ">=4.0.0" } }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "optional": true - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -10935,16 +10909,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.65.0.tgz", - "integrity": "sha512-/ggrHAwyjENDusvyxbuqxAC2dTnZg/Z8F+fgQtYIz+L6n/9HfSlEZcFGV/NsMNa6CkGk0xUjUAFwC0vHOflvIA==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.66.0.tgz", + "integrity": "sha512-QlEbBPz/RuJ1XUHj29nm3t0F/O/cSlEnntozqPOYHnnTGAXFamnMBu5i9Vn6vhUPHGAjR+Vl+5J8vPN/BMUrJw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.65.0", - "@typescript-eslint/parser": "8.65.0", - "@typescript-eslint/typescript-estree": "8.65.0", - "@typescript-eslint/utils": "8.65.0" + "@typescript-eslint/eslint-plugin": "8.66.0", + "@typescript-eslint/parser": "8.66.0", + "@typescript-eslint/typescript-estree": "8.66.0", + "@typescript-eslint/utils": "8.66.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" diff --git a/package.json b/package.json index 263f9b7c..5d615a6b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "solid-panes", - "version": "4.4.2-5", + "version": "4.4.2-6", "description": "Solid-compatible Panes: applets and views for the mashlib and databrowser", "main": "dist/index.cjs.js", "types": "dist/index.d.ts", @@ -61,7 +61,7 @@ "chat-pane": "3.0.4-3", "contacts-pane": "3.2.1-5", "dompurify": "^3.4.4", - "folder-pane": "3.1.1-2", + "folder-pane": "3.1.1-3", "issue-pane": "3.0.3-1", "lit-html": "^3.3.2", "marked": "^18.0.3", @@ -72,7 +72,7 @@ "rdflib": "2.4.0", "solid-logic": "4.0.8-2", "solid-namespace": "^0.5.4", - "solid-ui": "3.1.3-13", + "solid-ui": "3.1.3-15", "source-pane": "3.1.1-5" }, "overrides": { diff --git a/src/components/file-explorer-header/FileExplorerHeader.styles.css b/src/components/file-explorer-header/FileExplorerHeader.styles.css new file mode 100644 index 00000000..d75d59f4 --- /dev/null +++ b/src/components/file-explorer-header/FileExplorerHeader.styles.css @@ -0,0 +1,12 @@ +:host { + header { + display: flex; + justify-content: space-between; + align-items: center; + gap: 6px; + flex-wrap: nowrap; + width: 100%; + text-align: right; + padding: 15px; + } +} diff --git a/src/components/file-explorer-header/FileExplorerHeader.ts b/src/components/file-explorer-header/FileExplorerHeader.ts new file mode 100644 index 00000000..136cdc3f --- /dev/null +++ b/src/components/file-explorer-header/FileExplorerHeader.ts @@ -0,0 +1,86 @@ +import { sym } from 'rdflib' +import { WebComponent, type FileExplorerContext, fileExplorerContext } from 'solid-ui' +import { customElement, property, state } from 'lit/decorators.js' +import { consume } from '@lit/context' +import { html } from 'lit' +import '~icons/lucide/share-2' +import '~icons/lucide/pencil' +import '~icons/lucide/ellipsis-vertical' +import styles from './FileExplorerHeader.styles.css' +import './FileExplorerHeaderSummary' +import './FileExplorerHeaderControls' +import { PaneIcon } from './types' +import { fetchContentAndMetadata, type FileExplorerResourceMetadata } from './helper' + +@customElement('file-explorer-header') +export default class FileExplorerHeader extends WebComponent { + static styles = styles + + private _loadedMetadataForUri: string | undefined + + @consume({ context: fileExplorerContext, subscribe: true }) + accessor fileExplorerContext: FileExplorerContext = undefined as unknown as FileExplorerContext + + @property({ attribute: false }) + accessor menuItems: Array<{ label: string, action: (event: Event) => void }> = [] + + @property({ attribute: false }) + accessor paneIcon: PaneIcon = undefined as unknown as PaneIcon + + @state() + accessor responseMetadata: Pick = { + modified: undefined, + isPublic: false, + canEdit: false, + aclUri: undefined + } + + private getDefaultResponseMetadata (): Pick { + return { + modified: undefined, + isPublic: false, + canEdit: false, + aclUri: undefined + } + } + + protected updated () { + if (this.fileExplorerContext?.store && this.fileExplorerContext.subjectUri && this._loadedMetadataForUri !== this.fileExplorerContext.subjectUri) { + this._loadedMetadataForUri = this.fileExplorerContext.subjectUri + this.loadResponseMetadata() + } + } + + private async loadResponseMetadata () { + if (!this.fileExplorerContext?.store || !this.fileExplorerContext.subjectUri) return + + try { + const { metadata } = await fetchContentAndMetadata(this.fileExplorerContext.store, sym(this.fileExplorerContext.subjectUri)) + this.responseMetadata = { + modified: metadata.modified, + isPublic: metadata.isPublic, + canEdit: metadata.canEdit, + aclUri: metadata.aclUri + } + } catch (error) { + this.responseMetadata = this.getDefaultResponseMetadata() + console.warn('Failed to load response metadata', error) + } + } + + render () { + return html` +
+ + +
+ ` + } +} diff --git a/src/components/file-explorer-header/FileExplorerHeaderControls.styles.css b/src/components/file-explorer-header/FileExplorerHeaderControls.styles.css new file mode 100644 index 00000000..88c96aee --- /dev/null +++ b/src/components/file-explorer-header/FileExplorerHeaderControls.styles.css @@ -0,0 +1,43 @@ +:host { + div { + display: flex; + justify-content: flex-end; + align-items: center; + gap: 6px; + flex: 0 0 auto; + text-align: right; + } + + /* generative ai */ + div > * { + flex: 0 1 auto; + } + + /* TODO: look into what colors to use this is just to show */ + .dirtyIndicator { + display: inline-flex; + align-items: center; + border: 1px solid #F59E0B; + color: #92400E; + background: #FFFBEB; + border-radius: 999px; + font-size: 0.72rem; + font-weight: 600; + line-height: 1; + padding: 4px 8px; + white-space: nowrap; + } + + @media (max-width: 900px) { + div { + padding-right: 3px; + } + } + + @media (max-width: 600px) { + div { + justify-content: flex-start; + gap: 5px; + } + } +} diff --git a/src/components/file-explorer-header/FileExplorerHeaderControls.ts b/src/components/file-explorer-header/FileExplorerHeaderControls.ts new file mode 100644 index 00000000..b6668ce4 --- /dev/null +++ b/src/components/file-explorer-header/FileExplorerHeaderControls.ts @@ -0,0 +1,74 @@ +import { WebComponent } from 'solid-ui' +import { customElement, property } from 'lit/decorators.js' +import { consume } from '@lit/context' +import { html, nothing } from 'lit' +import 'solid-ui/components/button' +import '~icons/lucide/share-2' +import '~icons/lucide/pencil' +import styles from './FileExplorerHeaderControls.styles.css' +import '../resource-actions-menu/ResourceActionsMenu' +import { fileExplorerContext, type FileExplorerContext } from 'solid-ui' + +@customElement('file-explorer-header-controls') +export default class FileExplorerHeaderControls extends WebComponent { + static styles = styles + + @consume({ context: fileExplorerContext, subscribe: true }) + accessor fileExplorerContext: FileExplorerContext = undefined as unknown as FileExplorerContext + + @property({ attribute: false }) + accessor menuItems: Array<{ label: string, action: (event: Event) => void }> = [] + + @property({ type: Boolean }) + accessor canEdit: boolean = false + + // TODO: Add broken then use this function to set tooltip and disable edit button + /* private setEditable() { + const sourcePaneState = this.sourceContext?.sourcePaneState + const { canEdit } = this.sourceContext?.headerMetadata ?? { canEdit: false } + const subject = this.sourceContext?.subject + if (!sourcePaneState || !canEdit || sourcePaneState.broken || (subject && subject.endsWith('/'))) return + + this.sourceContext?.setEditing?.() + } */ + + private handleEditingClick () { + this.fileExplorerContext.edit?.onEdit?.() + } + + private getEditTooltip () { + if (!this.fileExplorerContext.paneSupportsEditing) return 'Not Supported' + if (!this.canEdit) return 'No Access' + return 'Edit' + } + + private renderDirtyIndicator () { + if (!this.fileExplorerContext.edit?.isDirty) return nothing + + return html`Unsaved` + } + + render () { + return html` +
+ ${this.renderDirtyIndicator()} + + + + + + + +
+ ` + } +} diff --git a/src/components/file-explorer-header/FileExplorerHeaderSummary.styles.css b/src/components/file-explorer-header/FileExplorerHeaderSummary.styles.css new file mode 100644 index 00000000..0fce991a --- /dev/null +++ b/src/components/file-explorer-header/FileExplorerHeaderSummary.styles.css @@ -0,0 +1,89 @@ + :host { + .file-explorer-header-summary { + display: flex; + justify-content: flex-start; + align-items: center; + gap: 6px; + flex-wrap: wrap; + flex: 1 1 auto; + min-width: 0; + text-align: left; + } + + h1 { + color: var(--solid-ui-color-gray-700, #364153); + font-size: var(--solid-ui-font-size-2xl, 1.5rem); + font-weight: 500; + } + + .pane-icon { + display: flex; + width: 40px; + height: 40px; + padding: 7.5px 7px 6.5px 7px; + justify-content: center; + align-items: center; + aspect-ratio: 1/1; + /* border-radius: 100px; */ + /* background: var(--slate-600, #45556C); */ + } + + .pane-icon img { + width: 100%; + height: 100%; + object-fit: contain; + display: block; + } + + p { + display: flex; + align-items: center; + gap: 5px; + color: var(--solid-ui-gray-500, #6A7282); + font-size: var(--solid-ui-font-size-xs, .75rem); + font-weight: 500; + } + + .public { + display: flex; + padding: 2px 5px; + justify-content: center; + align-items: center; + gap: 3px; + color: var(--blue-400, #51A2FF); + border-radius: 5px; + background: var(--blue-50, #EFF6FF); + } + + icon-lucide-globe { + stroke-width: 1.021px; + stroke: var(--blue-400, #51A2FF); + } + + .private { + display: flex; + padding: 2px 5px; + justify-content: center; + align-items: center; + gap: 3px; + color: var(--yellow-600, #D08700); + border-radius: 5px; + background: var(--yellow-100, #FEF9C2); + } + + icon-lucide-lock-keyhole { + stroke-width: 1.021px; + stroke: var(--yellow-600, #D08700); + } + + icon-lucide-globe, + icon-lucide-lock-keyhole { + width: 0.875rem; + height: 0.875rem; + } + + icon-lucide-arrow-left { + width: 1.125rem; + height: 1.125rem; + } +} diff --git a/src/components/file-explorer-header/FileExplorerHeaderSummary.ts b/src/components/file-explorer-header/FileExplorerHeaderSummary.ts new file mode 100644 index 00000000..a02b6947 --- /dev/null +++ b/src/components/file-explorer-header/FileExplorerHeaderSummary.ts @@ -0,0 +1,121 @@ +import { sym } from 'rdflib' +import { widgets, utils, WebComponent, fileExplorerContext, type FileExplorerContext } from 'solid-ui' +import 'solid-ui/components/button' +import { customElement, property, query, state } from 'lit/decorators.js' +import { html } from 'lit' +import { consume } from '@lit/context' +import { PaneIcon } from './types' +import '~icons/lucide/globe' +import '~icons/lucide/lock-keyhole' +import '~icons/lucide/arrow-left' +import styles from './FileExplorerHeaderSummary.styles.css' +import { type FileExplorerResourceMetadata } from './helper' + +@customElement('file-explorer-header-summary') +export default class FileExplorerHeaderSummary extends WebComponent { + static styles = styles + + private _draggableSubjectUri: string | undefined + private _resolvedPaneIconFor: PaneIcon | undefined + + @consume({ context: fileExplorerContext, subscribe: true }) + accessor fileExplorerContext: FileExplorerContext = undefined as unknown as FileExplorerContext + + @property({ attribute: false }) + accessor paneIcon: PaneIcon | undefined + + @property({ attribute: false }) + accessor onBackClick: (() => void) | undefined + + @property({ attribute: false }) + accessor responseMetadata: Pick = { + modified: undefined, + isPublic: false + } + + @state() + accessor resolvedPaneIcon: string | undefined = undefined + + @query('h1') + private accessor titleHeading: HTMLHeadingElement | null = null + + private formatModifiedDate (modified: string | undefined) { + if (!modified) return '' + + const date = new Date(modified) + if (Number.isNaN(date.getTime())) return modified + + const parts = new Intl.DateTimeFormat('en-GB', { + day: '2-digit', + month: 'short', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', + hour12: true + }).formatToParts(date) + + const getPart = (type: Intl.DateTimeFormatPartTypes) => parts.find(part => part.type === type)?.value ?? '' + const day = getPart('day') + const month = getPart('month') + const year = getPart('year') + const hour = getPart('hour') + const minute = getPart('minute') + const dayPeriod = getPart('dayPeriod').toUpperCase() + + return `${day} ${month}, ${year} at ${hour}:${minute} ${dayPeriod}` + } + + protected updated () { + if (this.paneIcon !== undefined && this._resolvedPaneIconFor !== this.paneIcon) { + this._resolvedPaneIconFor = this.paneIcon + this.resolvePaneIcon() + } + + if (!this.titleHeading || !this.fileExplorerContext?.subjectUri || this._draggableSubjectUri === this.fileExplorerContext.subjectUri) return + + widgets.makeDraggable(this.titleHeading, sym(this.fileExplorerContext.subjectUri)) // doing it this way for now, just to keep the same functionality + this._draggableSubjectUri = this.fileExplorerContext.subjectUri + } + + // Needed because humanReadable pane can return a promise for an icon. + private async resolvePaneIcon () { + try { + if (this.paneIcon == null) { + this.resolvedPaneIcon = undefined + return + } + + const icon = await this.paneIcon + this.resolvedPaneIcon = icon ?? undefined + } catch (error) { + this.resolvedPaneIcon = undefined + console.warn('file-explorer-header-summary: failed to resolve pane icon', error) + } + } + + render () { + const subject = this.fileExplorerContext?.subjectUri ? sym(this.fileExplorerContext.subjectUri) : undefined + const label = subject ? utils.label(subject) : '' + const modified = this.formatModifiedDate(this.responseMetadata.modified) + const isPublic = this.responseMetadata.isPublic + + return html` +
+ + + + + ${this.resolvedPaneIcon ? html`` : ''} + +
+

${label}

+

${modified} ${isPublic ? html` Public` : html` Private`}

+
+
+ ` + } +} diff --git a/src/components/file-explorer-header/FileExplorerProvider.styles.css b/src/components/file-explorer-header/FileExplorerProvider.styles.css new file mode 100644 index 00000000..298eedaa --- /dev/null +++ b/src/components/file-explorer-header/FileExplorerProvider.styles.css @@ -0,0 +1,20 @@ +:host { + display: block; + width: 100%; + min-width: 0; + + .file-explorer-provider { + display: flex; + flex-direction: column; + width: 100%; + min-width: 0; + } + + slot.pane { + display: block; + flex: 1 1 auto; + width: 100%; + min-width: 0; + overflow: auto; + } +} diff --git a/src/components/file-explorer-header/FileExplorerProvider.ts b/src/components/file-explorer-header/FileExplorerProvider.ts new file mode 100644 index 00000000..07ea4c24 --- /dev/null +++ b/src/components/file-explorer-header/FileExplorerProvider.ts @@ -0,0 +1,257 @@ +import { html, nothing, type PropertyValues } from 'lit' +import type { NamedNode, LiveStore } from 'rdflib' +import { DataBrowserContext, type PaneDefinition } from 'pane-registry' +import { utils, WebComponent } from 'solid-ui' +import { provide } from '@lit/context' +import { fileExplorerContext, type FileExplorerContext, type FileExplorerEdit } from 'solid-ui' +import { customElement, property, state } from 'lit/decorators.js' +import './FileExplorerHeader' +import styles from './FileExplorerProvider.styles.css' +import personIcon from '../../icons/person.svg' +import friendsIcon from '../../icons/friends.svg' + +const PERSON_ICON = personIcon +const FRIENDS_ICON = friendsIcon + +function createFileExplorerContextValue (value: { + store: LiveStore | undefined + subjectUri: string | undefined + pane?: PaneDefinition + soloPane?: boolean + onBack?: () => void + openPane?: (subject: NamedNode, paneName: string) => void + handleSharingClick?: () => void + paneSupportsEditing?: boolean + edit?: { + onEdit?: () => void + isDirty?: boolean + updateDirtyState?: (dirty: boolean) => void + } +}): FileExplorerContext { + return { + store: value.store as LiveStore, + subjectUri: value.subjectUri, + pane: value.pane, + soloPane: value.soloPane, + onBack: value.onBack, + openPane: value.openPane, + handleSharingClick: value.handleSharingClick, + paneSupportsEditing: value.paneSupportsEditing, + edit: value.edit + } +} +@customElement('file-explorer-provider') +export default class FileExplorerProvider extends WebComponent { + static styles = styles + + @property({ attribute: false }) + accessor context: DataBrowserContext | undefined = undefined + + @property({ attribute: false }) + accessor subjectUri: string | undefined = undefined + + @property({ attribute: false }) + accessor onBack: (() => void) | undefined = undefined + + @property({ attribute: false }) + accessor relevantPanes: PaneDefinition[] = [] + + @property({ attribute: false }) + accessor pane: PaneDefinition | undefined = undefined + + @property({ attribute: false }) + accessor paneRenderOptions: Record = {} + + @property({ attribute: false }) + accessor showHeader: boolean = true + + @property({ attribute: false }) + accessor handleSharingClick: (() => void) | undefined = undefined + + // TODO: Need to research this more, brought it over from manager. + @property({ attribute: false }) + accessor soloPane: boolean | undefined = undefined + + @property({ attribute: false }) + accessor openPane: ((subject: NamedNode, paneName: string) => void) | undefined = undefined + + @state() + accessor menuItems: Array<{ label: string, icon?: HTMLElement, action: (event: Event) => void }> = [] + + @state() + accessor isEditing: boolean = false + + @state() + accessor isDirty: boolean = false + + @state() + accessor paneSupportsEditing: boolean = false + + // TODO: For now this works, but check if there is a better way. + // because this means file explorer will know about the pane. + // what if other panes want to use this. If so maybe we should + // add more to the context to capture the provider for the pane that + // will be editing... anyway this shouldn't be just for source pane. + private beginEditingInSourcePane = () => { + const sourceProvider = this.querySelector('source-pane-source-provider') as { + beginEditing?: () => void + } | null + + sourceProvider?.beginEditing?.() + } + + // TODO: same as below. on Edit should be something more generic + @state() + accessor edit: FileExplorerEdit = { + onEdit: this.beginEditingInSourcePane, + isDirty: false, + updateDirtyState: (dirty: boolean) => { + if (this.isDirty === dirty) return + + this.isDirty = dirty + this.edit = { + ...this.edit, + isDirty: dirty + } + this.refreshFileExplorerContextValue() + } + } + + @provide({ context: fileExplorerContext }) + accessor fileExplorerContextValue: FileExplorerContext = createFileExplorerContextValue({ + store: this.context?.session.store as LiveStore, + subjectUri: this.subjectUri, + pane: this.pane, + soloPane: this.soloPane, + onBack: this.onBack, + openPane: this.openPane, + handleSharingClick: this.handleSharingClick, + paneSupportsEditing: false, + edit: this.edit + }) + + // Change the state for the pane so it can show the new icon. + openSelectedPane (pane: PaneDefinition) { + const store = this.context?.session.store as LiveStore + if (!store || !this.subjectUri) return + this.paneSupportsEditing = pane.name === 'source' + this.pane = pane + } + + private getPaneIcon (pane, subject, context) { + if (!pane) return undefined + + const icon = typeof pane.icon === 'function' + ? pane.icon(subject, context) + : pane.icon + return icon + } + + private async getPaneItems (subject, context, relevantPanes) { + const dom = context.dom + const menuItems = await Promise.all(relevantPanes.map(async pane => { + const label = pane.label(subject, context) + + let iconSrc = '' + if (pane.name === 'profile') { + iconSrc = PERSON_ICON + } else if (pane.name === 'social') { + iconSrc = FRIENDS_ICON + } else { + iconSrc = await this.getPaneIcon(pane, subject, context) + } + + const icon = utils.AJARImage(iconSrc, label, label, dom) + icon.setAttribute('slot', 'left-icon') + + return { + label, + icon, + action: () => this.openPane?.(subject, pane.name) + } + })) + return menuItems + } + + private refreshFileExplorerContextValue () { + this.fileExplorerContextValue = createFileExplorerContextValue({ + store: this.context?.session.store as LiveStore, + subjectUri: this.subjectUri, + pane: this.pane, + soloPane: this.soloPane, + onBack: this.onBack, + openPane: this.openPane, + handleSharingClick: this.handleSharingClick, + paneSupportsEditing: this.paneSupportsEditing, + edit: this.edit + }) + } + + private async refreshMenuItems () { + const store = this.context?.session.store as LiveStore + if (!store || !this.subjectUri) return + + const subject = store.sym(this.subjectUri) + const menuItems = await this.getPaneItems(subject, this.context as DataBrowserContext, this.relevantPanes) + + this.menuItems = menuItems + } + + protected willUpdate (changedProperties: PropertyValues) { + super.willUpdate(changedProperties) + const store = this.context?.session.store as LiveStore + if (!store) { + throw new Error('The element is missing the required `context.session.store` value. Ensure the `context` property is set.') + } + if (!this.subjectUri) { + throw new Error('The element is missing the required `subjectUri` property.') + } + + if ( + changedProperties.has('subjectUri') || + changedProperties.has('relevantPanes') || + changedProperties.has('context') + ) { + this.refreshMenuItems().catch(error => { + console.warn('Failed to refresh menu items', error) + }) + } + + if (changedProperties.has('pane') || changedProperties.has('subjectUri') || changedProperties.has('context')) { + this.paneSupportsEditing = this.pane?.name === 'source' + } + + if ( + changedProperties.has('context') || + changedProperties.has('subjectUri') || + changedProperties.has('pane') || + changedProperties.has('soloPane') || + changedProperties.has('onBack') || + changedProperties.has('openPane') || + changedProperties.has('handleSharingClick') || + changedProperties.has('pane') || + changedProperties.has('isDirty') + ) { + this.refreshFileExplorerContextValue() + } + } + + render () { + const store = this.context?.session.store as LiveStore + const subject = store.sym(this.subjectUri as string) + return html` +
+ ${this.showHeader + ? html` + + ` + : nothing} + +
+ ` + } +} diff --git a/src/components/file-explorer-header/helper.ts b/src/components/file-explorer-header/helper.ts new file mode 100644 index 00000000..129c30bb --- /dev/null +++ b/src/components/file-explorer-header/helper.ts @@ -0,0 +1,105 @@ +// TODO: this code will need to be moved later +import { ACL_LINK } from 'solid-logic' +import { ns } from 'solid-ui' +import type { LiveStore, NamedNode } from 'rdflib' + +export type FileExplorerResourceMetadata = { + contentType: string | undefined + canEdit: boolean + isPublic: boolean + aclUri: string | undefined + eTag: string | undefined + modified: string | undefined +} + +function parseWacAllowHeader (headerValue: string | null | undefined) { + const permissions = new Map>() + if (!headerValue) return permissions + + for (const entry of headerValue.split(',')) { + const match = entry.trim().match(/^([A-Za-z]+)\s*=\s*"([^"]*)"$/) + if (match) { + const [, permissionGroup, accessModes] = match + const modes = accessModes.trim().split(/\s+/).filter(Boolean) + permissions.set(permissionGroup.toLowerCase(), new Set(modes.map(mode => mode.toLowerCase()))) + } + } + + return permissions +} + +function deriveAccessFlags (wacAllow: string | null | undefined) { + if (!wacAllow) { + return { canEdit: false, isPublic: false } + } + + const permissions = parseWacAllowHeader(wacAllow) + const userModes = permissions.get('user') ?? new Set() + const publicModes = permissions.get('public') ?? new Set() + + return { + canEdit: userModes.has('write'), + isPublic: publicModes.has('read') || publicModes.has('write') + } +} + +export function getResponseMetadata (store: LiveStore, subject: NamedNode, response: Response): FileExplorerResourceMetadata { + let contentType: string | undefined + let canEdit = false + let isPublic = false + let eTag: string | undefined + let modified: string | undefined + + if (response.headers && response.headers.get('content-type')) { + contentType = response.headers.get('content-type')?.split(';')[0] ?? undefined + const accessFlags = deriveAccessFlags(response.headers.get('wac-allow')) + + canEdit = accessFlags.canEdit + isPublic = accessFlags.isPublic + eTag = response.headers.get('etag') ?? undefined + modified = store.anyValue(subject as any, ns.dct('modified')) || store.anyValue(subject as any, ns.dc('modified')) || undefined + } else { + const reqs = store.each( + null, + store.sym('http://www.w3.org/2007/ont/link#requestedURI'), + subject + ) + reqs.forEach((req: any) => { + const responseNode = store.any( + req as any, + store.sym('http://www.w3.org/2007/ont/link#response') + ) + if (responseNode && responseNode.termType === 'NamedNode') { + contentType = store.anyValue(responseNode as any, ns.httph('content-type')) || undefined + const wacAllow = (store.anyValue(responseNode as any, ns.httph('wac-allow')) as string | undefined) || + (store.anyValue(responseNode as any, ns.httph('WAC-Allow')) as string | undefined) + const accessFlags = deriveAccessFlags(wacAllow) + canEdit = accessFlags.canEdit + isPublic = accessFlags.isPublic + eTag = store.anyValue(responseNode as any, ns.httph('etag')) || undefined + modified = store.anyValue(subject as any, ns.dct('modified')) || store.anyValue(subject as any, ns.dc('modified')) || undefined + } + }) + } + + const aclUri = store.any(subject, ACL_LINK)?.value || undefined + return { contentType, canEdit, isPublic, aclUri, eTag, modified } +} + +export async function fetchContentAndMetadata (store: LiveStore, subject: NamedNode): Promise<{ content: string, metadata: FileExplorerResourceMetadata }> { + const fetcher = store.fetcher + + const response = await fetcher.webOperation('GET', subject.uri) + const content = (response as Response & { responseText?: string }).responseText + + if (content === undefined) { + throw new Error('No text in response object!!') + } + + const metadata = getResponseMetadata(store, subject, response) + if (!metadata.contentType) { + throw new Error('No content-type available!') + } + + return { content, metadata } +} diff --git a/src/components/file-explorer-header/types.ts b/src/components/file-explorer-header/types.ts new file mode 100644 index 00000000..b3b3ecbd --- /dev/null +++ b/src/components/file-explorer-header/types.ts @@ -0,0 +1 @@ +export type PaneIcon = string | Promise | null | undefined diff --git a/src/components/resource-actions-menu/DeleteResourceDialog.ts b/src/components/resource-actions-menu/DeleteResourceDialog.ts new file mode 100644 index 00000000..42b1908f --- /dev/null +++ b/src/components/resource-actions-menu/DeleteResourceDialog.ts @@ -0,0 +1,36 @@ +import { customElement, DialogComponent } from 'solid-ui' +import { html } from 'lit' +import { property } from 'lit/decorators.js' + +import 'solid-ui/components/button' +import 'solid-ui/components/dialog' +import 'solid-ui/components/dialog-content' +import 'solid-ui/components/dialog-footer' + +@customElement('resource-delete-dialog') +export default class DeleteResourceDialog extends DialogComponent { + @property({ type: String }) + accessor resourceName = 'this resource' + + private cancel = () => this.close(false) + + private confirm = () => this.close(true) + + protected render () { + return html` + + +

Are you sure you want to permanently delete ${this.resourceName}?

+
+ + + Go back + + + Yes + + +
+ ` + } +} diff --git a/src/components/resource-actions-menu/ResourceActionsMenu.ts b/src/components/resource-actions-menu/ResourceActionsMenu.ts new file mode 100644 index 00000000..884b3004 --- /dev/null +++ b/src/components/resource-actions-menu/ResourceActionsMenu.ts @@ -0,0 +1,104 @@ +import { showDialog, utils, WebComponent } from 'solid-ui' +import { customElement, property } from 'lit/decorators.js' +import { html } from 'lit' +import 'solid-ui/components/button' +import 'solid-ui/components/menu' +import 'solid-ui/components/menu-item' +import DeleteResourceDialog from './DeleteResourceDialog' +import '~icons/lucide/ellipsis-vertical' +import '~icons/lucide/trash-2' +import { LiveStore } from 'rdflib' +// TODO: Add Error Status section + +@customElement('resource-actions-menu') +export default class ResourceActionsMenu extends WebComponent { + @property({ attribute: false }) + accessor store: LiveStore | undefined + + @property({ type: String }) + accessor subjectUri: string | undefined + + @property({ attribute: false }) + accessor menuItems: Array<{ label: string, icon?: HTMLElement, action: (event: Event) => void }> = [] + + private confirmDelete (resourceName: string) { + return new Promise(resolve => { + showDialog(DeleteResourceDialog, { + props: { resourceName }, + onClose: (result) => resolve(result === true) + }) + }) + } + + /* private gotoParentFolder(resourceUri: string) { + const sourceContext = this.sourceContext + const outliner = sourceContext?.context?.getOutliner?.(sourceContext.context.dom) + + if (!outliner) return + + const parentFolderUri = this.getParentFolderUri(resourceUri) + ;(outliner as any).GotoSubject(sourceContext.context.session.store.sym(parentFolderUri), true, undefined, true, undefined) + } */ + + private async deleteResourceIfPresent (store: LiveStore, uri: string) { + try { + await store.fetcher.webOperation('DELETE', uri) + } catch (err: any) { + const status = err?.response?.status ?? err?.status + if (status === 404) return + throw err + } + } + + // TODO: Below is for a file only. I need to move this to a function + // that function needs to check if it's a container and if so we can do the + // recursive delete function. + // dont' forget public and private type indexes. + private async handleDelete (event: Event) { + event.preventDefault() + + if (!this.store?.fetcher || !this.subjectUri) return + + const store = this.store + const resourceNode = store.sym(this.subjectUri) + + const confirmation = await this.confirmDelete(utils.label(resourceNode)) + if (!confirmation) return + + try { + await this.deleteResourceIfPresent(store, resourceNode.value) + + const aclUri = this.subjectUri + '.acl' + if (aclUri) { + await this.deleteResourceIfPresent(store, aclUri) + store.removeDocument(store.sym(aclUri)) + } + + store.removeDocument(resourceNode) + // this.gotoParentFolder(resourceNode.value) + } catch (err) { + // error('Error deleting resource:', err) + // getStatusSection()?.showError('Failed to delete resource. Check console for details.') + } + } + + render () { + return html` + + + + + ${this.menuItems.map(item => html` + item.action(event)}> + ${item.icon} + ${item.label} + + `)} + this.handleDelete(event)}> + + Delete + + + ` + } +} diff --git a/src/outline/manager.css b/src/outline/manager.css index 8cfc5614..028ad892 100644 --- a/src/outline/manager.css +++ b/src/outline/manager.css @@ -7,10 +7,6 @@ vertical-align: top; } -.pred, .pred.internal { - /* Add any specific styles for predicate TDs here */ -} - .iconTD { margin: 0.2em; border: none; @@ -23,29 +19,7 @@ width: 100%; } -.paneIconTray { - display: flex; - justify-content: flex-start; - align-items: center; -} - -.paneShown { - width: 24px; - border: none !important; - border-radius: var(--border-radius-md, 0.5rem); - margin-left: var(--spacing-small, 0.1rem); - padding: 0.188rem; /* 3px */ - background-color: var(--header-menu-item-hover, #e6dcff) !important; -} - -.paneHidden { - width: 24px; - border-radius: var(--border-radius-md, 0.5rem); - margin-left: var(--spacing-small, 0.1rem); - padding: 0.188rem; /* 3px */ -} - -.header { +.file-explorer-header { display: flex; justify-content: flex-start; align-items: center; @@ -77,3 +51,34 @@ background: var(--solid-ui-color-white, #fff); overflow: hidden; } + +.paneDiv, +.exceptionPane { + display: block; + width: 100%; + min-width: 0; +} + +.objectValue--literal { + white-space: pre-wrap; +} + +.objectValue--integer, +.objectValue--decimal, +.objectValue--double { + display: block; + text-align: right; +} + +.objectValueAccessIcon, +.objectValueLinkIcon, +.phoneIcon { + display: inline-block; + vertical-align: middle; +} + +.objectValueLinkIcon, +.phoneIcon { + width: 12px; + height: 12px; +} diff --git a/src/outline/manager.js b/src/outline/manager.js index 811b2ef4..1207ad30 100644 --- a/src/outline/manager.js +++ b/src/outline/manager.js @@ -12,11 +12,8 @@ import { outlineIcons } from './outlineIcons.js' // @@ chec import { UserInput } from './userInput.js' import * as queryByExample from './queryByExample.js' import { loadContainerRepresentation } from '../utils/podUtils' -import personIcon from '../icons/person.svg' -import friendsIcon from '../icons/friends.svg' - -const PERSON_ICON = personIcon -const FRIENDS_ICON = friendsIcon +import { isWebIdUri } from '../utils/webIdUtils' +import '../components/file-explorer-header/FileExplorerProvider' export default function (context) { const dom = context.dom @@ -168,6 +165,7 @@ export default function (context) { outlineIcons.tooltips[icon].replace(/[Tt]his resource/, docuri), dom ) + img.classList.add('objectValueAccessIcon') img.setAttribute('uri', uri) img.addEventListener('click', listener) // @@ seemed to be missing 2017-08 addButtonCallbacks(img, docuri) @@ -189,14 +187,10 @@ export default function (context) { const td = dom.createElement('td') td.classList.add('obj') td.setAttribute('notSelectable', 'false') - td.style.margin = '0.2em' if (!obj) { td.textContent = 'No object available.' return td } - td.style.border = 'none' - td.style.padding = '0' - td.style.verticalAlign = 'top' const theClass = 'obj' // set about and put 'expand' icon @@ -356,7 +350,7 @@ export default function (context) { if (subject.uri.endsWith('/')) { await loadContainerRepresentation(subject) } const panes = context.session.paneRegistry const relevantPanes = panes.list.filter( - pane => pane.label(subject, context) && !pane.global + pane => pane.label(subject, context) && !pane.global && pane.name !== 'sharing' ) if (relevantPanes.length === 0) { // there are no relevant panes, simply return default pane (which ironically is internalPane) @@ -383,232 +377,112 @@ 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 = - 'width: 24px; border-radius: 0.5em; margin-left: 1em; padding: 3px' - const paneIconTray = td.appendChild(dom.createElement('nav')) - paneIconTray.style = - 'display:flex; justify-content: flex-start; align-items: center;' - - const relevantPanes = options.hideList - ? [] - : await getRelevantPanes(subject, context) - tr.firstPane = requiredPane || getPane(relevantPanes, subject) - const paneNumber = relevantPanes.indexOf(tr.firstPane) - - if (relevantPanes.length !== 1) { - // if only one, simplify interface - relevantPanes.forEach((pane, index) => { - const label = pane.label(subject, context) - - let iconSrc = '' - if (pane.name === 'profile') { - iconSrc = PERSON_ICON - } else if (pane.name === 'social') { - iconSrc = FRIENDS_ICON - } else { - iconSrc = typeof pane.icon === 'function' ? pane.icon(subject, context) : pane.icon - } - const ico = UI.utils.AJARImage(iconSrc, label, label, dom) - - // Handle async icon functions - if (iconSrc instanceof Promise) { - iconSrc.then(resolvedIconSrc => { - ico.setAttribute('src', resolvedIconSrc) - }).catch(err => { - console.error('Error resolving async icon:', err) - }) - } + function setQueryButtonVisibility (shouldShow) { + const queryButton = dom.getElementById('queryButton') + if (!queryButton) return + if (shouldShow) { + queryButton.removeAttribute('style') + } else { + queryButton.setAttribute('style', 'display:none;') + } + } - ico.style = pane === tr.firstPane ? paneShownStyle : paneHiddenStyle // init to something at least - // ico.setAttribute('align','right'); @@ Should be better, but ffox bug pushes them down - // ico.style.width = iconHeight - // ico.style.height = iconHeight - const listen = function (ico, pane) { - // Freeze scope for event time - ico.addEventListener( - 'click', - function (event) { - let containingTable - // Find the containing table for this subject - for (containingTable = td; containingTable.parentNode; containingTable = containingTable.parentNode) { - if (containingTable.nodeName === 'TABLE') break - } - if (containingTable.nodeName !== 'TABLE') { - throw new Error('outline: internal error.') - } - const removePanes = function (specific) { - for (let d = containingTable.firstChild; d; d = d.nextSibling) { - if (typeof d.pane !== 'undefined') { - if (!specific || d.pane === specific) { - if (d.paneButton) { - d.paneButton.setAttribute('class', 'paneHidden') - d.paneButton.style = paneHiddenStyle - } - removeAndRefresh(d) - // If we just delete the node d, ffox doesn't refresh the display properly. - // state = 'paneHidden'; - if ( - d.pane.requireQueryButton && - containingTable.parentNode.className /* outer table */ && - numberOfPanesRequiringQueryButton === 1 && - dom.getElementById('queryButton') - ) { - dom - .getElementById('queryButton') - .setAttribute('style', 'display:none;') - } - } - } - } - } - const renderPane = function (pane) { - let paneDiv - UI.log.info('outline: Rendering pane (2): ' + pane.name) - - try { - paneDiv = pane.render(subject, context, options) - } catch (e) { - // Easier debugging for pane developers - paneDiv = dom.createElement('div') - paneDiv.setAttribute('class', 'exceptionPane') - const pre = dom.createElement('pre') - paneDiv.appendChild(pre) - pre.appendChild( - dom.createTextNode(UI.utils.stackString(e)) - ) - } - - if ( - pane.requireQueryButton && - dom.getElementById('queryButton') - ) { - dom.getElementById('queryButton').removeAttribute('style') - } - const second = containingTable.firstChild.nextSibling - const row = dom.createElement('tr') - const cell = row.appendChild(dom.createElement('td')) - cell.setAttribute('colspan', '2') - cell.style.textAlign = 'left' - cell.style.width = '100%' - cell.appendChild(paneDiv) - if (second) containingTable.insertBefore(row, second) - else containingTable.appendChild(row) - row.pane = pane - row.paneButton = ico - } - const state = ico.getAttribute('class') - if (state === 'paneHidden') { - if (!event.shiftKey) { - // shift means multiple select - removePanes() - } - renderPane(pane) - ico.setAttribute('class', 'paneShown') - ico.style = paneShownStyle - } else { - removePanes(pane) - ico.setAttribute('class', 'paneHidden') - ico.style = paneHiddenStyle - } + function findContainingTable (td) { + let containingTable + for (containingTable = td; containingTable.parentNode; containingTable = containingTable.parentNode) { + if (containingTable.nodeName === 'TABLE') break + } + if (containingTable.nodeName !== 'TABLE') { + throw new Error('outline: internal error.') + } + return containingTable + } - let numberOfPanesRequiringQueryButton = 0 - for (let d = containingTable.firstChild; d; d = d.nextSibling) { - if (d.pane && d.pane.requireQueryButton) { - numberOfPanesRequiringQueryButton++ - } - } - }, - false - ) - } // listen + function renderPaneIntoProvider (provider, subject, pane, options) { + if (!provider || !pane) return + + let paneDiv + try { + UI.log.info('outline: Rendering pane (menu): ' + pane.name) + paneDiv = pane.render(subject, context, options) + } catch (e) { + paneDiv = dom.createElement('div') + paneDiv.setAttribute('class', 'exceptionPane') + const pre = dom.createElement('pre') + paneDiv.appendChild(pre) + pre.appendChild(dom.createTextNode(UI.utils.stackString(e))) + } + + paneDiv.classList.add('paneDiv') + const existingPaneDiv = provider.querySelector('.paneDiv') + if (existingPaneDiv) { + existingPaneDiv.replaceWith(paneDiv) + } else { + provider.appendChild(paneDiv) + } + } - listen(ico, pane) - ico.setAttribute( - 'class', - index !== paneNumber ? 'paneHidden' : 'paneShown' - ) - if (index === paneNumber) tr.paneButton = ico - paneIconTray.appendChild(ico) - }) - } - return paneIconTray - } // renderPaneIconTray + function openPaneInPlace (subject, pane) { + const outlineView = dom.getElementById('OutlineView') + if (!outlineView) return + + const subjectId = subject.toNT() + const subjectTd = outlineView.querySelector('td.paneView[about="' + subjectId + '"]') + if (!subjectTd) return + + const provider = subjectTd.querySelector('file-explorer-provider') + if (!provider) return + if (!pane) { + UI.log.warn('outline: Unable to open pane in place: pane is undefined.') + return + } + + setQueryButtonVisibility(!!pane.requireQueryButton) + provider.openSelectedPane?.(pane) + renderPaneIntoProvider(provider, subject, pane, provider.paneRenderOptions) + } + + async function expandedProviderTR (subject, requiredPane, options) { + options = options || {} - // Body of expandedHeaderTR + // TODO: hide the main storage header + // const showHeader = !!requiredPane const tr = dom.createElement('tr') if (options.hover) { // By default no hide till hover as community deems it confusing - tr.setAttribute('class', 'hoverControl') + tr.classList.add('hoverControl') } const td = tr.appendChild(dom.createElement('td')) - td.classList.add('tdFlex') + td.classList.add('paneView', 'tdFlex') td.setAttribute('notSelectable', 'true') td.setAttribute('about', subject.toNT()) td.setAttribute('colspan', '2') - // Stuff at the right about the subject - const header = td.appendChild(dom.createElement('div')) - header.style = - 'display:flex; justify-content: flex-start; align-items: center; flex-wrap: wrap;' - - const showHeader = !!requiredPane - - if (!options.solo && !showHeader) { - const icon = header.appendChild( - UI.utils.AJARImage( - UI.icons.originalIconBase + 'tbl-collapse.png', - 'collapse', - undefined, - dom - ) - ) - icon.addEventListener('click', collapseMouseDownListener) - - const strong = header.appendChild(dom.createElement('h1')) - strong.appendChild(dom.createTextNode(UI.utils.label(subject))) - strong.style = - '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 - }) - ) - } - - // Pane icon tray removed: preserve first-pane selection without rendering the tray. - await determineFirstPane({ hideList: showHeader }) - - // Hide the header row when the header div has no rendered children. - if (header.childNodes.length === 0) { - tr.style.display = 'none' + const provider = td.appendChild(dom.createElement('file-explorer-provider')) + provider.context = context + provider.subjectUri = subject.uri + provider.onBack = () => collapseMouseDownListener({ target: provider }) + + const relevantPanes = options.hideList + ? [] + : await getRelevantPanes(subject, context) + + provider.relevantPanes = relevantPanes + provider.pane = requiredPane || getPane(relevantPanes, subject) + const isRootResource = !!(subject && subject.uri && subject.site && subject.site().uri === subject.uri) + provider.showHeader = !isRootResource && !isWebIdUri(subject) + provider.paneRenderOptions = options + provider.soloPane = options.solo + provider.openPane = (paneSubject, paneName) => openPaneInPlace(paneSubject, paneRegistry.byName(paneName)) + // TODO: for now we do this until we create sharing dialog in solid-panes + provider.handleSharingClick = () => openPaneInPlace(subject, paneRegistry.byName('sharing')) + + if (provider.pane) { + tr.classList.add('outlinePaneRow') + renderPaneIntoProvider(provider, subject, provider.pane, options) } - - /* // set DOM methods - tr.firstChild.tabulatorSelect = function () { - setSelected(this, true) - } - tr.firstChild.tabulatorDeselect = function () { - setSelected(this, false) - } */ return tr - } // expandedHeaderTR + } // / ////////////////////////////////////////////////////////////////////////// @@ -648,51 +522,19 @@ export default function (context) { const propertyTable = (this.propertyTable = function propertyTable ( subject, table, - pane, + requiredPane, options ) { UI.log.debug('Property table for: ' + subject) subject = kb.canon(subject) - // if (!pane) pane = panes.defaultPane; + // if (!requiredPane) requiredPane = panes.defaultPane; if (!table) { // Create a new property table table = dom.createElement('table') table.classList.add('tableFullWidth') - expandedHeaderTR(subject, pane, options).then(tr1 => { - table.appendChild(tr1) - - if (tr1.firstPane) { - let paneDiv - try { - UI.log.info('outline: Rendering pane (1): ' + tr1.firstPane.name) - paneDiv = tr1.firstPane.render(subject, context, options) - } catch (e) { - // Easier debugging for pane developers - paneDiv = dom.createElement('div') - paneDiv.setAttribute('class', 'exceptionPane') - const pre = dom.createElement('pre') - paneDiv.appendChild(pre) - pre.appendChild(dom.createTextNode(UI.utils.stackString(e))) - } - - const row = dom.createElement('tr') - const cell = row.appendChild(dom.createElement('td')) - cell.setAttribute('colspan', '2') - cell.style.textAlign = 'left' - cell.style.width = '100%' - cell.style.backgroundColor = 'var(--color-background, #F8F9FB)' - cell.appendChild(paneDiv) - if ( - tr1.firstPane.requireQueryButton && - dom.getElementById('queryButton') - ) { - dom.getElementById('queryButton').removeAttribute('style') - } - table.appendChild(row) - row.pane = tr1.firstPane - row.paneButton = tr1.paneButton - } + expandedProviderTR(subject, requiredPane, options).then(providerTR => { + table.appendChild(providerTR) }) return table @@ -986,7 +828,6 @@ export default function (context) { try { baseURI = dom.location.href.split('?')[0] } catch (e) { - console.log(e) baseURI = '' } const relativeIconSrc = $rdf.uri.join(icon.src, baseURI) @@ -1011,10 +852,6 @@ export default function (context) { const makeIconCallback = function (icon) { return function IconCallback (req) { if (req.indexOf('#') >= 0) { - console.log( - '@@ makeIconCallback: Not expecting # in URI whose state changed: ' + - req - ) // alert('Should have no hash in '+req) } if (!target) { @@ -1132,7 +969,6 @@ export default function (context) { } // .class doesn't work. Be careful! for (let i = 0; i < selection.length; i++) { if (!selection[i].parentNode) { - console.log('showSource: EH? no parentNode? ' + selection[i] + '\n') continue } const st = selection[i].parentNode.AJAR_statement @@ -2040,7 +1876,8 @@ export default function (context) { } function GotoSubjectDefault () { - const tr = dom.createElement('TR') + const tr = dom.createElement('tr') + tr.classList.add('outlineRow1') tr.style.verticalAlign = 'top' table.appendChild(tr) const td = thisOutline.outlineObjectTD(subject, undefined, tr) @@ -2082,7 +1919,6 @@ export default function (context) { } } } catch (e) { - console.log(e) } } @@ -2107,24 +1943,19 @@ export default function (context) { let rep // representation in html if (obj.termType === 'Literal') { - const styles = { - integer: 'text-align: right;', - decimal: 'text-align: \'.\';', - double: 'text-align: \'.\';' - } rep = dom.createElement('span') + rep.classList.add('objectValue', 'objectValue--literal') rep.textContent = obj.value // Newlines have effect and overlong lines wrapped automatically - let style = '' if (obj.datatype && obj.datatype.uri) { const xsd = UI.ns.xsd('').uri if (obj.datatype.uri.slice(0, xsd.length) === xsd) { - style = styles[obj.datatype.uri.slice(xsd.length)] + rep.classList.add('objectValue--' + obj.datatype.uri.slice(xsd.length)) } } - rep.setAttribute('style', style || 'white-space: pre-wrap;') } else if (obj.termType === 'NamedNode' || obj.termType === 'BlankNode') { rep = dom.createElement('span') + rep.classList.add('objectValue', 'objectValue--resource') rep.setAttribute('about', obj.toNT()) thisOutline.appendAccessIcons(kb, rep, obj) @@ -2144,10 +1975,14 @@ export default function (context) { ) rep.appendChild(anchor) anchor.firstChild.setAttribute('class', 'phoneIcon') + anchor.firstChild.classList.add('objectValueLinkIcon') } else { // not tel: rep.appendChild(dom.createTextNode(UI.utils.label(obj))) const anchor = UI.widgets.linkIcon(dom, obj) + if (anchor.firstChild) { + anchor.firstChild.classList.add('objectValueLinkIcon') + } rep.appendChild(anchor) UI.widgets.makeDraggable(rep, obj) // 2017 } diff --git a/src/outline/sourcePaneIcon.ts b/src/outline/sourcePaneIcon.ts new file mode 100644 index 00000000..103c7140 --- /dev/null +++ b/src/outline/sourcePaneIcon.ts @@ -0,0 +1,8 @@ +import { html } from 'lit' + +export const sourcePaneIcon = html` + + + + +` diff --git a/test/unit/outline/manager.test.ts b/test/unit/outline/manager.test.ts index 01636c77..693663a4 100644 --- a/test/unit/outline/manager.test.ts +++ b/test/unit/outline/manager.test.ts @@ -55,12 +55,8 @@ describe('manager', () => { it('is selectable', () => { expect(result).toHaveAttribute('notselectable', 'false') }) - it('uses main inline layout styles', () => { - expect(result).toHaveStyle({ - margin: '0.2em', - padding: '0px', - verticalAlign: 'top' - }) + it('uses object cell class for layout styling', () => { + expect(result).toHaveClass('obj') }) it('shows an expand icon', () => { const img = result.firstChild @@ -113,12 +109,8 @@ describe('manager', () => { it('is selectable', () => { expect(result).toHaveAttribute('notselectable', 'false') }) - it('uses main inline layout styles', () => { - expect(result).toHaveStyle({ - margin: '0.2em', - padding: '0px', - verticalAlign: 'top' - }) + it('uses object cell class for layout styling', () => { + expect(result).toHaveClass('obj') }) it('shows an expand icon', () => { const img = result.firstChild @@ -164,19 +156,15 @@ describe('manager', () => { it('is selectable', () => { expect(result).toHaveAttribute('notselectable', 'false') }) - it('uses main inline layout styles', () => { - expect(result).toHaveStyle({ - margin: '0.2em', - padding: '0px', - verticalAlign: 'top' - }) + it('uses object cell class for layout styling', () => { + expect(result).toHaveClass('obj') }) it('shows the literal text', () => { expect(result).toHaveTextContent('some text') }) - it('literal text preserves white space', () => { + it('literal text uses literal styling class', () => { const text = getByText(result, 'some text') - expect(text).toHaveStyle('white-space: pre-wrap;') + expect(text).toHaveClass('objectValue--literal') }) }) @@ -198,12 +186,8 @@ describe('manager', () => { it('is selectable', () => { expect(result).toHaveAttribute('notselectable', 'false') }) - it('uses main inline layout styles', () => { - expect(result).toHaveStyle({ - margin: '0.2em', - padding: '0px', - verticalAlign: 'top' - }) + it('uses object cell class for layout styling', () => { + expect(result).toHaveClass('obj') }) it('shows 3 dots', () => { expect(result).toHaveTextContent('...')