Add our own router

This commit is contained in:
Rūdolfs Ošiņš
2024-09-03 16:30:12 +02:00
parent 484d0d58ba
commit 8179ed0f3e
14 changed files with 684 additions and 332 deletions
+233 -235
View File
@@ -18,6 +18,7 @@
"@sveltejs/vite-plugin-svelte": "^3.1.2",
"@tauri-apps/cli": "^2.0.0-rc.1",
"@tsconfig/svelte": "^5.0.4",
"baconjs": "^3.0.19",
"eslint": "^9.9.1",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.43.0",
@@ -26,7 +27,6 @@
"svelte": "^4.2.19",
"svelte-check": "^4.0.0",
"svelte-eslint-parser": "^0.41.0",
"svelte-routing": "^2.13.0",
"tslib": "^2.7.0",
"typescript": "^5.2.2",
"typescript-eslint": "^8.4.0",
@@ -432,6 +432,18 @@
"eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
}
},
"node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@eslint-community/regexpp": {
"version": "4.11.0",
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz",
@@ -478,35 +490,6 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@eslint/eslintrc/node_modules/eslint-visitor-keys": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
"integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
"dev": true,
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@eslint/eslintrc/node_modules/espree": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz",
"integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==",
"dev": true,
"dependencies": {
"acorn": "^8.12.0",
"acorn-jsx": "^5.3.2",
"eslint-visitor-keys": "^4.0.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@eslint/js": {
"version": "9.9.1",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.1.tgz",
@@ -882,23 +865,18 @@
}
},
"node_modules/@tauri-apps/api": {
"version": "2.0.0-beta.15",
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.0.0-beta.15.tgz",
"integrity": "sha512-H9w6iISmR+NvH4XuyCZB4zDN10tf9RFt6i/9JHEjaRhAowdAaJ+oiXq/3kedizNClHMtbTQ5j0oqDVPkZDAI8g==",
"engines": {
"node": ">= 18.18",
"npm": ">= 6.6.0",
"yarn": ">= 1.19.1"
},
"version": "2.0.0-rc.4",
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.0.0-rc.4.tgz",
"integrity": "sha512-UNiIhhKG08j4ooss2oEEVexffmWkgkYlC2M3GcX3VPtNsqFgVNL8Mcw/4Y7rO9M9S+ffAMnLOF5ypzyuyb8tyg==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/tauri"
}
},
"node_modules/@tauri-apps/cli": {
"version": "2.0.0-rc.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.0.0-rc.1.tgz",
"integrity": "sha512-9AzVrUMdb6EZ/Lwtdqt03XqqG6d/3gTJPOw2E9zmCHprJWEwqEp4JIVHYYfrqkkZyKclD3m5ggXwfYwclcYLdw==",
"version": "2.0.0-rc.10",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.0.0-rc.10.tgz",
"integrity": "sha512-mnoMyeD65DoVWzrLiLRW8Ns5Aktn9Ua7eKTOUEPq+r+1sQtWKxfnYTBEbEWnivduLhJCEDqGP5tyJaPcVXcEzA==",
"dev": true,
"bin": {
"tauri": "tauri.js"
@@ -911,22 +889,22 @@
"url": "https://opencollective.com/tauri"
},
"optionalDependencies": {
"@tauri-apps/cli-darwin-arm64": "2.0.0-rc.1",
"@tauri-apps/cli-darwin-x64": "2.0.0-rc.1",
"@tauri-apps/cli-linux-arm-gnueabihf": "2.0.0-rc.1",
"@tauri-apps/cli-linux-arm64-gnu": "2.0.0-rc.1",
"@tauri-apps/cli-linux-arm64-musl": "2.0.0-rc.1",
"@tauri-apps/cli-linux-x64-gnu": "2.0.0-rc.1",
"@tauri-apps/cli-linux-x64-musl": "2.0.0-rc.1",
"@tauri-apps/cli-win32-arm64-msvc": "2.0.0-rc.1",
"@tauri-apps/cli-win32-ia32-msvc": "2.0.0-rc.1",
"@tauri-apps/cli-win32-x64-msvc": "2.0.0-rc.1"
"@tauri-apps/cli-darwin-arm64": "2.0.0-rc.10",
"@tauri-apps/cli-darwin-x64": "2.0.0-rc.10",
"@tauri-apps/cli-linux-arm-gnueabihf": "2.0.0-rc.10",
"@tauri-apps/cli-linux-arm64-gnu": "2.0.0-rc.10",
"@tauri-apps/cli-linux-arm64-musl": "2.0.0-rc.10",
"@tauri-apps/cli-linux-x64-gnu": "2.0.0-rc.10",
"@tauri-apps/cli-linux-x64-musl": "2.0.0-rc.10",
"@tauri-apps/cli-win32-arm64-msvc": "2.0.0-rc.10",
"@tauri-apps/cli-win32-ia32-msvc": "2.0.0-rc.10",
"@tauri-apps/cli-win32-x64-msvc": "2.0.0-rc.10"
}
},
"node_modules/@tauri-apps/cli-darwin-arm64": {
"version": "2.0.0-rc.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.0.0-rc.1.tgz",
"integrity": "sha512-dJxyAi4P9fOkklBZXuwUVnHgdM/20fgM4zYdfejQfju5+q9GUqnMbrrIUqlJbQGf8EnrIdSWnieO8wU8GOwT0g==",
"version": "2.0.0-rc.10",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.0.0-rc.10.tgz",
"integrity": "sha512-oAuG3n/dIqK5ZedknF1QOgVDlpEepAaaIFHpUi+eIdG1MFp82jgyHqplveVZ95F16j7RhjIMaEhiTF6cGR/baA==",
"cpu": [
"arm64"
],
@@ -940,9 +918,9 @@
}
},
"node_modules/@tauri-apps/cli-darwin-x64": {
"version": "2.0.0-rc.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.0.0-rc.1.tgz",
"integrity": "sha512-dwrqLzNIFk8a1Vf2YI8axHm7uvLfo4M4TSWCw2ZkgeSGWWK6Y6CYVZbBEjOEGIOf+GFAa9rVOSZRuMwpiufNng==",
"version": "2.0.0-rc.10",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.0.0-rc.10.tgz",
"integrity": "sha512-n4ul0XUBqrA7KbNY6Vo52EBNqTXogYuV2qi5RWR0bIJF/A/vYjZ3LcC1TXXo/X57sDN55LWORrBe4c4Ds8MZrA==",
"cpu": [
"x64"
],
@@ -956,9 +934,9 @@
}
},
"node_modules/@tauri-apps/cli-linux-arm-gnueabihf": {
"version": "2.0.0-rc.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.0.0-rc.1.tgz",
"integrity": "sha512-jvMF4UNc3Jr/xHnw+4NNsWfk8WrcFrQVImAtKlCev9QepqfBmDh+FgXTvfysoBCSxEBS626TvYms3OhI0LOO4A==",
"version": "2.0.0-rc.10",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.0.0-rc.10.tgz",
"integrity": "sha512-RByz0zRbngps5QMQVsbgCD03TiCMxwAhaZhNtojXQ2AiJFkv1Mu68W/prbpWucw6Ep1nM3/yTIm0aL6ozdh/gw==",
"cpu": [
"arm"
],
@@ -972,9 +950,9 @@
}
},
"node_modules/@tauri-apps/cli-linux-arm64-gnu": {
"version": "2.0.0-rc.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.0.0-rc.1.tgz",
"integrity": "sha512-TGmadGW8BjTq864AYrv/u+vTnAodnOuzv1VCUOV23O8st35GZG6V47jwNsSjQjhrcO1XzmJiRAtrcVKuTZ/xUA==",
"version": "2.0.0-rc.10",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.0.0-rc.10.tgz",
"integrity": "sha512-ZqpbDIMp5b0jz1ddutJH6S5geLaBEmsMG6eZix+MgcZZRyEfahTMGCq3xkvv+tnrNNq7drvwBISCVSSS0zu3wQ==",
"cpu": [
"arm64"
],
@@ -988,9 +966,9 @@
}
},
"node_modules/@tauri-apps/cli-linux-arm64-musl": {
"version": "2.0.0-rc.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.0.0-rc.1.tgz",
"integrity": "sha512-+SJsRTW0PvvD7awEn+tIPJ3s12s6RpKXdOib2mztoKocasrGRfz+EFZuXc42Iwk3xROsrQkiw2UAmcNLkW5NwA==",
"version": "2.0.0-rc.10",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.0.0-rc.10.tgz",
"integrity": "sha512-EVh1xPqs5bi0aBYbv6Iy1ooFClyK6/wIsNw9DyxWwhPz9I7UNpDAgHm6lOhkMH26Cp/eQPiEA8OdfOLTfCY81A==",
"cpu": [
"arm64"
],
@@ -1004,9 +982,9 @@
}
},
"node_modules/@tauri-apps/cli-linux-x64-gnu": {
"version": "2.0.0-rc.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.0.0-rc.1.tgz",
"integrity": "sha512-vjPrj2btS97IOp6cU42IrkI49SQZDSg8TPqwOwFqyQeAotCT1i0F38pLZWe1gLyPUowO8XdaaBdwYg6IRDKcZg==",
"version": "2.0.0-rc.10",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.0.0-rc.10.tgz",
"integrity": "sha512-ZLcXJbRRMfgSkZdxBegP/4PlXkoVR1zpx2pE7mKkRgyvwJCx+A2f0+IZM+VVu/WRECxAdzVCbgxztTAOoLkdrg==",
"cpu": [
"x64"
],
@@ -1020,9 +998,9 @@
}
},
"node_modules/@tauri-apps/cli-linux-x64-musl": {
"version": "2.0.0-rc.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.0.0-rc.1.tgz",
"integrity": "sha512-MrE68/u6rMrkM1uM/DR1MNnMXiYebhSPGqqxshJ12SmFdk3yQ/Z73Wzvk8xv78eOExh4lTtEXI22YwaBCf9AEg==",
"version": "2.0.0-rc.10",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.0.0-rc.10.tgz",
"integrity": "sha512-IgzRemlQT+SHfb2x8kq32xKGnR3r7S69Ogv5pBKIDX1/G2qQofM6wfy0OHnAyS4Bj0y2lZPjiYQBwmLIkK/BNw==",
"cpu": [
"x64"
],
@@ -1036,9 +1014,9 @@
}
},
"node_modules/@tauri-apps/cli-win32-arm64-msvc": {
"version": "2.0.0-rc.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.0.0-rc.1.tgz",
"integrity": "sha512-SLulbiUjg8BGf/zX+U1PGjB+JpsN2nLRGuW07BYwSDW3s3mp2aagLuOwaTaOPBrDzfIMRYq8KT54A4jfRjEZlg==",
"version": "2.0.0-rc.10",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.0.0-rc.10.tgz",
"integrity": "sha512-RmSh5omDiCEZgw1fOhdEFi6MzAQ1rQBmvTM13K2p8XUxxaYb/MHYYZbNEMqxqWvsg4fidZ8hNSqRkB7YCCWWgg==",
"cpu": [
"arm64"
],
@@ -1052,9 +1030,9 @@
}
},
"node_modules/@tauri-apps/cli-win32-ia32-msvc": {
"version": "2.0.0-rc.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.0.0-rc.1.tgz",
"integrity": "sha512-rz85riTjcWdZlgTku6HcBx625Otdc0/NwDjRXgdXakL1ybw7E+G5YlLZNcQX25u17RKUAWX/2/VZ1pSz945Ovw==",
"version": "2.0.0-rc.10",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.0.0-rc.10.tgz",
"integrity": "sha512-6zxZ1KnKqflC5YpJmXZyNNVaRXMdOiRijimua8zLzfoAo+adb6gd8V4o03rZF3BPHtmd35rPkZHlgMlg/th2Bw==",
"cpu": [
"ia32"
],
@@ -1068,9 +1046,9 @@
}
},
"node_modules/@tauri-apps/cli-win32-x64-msvc": {
"version": "2.0.0-rc.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.0.0-rc.1.tgz",
"integrity": "sha512-aRO70dDbn4w3CbALMG+b7g460xmbSTuUiGmRh0r/MNVeoZk/YbqluBUyhXdWGxJb8OVubw/4RlczKYcPmJceMw==",
"version": "2.0.0-rc.10",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.0.0-rc.10.tgz",
"integrity": "sha512-D7L9QnxUJcSykQ9S8AQ0CEdxaw3IMoyAwv2LR7x+w/j7Jg3UsEgnsX5ePkShBiqSmu/UXfSuQeGvAoA8kSLiUw==",
"cpu": [
"x64"
],
@@ -1084,28 +1062,19 @@
}
},
"node_modules/@tauri-apps/plugin-shell": {
"version": "2.0.0-beta.8",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-shell/-/plugin-shell-2.0.0-beta.8.tgz",
"integrity": "sha512-rFXI6MvsCdSGbuKbDu/NaOePREb9YTVTdeugHdvvljnKWW3dvmThBb2h/8Hxj+Z7Cd8MUoRxPeJWUZbPbJ2Imw==",
"version": "2.0.0-rc.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-shell/-/plugin-shell-2.0.0-rc.1.tgz",
"integrity": "sha512-JtNROc0rqEwN/g93ig5pK4cl1vUo2yn+osCpY9de64cy/d9hRzof7AuYOgvt/Xcd5VPQmlgo2AGvUh5sQRSR1A==",
"dependencies": {
"@tauri-apps/api": "2.0.0-beta.15"
"@tauri-apps/api": "^2.0.0-rc.4"
}
},
"node_modules/@tauri-apps/plugin-window-state": {
"version": "2.0.0-rc.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-window-state/-/plugin-window-state-2.0.0-rc.0.tgz",
"integrity": "sha512-lR8reD+D1yIHT+53v56WltLS0+Y2zIkKqTuwrvz1yNbY5Hk4Z6foFV2Byo4kJAAvi5vbeGtvxYAjSiczZK5euw==",
"version": "2.0.0-rc.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-window-state/-/plugin-window-state-2.0.0-rc.1.tgz",
"integrity": "sha512-fQG6G6G+b3mx2QE6dAFxl3iyKvz35DpGggIczKn+qRc4Mdjsb9y42iJMUpMpZAC2q9j8h3LfknguCacifVP5lA==",
"dependencies": {
"@tauri-apps/api": "^2.0.0-rc.0"
}
},
"node_modules/@tauri-apps/plugin-window-state/node_modules/@tauri-apps/api": {
"version": "2.0.0-rc.2",
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.0.0-rc.2.tgz",
"integrity": "sha512-qIJJ1gKkzpPmEmIGTpja6XhuCD8A+vEh/wKaO7TzbxKiws5w3E+Kg4sBtwrH85hjMyqT0SgAUVaUk9XS7FBg3g==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/tauri"
"@tauri-apps/api": "^2.0.0-rc.4"
}
},
"node_modules/@tsconfig/svelte": {
@@ -1120,17 +1089,6 @@
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
"dev": true
},
"node_modules/@types/node": {
"version": "22.5.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.0.tgz",
"integrity": "sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"undici-types": "~6.19.2"
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.4.0.tgz",
@@ -1337,6 +1295,18 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/acorn": {
"version": "8.12.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
@@ -1411,6 +1381,18 @@
"node": ">= 8"
}
},
"node_modules/anymatch/node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -1435,6 +1417,12 @@
"node": ">= 0.4"
}
},
"node_modules/baconjs": {
"version": "3.0.19",
"resolved": "https://registry.npmjs.org/baconjs/-/baconjs-3.0.19.tgz",
"integrity": "sha512-/h7R6hTql8yk1FxYk/bTALea7fGcSJrUoLHFhX1WEkfI4C2mbR4sPbaNd0EhUIDJi3QwTBWEFHh7xEAaz3A3/A==",
"dev": true
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -1524,6 +1512,18 @@
"fsevents": "~2.3.2"
}
},
"node_modules/chokidar/node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"dependencies": {
"is-glob": "^4.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/code-red": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz",
@@ -1601,9 +1601,9 @@
}
},
"node_modules/debug": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
@@ -1812,34 +1812,6 @@
}
},
"node_modules/eslint-scope": {
"version": "7.2.2",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
"integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
"dev": true,
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint-visitor-keys": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint/node_modules/eslint-scope": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz",
"integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==",
@@ -1855,7 +1827,7 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint/node_modules/eslint-visitor-keys": {
"node_modules/eslint-visitor-keys": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
"integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
@@ -1867,7 +1839,7 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint/node_modules/espree": {
"node_modules/espree": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz",
"integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==",
@@ -1884,35 +1856,6 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint/node_modules/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
"dependencies": {
"is-glob": "^4.0.3"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/espree": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
"integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
"dev": true,
"dependencies": {
"acorn": "^8.9.0",
"acorn-jsx": "^5.3.2",
"eslint-visitor-keys": "^3.4.1"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/esquery": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
@@ -1986,6 +1929,18 @@
"node": ">=8.6.0"
}
},
"node_modules/fast-glob/node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"dependencies": {
"is-glob": "^4.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -2007,6 +1962,20 @@
"reusify": "^1.0.4"
}
},
"node_modules/fdir": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.3.0.tgz",
"integrity": "sha512-QOnuT+BOtivR77wYvCWHfGt9s4Pz1VIMbD463vegT5MLqNXy8rYFT/lPVEqf/bhYeT6qmqrNHhsX+rWwe3rOCQ==",
"dev": true,
"peerDependencies": {
"picomatch": "^3 || ^4"
},
"peerDependenciesMeta": {
"picomatch": {
"optional": true
}
}
},
"node_modules/file-entry-cache": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@@ -2081,15 +2050,15 @@
}
},
"node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
"dependencies": {
"is-glob": "^4.0.1"
"is-glob": "^4.0.3"
},
"engines": {
"node": ">= 6"
"node": ">=10.13.0"
}
},
"node_modules/globals": {
@@ -2120,9 +2089,9 @@
}
},
"node_modules/ignore": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
"integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
"dev": true,
"engines": {
"node": ">= 4"
@@ -2323,12 +2292,12 @@
"dev": true
},
"node_modules/magic-string": {
"version": "0.30.10",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz",
"integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==",
"version": "0.30.11",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz",
"integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==",
"dev": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15"
"@jridgewell/sourcemap-codec": "^1.5.0"
}
},
"node_modules/mdn-data": {
@@ -2359,6 +2328,18 @@
"node": ">=8.6"
}
},
"node_modules/micromatch/node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -2508,18 +2489,20 @@
}
},
"node_modules/picocolors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
"integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
"integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
"dev": true
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"optional": true,
"peer": true,
"engines": {
"node": ">=8.6"
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
@@ -2625,9 +2608,9 @@
}
},
"node_modules/postcss-selector-parser": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz",
"integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==",
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
"dev": true,
"dependencies": {
"cssesc": "^3.0.0",
@@ -2712,6 +2695,18 @@
"node": ">=8.10.0"
}
},
"node_modules/readdirp/node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
@@ -2927,34 +2922,6 @@
"typescript": ">=5.0.0"
}
},
"node_modules/svelte-check/node_modules/fdir": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.3.0.tgz",
"integrity": "sha512-QOnuT+BOtivR77wYvCWHfGt9s4Pz1VIMbD463vegT5MLqNXy8rYFT/lPVEqf/bhYeT6qmqrNHhsX+rWwe3rOCQ==",
"dev": true,
"peerDependencies": {
"picomatch": "^3 || ^4"
},
"peerDependenciesMeta": {
"picomatch": {
"optional": true
}
}
},
"node_modules/svelte-check/node_modules/picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/svelte-eslint-parser": {
"version": "0.41.0",
"resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.41.0.tgz",
@@ -2982,6 +2949,51 @@
}
}
},
"node_modules/svelte-eslint-parser/node_modules/eslint-scope": {
"version": "7.2.2",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
"integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
"dev": true,
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/svelte-eslint-parser/node_modules/eslint-visitor-keys": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/svelte-eslint-parser/node_modules/espree": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
"integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
"dev": true,
"dependencies": {
"acorn": "^8.9.0",
"acorn-jsx": "^5.3.2",
"eslint-visitor-keys": "^3.4.1"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/svelte-hmr": {
"version": "0.16.0",
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz",
@@ -2994,12 +3006,6 @@
"svelte": "^3.19.0 || ^4.0.0"
}
},
"node_modules/svelte-routing": {
"version": "2.13.0",
"resolved": "https://registry.npmjs.org/svelte-routing/-/svelte-routing-2.13.0.tgz",
"integrity": "sha512-/NTxqTwLc7Dq306hARJrH2HLXOBtKd7hu8nxgoFDlK0AC4SOKnzisiX/9m8Uksei1QAWtlAEdF91YphNM8iDMg==",
"dev": true
},
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -3084,14 +3090,6 @@
}
}
},
"node_modules/undici-types": {
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"dev": true,
"optional": true,
"peer": true
},
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+1 -1
View File
@@ -27,6 +27,7 @@
"@tauri-apps/cli": "^2.0.0-rc.1",
"@tsconfig/svelte": "^5.0.4",
"eslint": "^9.9.1",
"baconjs": "^3.0.19",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.43.0",
"prettier": "^3.3.3",
@@ -34,7 +35,6 @@
"svelte": "^4.2.19",
"svelte-check": "^4.0.0",
"svelte-eslint-parser": "^0.41.0",
"svelte-routing": "^2.13.0",
"tslib": "^2.7.0",
"typescript": "^5.2.2",
"typescript-eslint": "^8.4.0",
-7
View File
@@ -15,10 +15,3 @@ html {
height: 100%;
width: 100%;
}
code {
font-family: var(--font-family-monospace);
font-size: var(--font-size-small);
background-color: var(--color-fill-ghost);
padding: 0.125rem 0.25rem;
}
+38 -8
View File
@@ -1,16 +1,46 @@
<script lang="ts">
import { Router, Route } from "svelte-routing";
import { onMount } from "svelte";
import { invoke } from "@tauri-apps/api/core";
import * as router from "@app/lib/router";
import { theme } from "@app/components/ThemeSwitch.svelte";
import { unreachable } from "@app/lib/utils";
import DesignSystem from "@app/views/DesignSystem.svelte";
import Repos from "@app/views/Repos.svelte";
import Startup from "@app/views/Startup.svelte";
import Home from "@app/views/Home.svelte";
import AuthenticationError from "@app/views/AuthenticationError.svelte";
const activeRouteStore = router.activeRouteStore;
void router.loadFromLocation();
onMount(async () => {
try {
await invoke("authenticate");
void router.push({ resource: "home" });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) {
void router.push({
resource: "authenticationError",
params: {
error: e.err,
hint: e.hint,
},
});
}
});
$: document.documentElement.setAttribute("data-theme", $theme);
</script>
<Router>
<Route path="/" component={Startup} />
<Route path="/repos" component={Repos} />
<Route path="/design-system" component={DesignSystem} />
</Router>
{#if $activeRouteStore.resource === "booting"}
<!-- Don't show anything -->
{:else if $activeRouteStore.resource === "home"}
<Home />
{:else if $activeRouteStore.resource === "authenticationError"}
<AuthenticationError {...$activeRouteStore.params} />
{:else if $activeRouteStore.resource === "designSystem"}
<DesignSystem />
{:else}
{unreachable($activeRouteStore)}
{/if}
+19 -4
View File
@@ -5,6 +5,8 @@
import Icon from "./Icon.svelte";
import Popover from "./Popover.svelte";
import ThemeSwitch from "./ThemeSwitch.svelte";
export let currentPage: string;
</script>
<style>
@@ -26,17 +28,30 @@
gap: 0.5rem;
padding: 0 0.5rem;
}
.navigation :global(svg:hover) {
display: flex;
color: var(--color-fill-secondary);
}
</style>
<header class="flex-item">
<div class="wrapper flex-item">
<div class="wrapper-left flex-item">
<div class="flex-item" style:gap="0.5rem">
<Icon name="arrow-left" />
<Icon name="arrow-right" />
<div class="flex-item navigation" style:gap="0.5rem">
<Icon
name="arrow-left"
on:click={() => {
window.history.back();
}} />
<Icon
name="arrow-right"
on:click={() => {
window.history.forward();
}} />
</div>
<Fill variant="ghost" stylePadding="0 0.5rem" styleHeight="32px">
Repositories
{currentPage}
</Fill>
<Border variant="ghost" stylePadding="0 0.25rem" styleHeight="32px">
<Icon name="plus" />
+3
View File
@@ -26,6 +26,9 @@
svg {
display: flex;
flex-shrink: 0;
-webkit-touch-callout: none;
-webkit-user-select: none;
user-select: none;
}
</style>
+39
View File
@@ -0,0 +1,39 @@
<script lang="ts" strictEvents>
import type { Route } from "@app/lib/router/definitions";
import { createEventDispatcher } from "svelte";
import { push, routeToPath } from "@app/lib/router";
export let route: Route;
export let disabled: boolean = false;
const dispatch = createEventDispatcher<{
afterNavigate: null;
}>();
function navigateToRoute(event: MouseEvent): void {
event.preventDefault();
if (disabled) {
return;
}
void push(route);
dispatch("afterNavigate");
}
</script>
<style>
a {
color: var(--color-fill-secondary);
text-decoration: none;
}
a:hover {
text-decoration: underline;
text-decoration-thickness: 1px;
text-underline-offset: 2px;
}
</style>
<a on:click={navigateToRoute} href={routeToPath(route)}>
<slot />
</a>
+113
View File
@@ -0,0 +1,113 @@
// Copyright © 2021 The Radicle Upstream Contributors
//
// This file is part of radicle-upstream, distributed under the GPLv3
// with Radicle Linking Exception. For full terms see the included
// LICENSE file.
//@ts-expect-error the typescript bindings are out of date.
import * as Bacon from "baconjs";
// A task executor that runs only one task concurrently. If a new task
// is run, any previously running task is aborted and the promise
// returned from `run()` will return undefined.
//
// import * as mutexExecutor from "ui/src/mutexExecutor"
// const executor = mutexExecutor.create()
// const first = await executor.run(async () => {
// await sleep(1000)
// return "first"
// })
// const second = await executor.run(async () => "second")
//
// In the example above the promise `first` will resolve to `undefined`
// while the promise `second` will resolve to "second".
//
// If the first tasks throws after the second task has run the
// behavior is the same.
//
// const first = await executor.run(async () => {
// await sleep(1000)
// throw new Error()
// })
//
// The task call back receives an AbortSignal as a parameter. The abort
// event is emitted when another task is run.
export function create(): MutexExecutor {
return new MutexExecutor();
}
// A worker that asynchronously process one item at a time and provides
// the result as an event stream.
//
// import * as mutexExecutor from "ui/src/mutexExecutor"
// const worker = mutexExecutor.createWorker(async (value) => {
// await sleep(1000)
// return value
// })
//
// const firstPromise = worker.output.firstToPromise()
// worker.push("first)
// assert.equal(await firstPromise, "first")
//
// When an item is submitted to the worker while the previous items is
// still being processed, the result of the first item will not be
// emitted to `worker.output`. Instead, only the last item will be
// emitted.
export function createWorker<In, Out>(
fn: (x: In, abortSignal: AbortSignal) => Promise<Out>,
): MutexWorker<In, Out> {
return new MutexWorker(fn);
}
class MutexExecutor {
private runningTaskId = 0;
private abortController: AbortController | null = null;
public async run<T>(
f: (abortSignal: AbortSignal) => Promise<T>,
): Promise<T | undefined> {
this.runningTaskId += 1;
const taskId = this.runningTaskId;
if (this.abortController) {
this.abortController.abort();
}
this.abortController = new AbortController();
return f(this.abortController.signal).then(
data => {
if (this.runningTaskId === taskId) {
return data;
} else {
return undefined;
}
},
err => {
if (this.runningTaskId === taskId) {
throw err;
} else {
return undefined;
}
},
);
}
}
class MutexWorker<In, Out> {
private outputBus = new Bacon.Bus<Out>();
private executor = new MutexExecutor();
public output: Bacon.EventStream<Out>;
public constructor(
private fn: (x: In, abortSignal: AbortSignal) => Promise<Out>,
) {
this.output = this.outputBus.toEventStream();
}
public async submit(x: In): Promise<void> {
const output = await this.executor.run(abort => this.fn(x, abort));
if (output !== undefined) {
this.outputBus.push(output);
}
}
}
+150
View File
@@ -0,0 +1,150 @@
import type { LoadedRoute, Route } from "@app/lib/router/definitions";
import { get, writable } from "svelte/store";
import * as mutexExecutor from "@app/lib/mutexExecutor";
import * as utils from "@app/lib/utils";
import { loadRoute } from "@app/lib/router/definitions";
export { type Route };
const InitialStore = { resource: "booting" as const };
export const isLoading = writable<boolean>(true);
export const activeRouteStore = writable<LoadedRoute>(InitialStore);
export const activeUnloadedRouteStore = writable<Route>(InitialStore);
let currentUrl: URL | undefined;
export async function loadFromLocation(): Promise<void> {
await navigateToUrl("replace", new URL(window.location.href));
}
async function navigateToUrl(
action: "push" | "replace",
url: URL,
): Promise<void> {
const { pathname, hash } = url;
if (url.origin !== window.origin) {
throw new Error("Cannot navigate to other origin");
}
if (
currentUrl &&
currentUrl.pathname === pathname &&
currentUrl.search === url.search
) {
return;
}
const relativeUrl = pathname + url.search + (hash || "");
url = new URL(relativeUrl, window.origin);
const route = urlToRoute(url);
if (route) {
await navigate(action, route);
} else {
await navigate(action, {
// On 404 we redirect to the Home page, shouldn't happen.
resource: "home",
});
}
}
window.addEventListener("popstate", () => loadFromLocation());
const loadExecutor = mutexExecutor.create();
async function navigate(
action: "push" | "replace",
newRoute: Route,
): Promise<void> {
isLoading.set(true);
const path = routeToPath(newRoute);
if (action === "push") {
window.history.pushState(newRoute, "", path);
} else if (action === "replace") {
window.history.replaceState(newRoute, "");
}
currentUrl = new URL(window.location.href);
const currentLoadedRoute = get(activeRouteStore);
const loadedRoute = await loadExecutor.run(async () => {
return loadRoute(newRoute, currentLoadedRoute);
});
// Only let the last request through.
if (loadedRoute === undefined) {
return;
}
setTitle(loadedRoute);
activeRouteStore.set(loadedRoute);
activeUnloadedRouteStore.set(newRoute);
isLoading.set(false);
}
function setTitle(loadedRoute: LoadedRoute) {
const title: string[] = [];
if (loadedRoute.resource === "booting") {
title.push("Radicle");
} else if (loadedRoute.resource === "home") {
title.push("Home");
title.push("Radicle");
} else if (loadedRoute.resource === "authenticationError") {
title.push("Authentication Error");
title.push("Radicle");
} else if (loadedRoute.resource === "designSystem") {
title.push("Design System");
title.push("Radicle");
} else {
utils.unreachable(loadedRoute);
}
document.title = title.join(" · ");
}
export async function push(newRoute: Route): Promise<void> {
await navigate("push", newRoute);
}
export async function replace(newRoute: Route): Promise<void> {
await navigate("replace", newRoute);
}
function urlToRoute(url: URL): Route | null {
const segments = url.pathname.substring(1).split("/");
const resource = segments.shift();
switch (resource) {
case "": {
return { resource: "home" };
}
case "authenticationError": {
return { resource: "authenticationError", params: { error: "" } };
}
case "designSystem": {
return { resource: "designSystem" };
}
default: {
return null;
}
}
}
export function routeToPath(route: Route): string {
if (route.resource === "home") {
return "/";
} else if (route.resource === "authenticationError") {
return "/authenticationError";
} else if (route.resource === "designSystem") {
return "/designSystem";
} else if (route.resource === "booting") {
return "";
} else {
return utils.unreachable(route);
}
}
+38
View File
@@ -0,0 +1,38 @@
interface BootingRoute {
resource: "booting";
}
interface AuthenticationErrorRoute {
resource: "authenticationError";
params: {
error: string;
hint?: string;
};
}
interface HomeRoute {
resource: "home";
}
interface DesignSystemRoute {
resource: "designSystem";
}
export type Route =
| BootingRoute
| DesignSystemRoute
| HomeRoute
| AuthenticationErrorRoute;
export type LoadedRoute =
| BootingRoute
| DesignSystemRoute
| HomeRoute
| AuthenticationErrorRoute;
export async function loadRoute(
route: Route,
_previousLoaded: LoadedRoute,
): Promise<LoadedRoute> {
return route;
}
+36
View File
@@ -0,0 +1,36 @@
<script lang="ts">
import Icon from "@app/components/Icon.svelte";
export let error: string;
export let hint: string | undefined = undefined;
</script>
<style>
main {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100%;
width: 100%;
row-gap: 0.5rem;
}
/* This tag comes from the backend. */
:global(code) {
font-family: var(--font-family-monospace);
font-size: var(--font-size-small);
background-color: var(--color-fill-ghost);
padding: 0.125rem 0.25rem;
}
</style>
<main>
<Icon name="warning" size="32" />
<div class="txt-medium txt-semibold">
{error}
</div>
{#if hint}
<div class="txt-small">{@html hint}</div>
{/if}
</main>
+6 -30
View File
@@ -1,42 +1,18 @@
<script lang="ts">
import Border from "@app/components/Border.svelte";
import Button from "@app/components/Button.svelte";
import Fill from "@app/components/Fill.svelte";
import Header from "@app/components/Header.svelte";
import Icon from "@app/components/Icon.svelte";
let theme = "dark";
$: document.documentElement.setAttribute("data-theme", theme);
import Link from "@app/components/Link.svelte";
</script>
<Header currentPage="Design System" />
<div style="display: flex; gap: 1rem;">
<div style="display: flex; gap: 1rem;">
<Border variant="secondary">
<Fill
stylePadding="0 0.5rem"
variant={theme === "dark" ? "secondary" : "transparent"}
on:click={() => {
theme = "dark";
}}>
<Icon name="seedling" />
Dark
</Fill>
<Fill
stylePadding="0 0.5rem"
variant={theme === "light" ? "secondary" : "transparent"}
on:click={() => {
theme = "light";
}}>
<Icon name="seedling" />
Light
</Fill>
</Border>
</div>
<div style="display: flex; gap: 1rem;">
<Button variant="primary"><Icon name="seedling" />Press me</Button>
<Button variant="secondary"><Icon name="seedling" /> Press me</Button>
<Button variant="ghost"><Icon name="seedling" /> Press me</Button>
</div>
</div>
👉 <Link route={{ resource: "home" }}>Home</Link>
+8
View File
@@ -0,0 +1,8 @@
<script lang="ts">
import Header from "@app/components/Header.svelte";
import Link from "@app/components/Link.svelte";
</script>
<Header currentPage="Repositories" />
👉 <Link route={{ resource: "designSystem" }}>Design System</Link>
-47
View File
@@ -1,47 +0,0 @@
<script lang="ts">
import { invoke } from "@tauri-apps/api/core";
import { onMount } from "svelte";
import Repos from "@app/views/Repos.svelte";
import Icon from "@app/components/Icon.svelte";
let loading = true;
let error: { err: string; hint?: string } | undefined = undefined;
onMount(async () => {
try {
await invoke("authenticate");
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) {
error = e;
} finally {
loading = false;
}
});
</script>
<style>
main {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100%;
width: 100%;
row-gap: 0.5rem;
}
</style>
{#if error}
<main>
<Icon name="warning" size="32" />
<div class="txt-medium txt-semibold">
{error.err}
</div>
{#if error.hint}
<div class="txt-small">{@html error.hint}</div>
{/if}
</main>
{:else if !loading}
<Repos />
{/if}