pds dash for shimaenaga.veryroundbird.house (based off of pds.witchcraft.systems)

add files from witchcraft.systems pds frontpage + edits

+155
.gitignore
··· 1 + # Logs 2 + logs 3 + *.log 4 + npm-debug.log* 5 + yarn-debug.log* 6 + yarn-error.log* 7 + pnpm-debug.log* 8 + lerna-debug.log* 9 + 10 + node_modules 11 + dist 12 + dist-ssr 13 + *.local 14 + 15 + # Editor directories and files 16 + .vscode/* 17 + !.vscode/extensions.json 18 + .idea 19 + .DS_Store 20 + *.suo 21 + *.ntvs* 22 + *.njsproj 23 + *.sln 24 + *.sw? 25 + 26 + # Diagnostic reports (https://nodejs.org/api/report.html) 27 + report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 28 + 29 + # Runtime data 30 + pids 31 + *.pid 32 + *.seed 33 + *.pid.lock 34 + 35 + # Directory for instrumented libs generated by jscoverage/JSCover 36 + lib-cov 37 + 38 + # Coverage directory used by tools like istanbul 39 + coverage 40 + *.lcov 41 + 42 + # nyc test coverage 43 + .nyc_output 44 + 45 + # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 46 + .grunt 47 + 48 + # Bower dependency directory (https://bower.io/) 49 + bower_components 50 + 51 + # node-waf configuration 52 + .lock-wscript 53 + 54 + # Compiled binary addons (https://nodejs.org/api/addons.html) 55 + build/Release 56 + 57 + # Dependency directories 58 + node_modules/ 59 + jspm_packages/ 60 + 61 + # Snowpack dependency directory (https://snowpack.dev/) 62 + web_modules/ 63 + 64 + # TypeScript cache 65 + *.tsbuildinfo 66 + 67 + # Optional npm cache directory 68 + .npm 69 + 70 + # Optional eslint cache 71 + .eslintcache 72 + 73 + # Optional stylelint cache 74 + .stylelintcache 75 + 76 + # Microbundle cache 77 + .rpt2_cache/ 78 + .rts2_cache_cjs/ 79 + .rts2_cache_es/ 80 + .rts2_cache_umd/ 81 + 82 + # Optional REPL history 83 + .node_repl_history 84 + 85 + # Output of 'npm pack' 86 + *.tgz 87 + 88 + # Yarn Integrity file 89 + .yarn-integrity 90 + 91 + # dotenv environment variable files 92 + .env 93 + .env.development.local 94 + .env.test.local 95 + .env.production.local 96 + .env.local 97 + 98 + # parcel-bundler cache (https://parceljs.org/) 99 + .cache 100 + .parcel-cache 101 + 102 + # Next.js build output 103 + .next 104 + out 105 + 106 + # Nuxt.js build / generate output 107 + .nuxt 108 + dist 109 + 110 + # Gatsby files 111 + .cache/ 112 + # Comment in the public line in if your project uses Gatsby and not Next.js 113 + # https://nextjs.org/blog/next-9-1#public-directory-support 114 + # public 115 + 116 + # vuepress build output 117 + .vuepress/dist 118 + 119 + # vuepress v2.x temp and cache directory 120 + .temp 121 + .cache 122 + 123 + # vitepress build output 124 + **/.vitepress/dist 125 + 126 + # vitepress cache directory 127 + **/.vitepress/cache 128 + 129 + # Docusaurus cache and generated files 130 + .docusaurus 131 + 132 + # Serverless directories 133 + .serverless/ 134 + 135 + # FuseBox cache 136 + .fusebox/ 137 + 138 + # DynamoDB Local files 139 + .dynamodb/ 140 + 141 + # TernJS port file 142 + .tern-port 143 + 144 + # Stores VSCode versions used for testing VSCode extensions 145 + .vscode-test 146 + 147 + # yarn v2 148 + .yarn/cache 149 + .yarn/unplugged 150 + .yarn/build-state.yml 151 + .yarn/install-state.gz 152 + .pnp.* 153 + 154 + # Config files 155 + config.ts
+21
LICENSE
··· 1 + # MIT License 2 + 3 + Copyright (c) 2025 Witchcraft Systems 4 + 5 + Permission is hereby granted, free of charge, to any person obtaining a copy 6 + of this software and associated documentation files (the "Software"), to deal 7 + in the Software without restriction, including without limitation the rights 8 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 + copies of the Software, and to permit persons to whom the Software is 10 + furnished to do so, subject to the following conditions: 11 + 12 + The above copyright notice and this permission notice shall be included in all 13 + copies or substantial portions of the Software. 14 + 15 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 + SOFTWARE.
+59
README.md
··· 1 + # pds-dash 2 + 3 + a frontend dashboard with stats for your ATProto PDS. 4 + 5 + ## setup 6 + 7 + ### prerequisites 8 + 9 + - [deno](https://deno.com/manual/getting_started/installation) 10 + 11 + ### installing 12 + 13 + clone the repo, copy `config.ts.example` to `config.ts` and edit it to your liking. 14 + 15 + then, install dependencies using deno: 16 + 17 + ```sh 18 + deno install 19 + ``` 20 + 21 + ### development server 22 + 23 + local develompent server with hot reloading: 24 + 25 + ```sh 26 + deno task dev 27 + ``` 28 + 29 + ### building 30 + 31 + to build the optimized bundle run: 32 + 33 + ```sh 34 + deno task build 35 + ``` 36 + 37 + the output will be in the `dist/` directory. 38 + 39 + ## deploying 40 + 41 + we use our own CI/CD workflow at [`.forgejo/workflows/deploy.yaml`](.forgejo/workflows/deploy.yaml), but it boils down to building the project bundle and deploying it to a web server. it'll probably make more sense to host it on the same domain as your PDS, but it doesn't affect anything if you host it somewhere else. 42 + 43 + ## configuring 44 + 45 + [`config.ts`](config.ts) is the main configuration file, you can find more information in the file itself. 46 + 47 + ## theming 48 + 49 + themes are located in the `themes/` directory, you can create your own theme by copying one of the existing themes and modifying it to your liking. 50 + 51 + currently, the name of the theme is determined by the directory name, and the theme itself is defined in `theme.css` inside that directory. 52 + 53 + you can switch themes by changing the `theme` property in `config.ts`. 54 + 55 + the favicon is located at [`public/favicon.ico`](public/favicon.ico) 56 + 57 + ## license 58 + 59 + MIT
+223
bun.lock
··· 1 + { 2 + "lockfileVersion": 1, 3 + "workspaces": { 4 + "": { 5 + "name": "web", 6 + "dependencies": { 7 + "@atcute/bluesky": "^2.0.2", 8 + "@atcute/client": "^3.0.1", 9 + "@atcute/identity-resolver": "^0.1.2", 10 + "moment": "^2.30.1", 11 + "mutex-ts": "^1.2.1", 12 + "svelte-infinite-loading": "^1.4.0", 13 + }, 14 + "devDependencies": { 15 + "@sveltejs/vite-plugin-svelte": "^5.0.3", 16 + "@tsconfig/svelte": "^5.0.4", 17 + "svelte": "^5.23.1", 18 + "svelte-check": "^4.1.5", 19 + "typescript": "~5.7.2", 20 + "vite": "^6.3.1", 21 + }, 22 + }, 23 + }, 24 + "packages": { 25 + "@atcute/bluesky": ["@atcute/bluesky@2.1.1", "", { "peerDependencies": { "@atcute/client": "^3.0.0" } }, "sha512-wEZfFW58J6yC1SqHcVJOn4qbHENTTzjeCEWthRT5HvKovADLqk54HSMSAuXDMBUbintSTBr0khQNZQ3ZdgzDdQ=="], 26 + 27 + "@atcute/client": ["@atcute/client@3.1.0", "", {}, "sha512-+rQPsHXSf0DUm8XoHoaH7Y2E8tIpbsW84djyPj7dqAyrFIjvGuJ1X1DvMufwbTIcmLerdy+dzl34iZcz/h3Vhg=="], 28 + 29 + "@atcute/identity": ["@atcute/identity@0.1.3", "", { "dependencies": { "@badrap/valita": "^0.4.2" } }, "sha512-ndlD8nypHt8G00wixbozKdSNL0O8HTzBjFGEXeAcBUCXSZPBjRWbqtgyJxhgUWnr7swgxgw1mSbZwRB5b7xCiQ=="], 30 + 31 + "@atcute/identity-resolver": ["@atcute/identity-resolver@0.1.2", "", { "dependencies": { "@atcute/util-fetch": "^1.0.0", "@badrap/valita": "^0.4.2" }, "peerDependencies": { "@atcute/identity": "^0.1.0" } }, "sha512-fP2VbHD04kVcCdNi/Kszo6jFzqM7Pg3p33oGhfp2zVkwFKaVBlwCaFRWEga/Xvu/IDLwNdASGWnLqoA34SFeSg=="], 32 + 33 + "@atcute/util-fetch": ["@atcute/util-fetch@1.0.1", "", { "dependencies": { "@badrap/valita": "^0.4.2" } }, "sha512-Clc0E/5ufyGBVfYBUwWNlHONlZCoblSr4Ho50l1LhmRPGB1Wu/AQ9Sz+rsBg7fdaW/auve8ulmwhRhnX2cGRow=="], 34 + 35 + "@badrap/valita": ["@badrap/valita@0.4.6", "", {}, "sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg=="], 36 + 37 + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.9", "", { "os": "aix", "cpu": "ppc64" }, "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA=="], 38 + 39 + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.9", "", { "os": "android", "cpu": "arm" }, "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ=="], 40 + 41 + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.9", "", { "os": "android", "cpu": "arm64" }, "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg=="], 42 + 43 + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.9", "", { "os": "android", "cpu": "x64" }, "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw=="], 44 + 45 + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg=="], 46 + 47 + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ=="], 48 + 49 + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.9", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q=="], 50 + 51 + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.9", "", { "os": "freebsd", "cpu": "x64" }, "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg=="], 52 + 53 + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.9", "", { "os": "linux", "cpu": "arm" }, "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw=="], 54 + 55 + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw=="], 56 + 57 + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.9", "", { "os": "linux", "cpu": "ia32" }, "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A=="], 58 + 59 + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.9", "", { "os": "linux", "cpu": "none" }, "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ=="], 60 + 61 + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.9", "", { "os": "linux", "cpu": "none" }, "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA=="], 62 + 63 + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.9", "", { "os": "linux", "cpu": "ppc64" }, "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w=="], 64 + 65 + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.9", "", { "os": "linux", "cpu": "none" }, "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg=="], 66 + 67 + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.9", "", { "os": "linux", "cpu": "s390x" }, "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA=="], 68 + 69 + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.9", "", { "os": "linux", "cpu": "x64" }, "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg=="], 70 + 71 + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.9", "", { "os": "none", "cpu": "arm64" }, "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q=="], 72 + 73 + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.9", "", { "os": "none", "cpu": "x64" }, "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g=="], 74 + 75 + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.9", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ=="], 76 + 77 + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.9", "", { "os": "openbsd", "cpu": "x64" }, "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA=="], 78 + 79 + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.9", "", { "os": "none", "cpu": "arm64" }, "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg=="], 80 + 81 + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.9", "", { "os": "sunos", "cpu": "x64" }, "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw=="], 82 + 83 + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.9", "", { "os": "win32", "cpu": "arm64" }, "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ=="], 84 + 85 + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.9", "", { "os": "win32", "cpu": "ia32" }, "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww=="], 86 + 87 + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.9", "", { "os": "win32", "cpu": "x64" }, "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ=="], 88 + 89 + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], 90 + 91 + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], 92 + 93 + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], 94 + 95 + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], 96 + 97 + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], 98 + 99 + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.50.1", "", { "os": "android", "cpu": "arm" }, "sha512-HJXwzoZN4eYTdD8bVV22DN8gsPCAj3V20NHKOs8ezfXanGpmVPR7kalUHd+Y31IJp9stdB87VKPFbsGY3H/2ag=="], 100 + 101 + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.50.1", "", { "os": "android", "cpu": "arm64" }, "sha512-PZlsJVcjHfcH53mOImyt3bc97Ep3FJDXRpk9sMdGX0qgLmY0EIWxCag6EigerGhLVuL8lDVYNnSo8qnTElO4xw=="], 102 + 103 + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.50.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-xc6i2AuWh++oGi4ylOFPmzJOEeAa2lJeGUGb4MudOtgfyyjr4UPNK+eEWTPLvmPJIY/pgw6ssFIox23SyrkkJw=="], 104 + 105 + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.50.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-2ofU89lEpDYhdLAbRdeyz/kX3Y2lpYc6ShRnDjY35bZhd2ipuDMDi6ZTQ9NIag94K28nFMofdnKeHR7BT0CATw=="], 106 + 107 + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.50.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-wOsE6H2u6PxsHY/BeFHA4VGQN3KUJFZp7QJBmDYI983fgxq5Th8FDkVuERb2l9vDMs1D5XhOrhBrnqcEY6l8ZA=="], 108 + 109 + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.50.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-A/xeqaHTlKbQggxCqispFAcNjycpUEHP52mwMQZUNqDUJFFYtPHCXS1VAG29uMlDzIVr+i00tSFWFLivMcoIBQ=="], 110 + 111 + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.50.1", "", { "os": "linux", "cpu": "arm" }, "sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg=="], 112 + 113 + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.50.1", "", { "os": "linux", "cpu": "arm" }, "sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw=="], 114 + 115 + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.50.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw=="], 116 + 117 + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.50.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w=="], 118 + 119 + "@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.50.1", "", { "os": "linux", "cpu": "none" }, "sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q=="], 120 + 121 + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.50.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q=="], 122 + 123 + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.50.1", "", { "os": "linux", "cpu": "none" }, "sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ=="], 124 + 125 + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.50.1", "", { "os": "linux", "cpu": "none" }, "sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg=="], 126 + 127 + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.50.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg=="], 128 + 129 + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.50.1", "", { "os": "linux", "cpu": "x64" }, "sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA=="], 130 + 131 + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.50.1", "", { "os": "linux", "cpu": "x64" }, "sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg=="], 132 + 133 + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.50.1", "", { "os": "none", "cpu": "arm64" }, "sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA=="], 134 + 135 + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.50.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-hpZB/TImk2FlAFAIsoElM3tLzq57uxnGYwplg6WDyAxbYczSi8O2eQ+H2Lx74504rwKtZ3N2g4bCUkiamzS6TQ=="], 136 + 137 + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.50.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-SXjv8JlbzKM0fTJidX4eVsH+Wmnp0/WcD8gJxIZyR6Gay5Qcsmdbi9zVtnbkGPG8v2vMR1AD06lGWy5FLMcG7A=="], 138 + 139 + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.50.1", "", { "os": "win32", "cpu": "x64" }, "sha512-StxAO/8ts62KZVRAm4JZYq9+NqNsV7RvimNK+YM7ry//zebEH6meuugqW/P5OFUCjyQgui+9fUxT6d5NShvMvA=="], 140 + 141 + "@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.5", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ=="], 142 + 143 + "@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@5.1.1", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", "debug": "^4.4.1", "deepmerge": "^4.3.1", "kleur": "^4.1.5", "magic-string": "^0.30.17", "vitefu": "^1.0.6" }, "peerDependencies": { "svelte": "^5.0.0", "vite": "^6.0.0" } }, "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ=="], 144 + 145 + "@sveltejs/vite-plugin-svelte-inspector": ["@sveltejs/vite-plugin-svelte-inspector@4.0.1", "", { "dependencies": { "debug": "^4.3.7" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^5.0.0", "svelte": "^5.0.0", "vite": "^6.0.0" } }, "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw=="], 146 + 147 + "@tsconfig/svelte": ["@tsconfig/svelte@5.0.5", "", {}, "sha512-48fAnUjKye38FvMiNOj0J9I/4XlQQiZlpe9xaNPfe8vy2Y1hFBt8g1yqf2EGjVvHavo4jf2lC+TQyENCr4BJBQ=="], 148 + 149 + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], 150 + 151 + "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], 152 + 153 + "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], 154 + 155 + "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], 156 + 157 + "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], 158 + 159 + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], 160 + 161 + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], 162 + 163 + "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], 164 + 165 + "esbuild": ["esbuild@0.25.9", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.9", "@esbuild/android-arm": "0.25.9", "@esbuild/android-arm64": "0.25.9", "@esbuild/android-x64": "0.25.9", "@esbuild/darwin-arm64": "0.25.9", "@esbuild/darwin-x64": "0.25.9", "@esbuild/freebsd-arm64": "0.25.9", "@esbuild/freebsd-x64": "0.25.9", "@esbuild/linux-arm": "0.25.9", "@esbuild/linux-arm64": "0.25.9", "@esbuild/linux-ia32": "0.25.9", "@esbuild/linux-loong64": "0.25.9", "@esbuild/linux-mips64el": "0.25.9", "@esbuild/linux-ppc64": "0.25.9", "@esbuild/linux-riscv64": "0.25.9", "@esbuild/linux-s390x": "0.25.9", "@esbuild/linux-x64": "0.25.9", "@esbuild/netbsd-arm64": "0.25.9", "@esbuild/netbsd-x64": "0.25.9", "@esbuild/openbsd-arm64": "0.25.9", "@esbuild/openbsd-x64": "0.25.9", "@esbuild/openharmony-arm64": "0.25.9", "@esbuild/sunos-x64": "0.25.9", "@esbuild/win32-arm64": "0.25.9", "@esbuild/win32-ia32": "0.25.9", "@esbuild/win32-x64": "0.25.9" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g=="], 166 + 167 + "esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="], 168 + 169 + "esrap": ["esrap@2.1.0", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, "sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA=="], 170 + 171 + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], 172 + 173 + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], 174 + 175 + "is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="], 176 + 177 + "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], 178 + 179 + "locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="], 180 + 181 + "magic-string": ["magic-string@0.30.19", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw=="], 182 + 183 + "moment": ["moment@2.30.1", "", {}, "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="], 184 + 185 + "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], 186 + 187 + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], 188 + 189 + "mutex-ts": ["mutex-ts@1.2.1", "", {}, "sha512-OkcXgf0viuCgYdnm48kiNQ9PzC5OzISQ261svHr/Ybc2vBYC/5xfLXn44hQ+dYRX74v7MCSqV/LKPEbpYdDybw=="], 190 + 191 + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], 192 + 193 + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], 194 + 195 + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], 196 + 197 + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], 198 + 199 + "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], 200 + 201 + "rollup": ["rollup@4.50.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.50.1", "@rollup/rollup-android-arm64": "4.50.1", "@rollup/rollup-darwin-arm64": "4.50.1", "@rollup/rollup-darwin-x64": "4.50.1", "@rollup/rollup-freebsd-arm64": "4.50.1", "@rollup/rollup-freebsd-x64": "4.50.1", "@rollup/rollup-linux-arm-gnueabihf": "4.50.1", "@rollup/rollup-linux-arm-musleabihf": "4.50.1", "@rollup/rollup-linux-arm64-gnu": "4.50.1", "@rollup/rollup-linux-arm64-musl": "4.50.1", "@rollup/rollup-linux-loongarch64-gnu": "4.50.1", "@rollup/rollup-linux-ppc64-gnu": "4.50.1", "@rollup/rollup-linux-riscv64-gnu": "4.50.1", "@rollup/rollup-linux-riscv64-musl": "4.50.1", "@rollup/rollup-linux-s390x-gnu": "4.50.1", "@rollup/rollup-linux-x64-gnu": "4.50.1", "@rollup/rollup-linux-x64-musl": "4.50.1", "@rollup/rollup-openharmony-arm64": "4.50.1", "@rollup/rollup-win32-arm64-msvc": "4.50.1", "@rollup/rollup-win32-ia32-msvc": "4.50.1", "@rollup/rollup-win32-x64-msvc": "4.50.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA=="], 202 + 203 + "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], 204 + 205 + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], 206 + 207 + "svelte": ["svelte@5.38.10", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "esm-env": "^1.2.1", "esrap": "^2.1.0", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-UY+OhrWK7WI22bCZ00P/M3HtyWgwJPi9IxSRkoAE2MeAy6kl7ZlZWJZ8RaB+X4KD/G+wjis+cGVnVYaoqbzBqg=="], 208 + 209 + "svelte-check": ["svelte-check@4.3.1", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-lkh8gff5gpHLjxIV+IaApMxQhTGnir2pNUAqcNgeKkvK5bT/30Ey/nzBxNLDlkztCH4dP7PixkMt9SWEKFPBWg=="], 210 + 211 + "svelte-infinite-loading": ["svelte-infinite-loading@1.4.0", "", {}, "sha512-Jo+f/yr/HmZQuIiiKKzAHVFXdAUWHW2RBbrcQTil8JVk1sCm/riy7KTJVzjBgQvHasrFQYKF84zvtc9/Y4lFYg=="], 212 + 213 + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], 214 + 215 + "typescript": ["typescript@5.7.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw=="], 216 + 217 + "vite": ["vite@6.3.6", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA=="], 218 + 219 + "vitefu": ["vitefu@1.1.1", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ=="], 220 + 221 + "zimmerframe": ["zimmerframe@1.1.4", "", {}, "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ=="], 222 + } 223 + }
+605
deno.lock
··· 1 + { 2 + "version": "5", 3 + "specifiers": { 4 + "npm:@atcute/bluesky@^2.0.2": "2.0.2_@atcute+client@3.0.1", 5 + "npm:@atcute/client@^3.0.1": "3.0.1", 6 + "npm:@atcute/identity-resolver@~0.1.2": "0.1.2_@atcute+identity@0.1.3", 7 + "npm:@sveltejs/vite-plugin-svelte@^5.0.3": "5.0.3_svelte@5.28.1__acorn@8.14.1_vite@6.3.2__picomatch@4.0.2", 8 + "npm:@tsconfig/svelte@^5.0.4": "5.0.4", 9 + "npm:moment@^2.30.1": "2.30.1", 10 + "npm:mutex-ts@^1.2.1": "1.2.1", 11 + "npm:svelte-check@^4.1.5": "4.1.6_svelte@5.28.1__acorn@8.14.1_typescript@5.7.3", 12 + "npm:svelte-infinite-loading@^1.4.0": "1.4.0", 13 + "npm:svelte@^5.23.1": "5.28.1_acorn@8.14.1", 14 + "npm:typescript@~5.7.2": "5.7.3", 15 + "npm:vite@^6.3.1": "6.3.2_picomatch@4.0.2" 16 + }, 17 + "npm": { 18 + "@ampproject/remapping@2.3.0": { 19 + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", 20 + "dependencies": [ 21 + "@jridgewell/gen-mapping", 22 + "@jridgewell/trace-mapping" 23 + ] 24 + }, 25 + "@atcute/bluesky@2.0.2_@atcute+client@3.0.1": { 26 + "integrity": "sha512-xU+9Rp8bzc9AOnWSc11M1urRppDt3BiWR7v2QrLt3Qoysa5jvL8j2p2w4iRT8vLByz8Q+Xgk5Kz4zWVx1zCiug==", 27 + "dependencies": [ 28 + "@atcute/client" 29 + ] 30 + }, 31 + "@atcute/client@3.0.1": { 32 + "integrity": "sha512-j51SuQYQj5jeKrx1DCXx+Q3fpVvO0JYGnKnJAdDSlesSLjPXjvnx1abC+hkuro58KRHHJvRA6P1MC0pmJsWfcg==" 33 + }, 34 + "@atcute/identity-resolver@0.1.2_@atcute+identity@0.1.3": { 35 + "integrity": "sha512-fP2VbHD04kVcCdNi/Kszo6jFzqM7Pg3p33oGhfp2zVkwFKaVBlwCaFRWEga/Xvu/IDLwNdASGWnLqoA34SFeSg==", 36 + "dependencies": [ 37 + "@atcute/identity", 38 + "@atcute/util-fetch", 39 + "@badrap/valita" 40 + ] 41 + }, 42 + "@atcute/identity@0.1.3": { 43 + "integrity": "sha512-ndlD8nypHt8G00wixbozKdSNL0O8HTzBjFGEXeAcBUCXSZPBjRWbqtgyJxhgUWnr7swgxgw1mSbZwRB5b7xCiQ==", 44 + "dependencies": [ 45 + "@badrap/valita" 46 + ] 47 + }, 48 + "@atcute/util-fetch@1.0.1": { 49 + "integrity": "sha512-Clc0E/5ufyGBVfYBUwWNlHONlZCoblSr4Ho50l1LhmRPGB1Wu/AQ9Sz+rsBg7fdaW/auve8ulmwhRhnX2cGRow==", 50 + "dependencies": [ 51 + "@badrap/valita" 52 + ] 53 + }, 54 + "@badrap/valita@0.4.4": { 55 + "integrity": "sha512-GEhUCk9c4XbNxi+0YZHZsV4fYNd6HejfWuN4Ti4c02DauX+LyX5WY1Y3WfyZ8Pxxl0zqhs+MLtW98cMh86vv6g==" 56 + }, 57 + "@esbuild/aix-ppc64@0.25.2": { 58 + "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", 59 + "os": ["aix"], 60 + "cpu": ["ppc64"] 61 + }, 62 + "@esbuild/android-arm64@0.25.2": { 63 + "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", 64 + "os": ["android"], 65 + "cpu": ["arm64"] 66 + }, 67 + "@esbuild/android-arm@0.25.2": { 68 + "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", 69 + "os": ["android"], 70 + "cpu": ["arm"] 71 + }, 72 + "@esbuild/android-x64@0.25.2": { 73 + "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", 74 + "os": ["android"], 75 + "cpu": ["x64"] 76 + }, 77 + "@esbuild/darwin-arm64@0.25.2": { 78 + "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", 79 + "os": ["darwin"], 80 + "cpu": ["arm64"] 81 + }, 82 + "@esbuild/darwin-x64@0.25.2": { 83 + "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", 84 + "os": ["darwin"], 85 + "cpu": ["x64"] 86 + }, 87 + "@esbuild/freebsd-arm64@0.25.2": { 88 + "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", 89 + "os": ["freebsd"], 90 + "cpu": ["arm64"] 91 + }, 92 + "@esbuild/freebsd-x64@0.25.2": { 93 + "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", 94 + "os": ["freebsd"], 95 + "cpu": ["x64"] 96 + }, 97 + "@esbuild/linux-arm64@0.25.2": { 98 + "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", 99 + "os": ["linux"], 100 + "cpu": ["arm64"] 101 + }, 102 + "@esbuild/linux-arm@0.25.2": { 103 + "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", 104 + "os": ["linux"], 105 + "cpu": ["arm"] 106 + }, 107 + "@esbuild/linux-ia32@0.25.2": { 108 + "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", 109 + "os": ["linux"], 110 + "cpu": ["ia32"] 111 + }, 112 + "@esbuild/linux-loong64@0.25.2": { 113 + "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", 114 + "os": ["linux"], 115 + "cpu": ["loong64"] 116 + }, 117 + "@esbuild/linux-mips64el@0.25.2": { 118 + "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", 119 + "os": ["linux"], 120 + "cpu": ["mips64el"] 121 + }, 122 + "@esbuild/linux-ppc64@0.25.2": { 123 + "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", 124 + "os": ["linux"], 125 + "cpu": ["ppc64"] 126 + }, 127 + "@esbuild/linux-riscv64@0.25.2": { 128 + "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", 129 + "os": ["linux"], 130 + "cpu": ["riscv64"] 131 + }, 132 + "@esbuild/linux-s390x@0.25.2": { 133 + "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", 134 + "os": ["linux"], 135 + "cpu": ["s390x"] 136 + }, 137 + "@esbuild/linux-x64@0.25.2": { 138 + "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", 139 + "os": ["linux"], 140 + "cpu": ["x64"] 141 + }, 142 + "@esbuild/netbsd-arm64@0.25.2": { 143 + "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", 144 + "os": ["netbsd"], 145 + "cpu": ["arm64"] 146 + }, 147 + "@esbuild/netbsd-x64@0.25.2": { 148 + "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", 149 + "os": ["netbsd"], 150 + "cpu": ["x64"] 151 + }, 152 + "@esbuild/openbsd-arm64@0.25.2": { 153 + "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", 154 + "os": ["openbsd"], 155 + "cpu": ["arm64"] 156 + }, 157 + "@esbuild/openbsd-x64@0.25.2": { 158 + "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", 159 + "os": ["openbsd"], 160 + "cpu": ["x64"] 161 + }, 162 + "@esbuild/sunos-x64@0.25.2": { 163 + "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", 164 + "os": ["sunos"], 165 + "cpu": ["x64"] 166 + }, 167 + "@esbuild/win32-arm64@0.25.2": { 168 + "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", 169 + "os": ["win32"], 170 + "cpu": ["arm64"] 171 + }, 172 + "@esbuild/win32-ia32@0.25.2": { 173 + "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", 174 + "os": ["win32"], 175 + "cpu": ["ia32"] 176 + }, 177 + "@esbuild/win32-x64@0.25.2": { 178 + "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", 179 + "os": ["win32"], 180 + "cpu": ["x64"] 181 + }, 182 + "@jridgewell/gen-mapping@0.3.8": { 183 + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", 184 + "dependencies": [ 185 + "@jridgewell/set-array", 186 + "@jridgewell/sourcemap-codec", 187 + "@jridgewell/trace-mapping" 188 + ] 189 + }, 190 + "@jridgewell/resolve-uri@3.1.2": { 191 + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==" 192 + }, 193 + "@jridgewell/set-array@1.2.1": { 194 + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" 195 + }, 196 + "@jridgewell/sourcemap-codec@1.5.0": { 197 + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" 198 + }, 199 + "@jridgewell/trace-mapping@0.3.25": { 200 + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", 201 + "dependencies": [ 202 + "@jridgewell/resolve-uri", 203 + "@jridgewell/sourcemap-codec" 204 + ] 205 + }, 206 + "@rollup/rollup-android-arm-eabi@4.40.0": { 207 + "integrity": "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==", 208 + "os": ["android"], 209 + "cpu": ["arm"] 210 + }, 211 + "@rollup/rollup-android-arm64@4.40.0": { 212 + "integrity": "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==", 213 + "os": ["android"], 214 + "cpu": ["arm64"] 215 + }, 216 + "@rollup/rollup-darwin-arm64@4.40.0": { 217 + "integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==", 218 + "os": ["darwin"], 219 + "cpu": ["arm64"] 220 + }, 221 + "@rollup/rollup-darwin-x64@4.40.0": { 222 + "integrity": "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==", 223 + "os": ["darwin"], 224 + "cpu": ["x64"] 225 + }, 226 + "@rollup/rollup-freebsd-arm64@4.40.0": { 227 + "integrity": "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==", 228 + "os": ["freebsd"], 229 + "cpu": ["arm64"] 230 + }, 231 + "@rollup/rollup-freebsd-x64@4.40.0": { 232 + "integrity": "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==", 233 + "os": ["freebsd"], 234 + "cpu": ["x64"] 235 + }, 236 + "@rollup/rollup-linux-arm-gnueabihf@4.40.0": { 237 + "integrity": "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==", 238 + "os": ["linux"], 239 + "cpu": ["arm"] 240 + }, 241 + "@rollup/rollup-linux-arm-musleabihf@4.40.0": { 242 + "integrity": "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==", 243 + "os": ["linux"], 244 + "cpu": ["arm"] 245 + }, 246 + "@rollup/rollup-linux-arm64-gnu@4.40.0": { 247 + "integrity": "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==", 248 + "os": ["linux"], 249 + "cpu": ["arm64"] 250 + }, 251 + "@rollup/rollup-linux-arm64-musl@4.40.0": { 252 + "integrity": "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==", 253 + "os": ["linux"], 254 + "cpu": ["arm64"] 255 + }, 256 + "@rollup/rollup-linux-loongarch64-gnu@4.40.0": { 257 + "integrity": "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==", 258 + "os": ["linux"], 259 + "cpu": ["loong64"] 260 + }, 261 + "@rollup/rollup-linux-powerpc64le-gnu@4.40.0": { 262 + "integrity": "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==", 263 + "os": ["linux"], 264 + "cpu": ["ppc64"] 265 + }, 266 + "@rollup/rollup-linux-riscv64-gnu@4.40.0": { 267 + "integrity": "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==", 268 + "os": ["linux"], 269 + "cpu": ["riscv64"] 270 + }, 271 + "@rollup/rollup-linux-riscv64-musl@4.40.0": { 272 + "integrity": "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==", 273 + "os": ["linux"], 274 + "cpu": ["riscv64"] 275 + }, 276 + "@rollup/rollup-linux-s390x-gnu@4.40.0": { 277 + "integrity": "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==", 278 + "os": ["linux"], 279 + "cpu": ["s390x"] 280 + }, 281 + "@rollup/rollup-linux-x64-gnu@4.40.0": { 282 + "integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==", 283 + "os": ["linux"], 284 + "cpu": ["x64"] 285 + }, 286 + "@rollup/rollup-linux-x64-musl@4.40.0": { 287 + "integrity": "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==", 288 + "os": ["linux"], 289 + "cpu": ["x64"] 290 + }, 291 + "@rollup/rollup-win32-arm64-msvc@4.40.0": { 292 + "integrity": "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==", 293 + "os": ["win32"], 294 + "cpu": ["arm64"] 295 + }, 296 + "@rollup/rollup-win32-ia32-msvc@4.40.0": { 297 + "integrity": "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==", 298 + "os": ["win32"], 299 + "cpu": ["ia32"] 300 + }, 301 + "@rollup/rollup-win32-x64-msvc@4.40.0": { 302 + "integrity": "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==", 303 + "os": ["win32"], 304 + "cpu": ["x64"] 305 + }, 306 + "@sveltejs/acorn-typescript@1.0.5_acorn@8.14.1": { 307 + "integrity": "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==", 308 + "dependencies": [ 309 + "acorn" 310 + ] 311 + }, 312 + "@sveltejs/vite-plugin-svelte-inspector@4.0.1_@sveltejs+vite-plugin-svelte@5.0.3__svelte@5.28.1___acorn@8.14.1__vite@6.3.2___picomatch@4.0.2_svelte@5.28.1__acorn@8.14.1_vite@6.3.2__picomatch@4.0.2": { 313 + "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==", 314 + "dependencies": [ 315 + "@sveltejs/vite-plugin-svelte", 316 + "debug", 317 + "svelte", 318 + "vite" 319 + ] 320 + }, 321 + "@sveltejs/vite-plugin-svelte@5.0.3_svelte@5.28.1__acorn@8.14.1_vite@6.3.2__picomatch@4.0.2": { 322 + "integrity": "sha512-MCFS6CrQDu1yGwspm4qtli0e63vaPCehf6V7pIMP15AsWgMKrqDGCPFF/0kn4SP0ii4aySu4Pa62+fIRGFMjgw==", 323 + "dependencies": [ 324 + "@sveltejs/vite-plugin-svelte-inspector", 325 + "debug", 326 + "deepmerge", 327 + "kleur", 328 + "magic-string", 329 + "svelte", 330 + "vite", 331 + "vitefu" 332 + ] 333 + }, 334 + "@tsconfig/svelte@5.0.4": { 335 + "integrity": "sha512-BV9NplVgLmSi4mwKzD8BD/NQ8erOY/nUE/GpgWe2ckx+wIQF5RyRirn/QsSSCPeulVpc3RA/iJt6DpfTIZps0Q==" 336 + }, 337 + "@types/estree@1.0.7": { 338 + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==" 339 + }, 340 + "acorn@8.14.1": { 341 + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", 342 + "bin": true 343 + }, 344 + "aria-query@5.3.2": { 345 + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==" 346 + }, 347 + "axobject-query@4.1.0": { 348 + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==" 349 + }, 350 + "chokidar@4.0.3": { 351 + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", 352 + "dependencies": [ 353 + "readdirp" 354 + ] 355 + }, 356 + "clsx@2.1.1": { 357 + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==" 358 + }, 359 + "debug@4.4.0": { 360 + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", 361 + "dependencies": [ 362 + "ms" 363 + ] 364 + }, 365 + "deepmerge@4.3.1": { 366 + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==" 367 + }, 368 + "esbuild@0.25.2": { 369 + "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", 370 + "optionalDependencies": [ 371 + "@esbuild/aix-ppc64", 372 + "@esbuild/android-arm", 373 + "@esbuild/android-arm64", 374 + "@esbuild/android-x64", 375 + "@esbuild/darwin-arm64", 376 + "@esbuild/darwin-x64", 377 + "@esbuild/freebsd-arm64", 378 + "@esbuild/freebsd-x64", 379 + "@esbuild/linux-arm", 380 + "@esbuild/linux-arm64", 381 + "@esbuild/linux-ia32", 382 + "@esbuild/linux-loong64", 383 + "@esbuild/linux-mips64el", 384 + "@esbuild/linux-ppc64", 385 + "@esbuild/linux-riscv64", 386 + "@esbuild/linux-s390x", 387 + "@esbuild/linux-x64", 388 + "@esbuild/netbsd-arm64", 389 + "@esbuild/netbsd-x64", 390 + "@esbuild/openbsd-arm64", 391 + "@esbuild/openbsd-x64", 392 + "@esbuild/sunos-x64", 393 + "@esbuild/win32-arm64", 394 + "@esbuild/win32-ia32", 395 + "@esbuild/win32-x64" 396 + ], 397 + "scripts": true, 398 + "bin": true 399 + }, 400 + "esm-env@1.2.2": { 401 + "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==" 402 + }, 403 + "esrap@1.4.6": { 404 + "integrity": "sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw==", 405 + "dependencies": [ 406 + "@jridgewell/sourcemap-codec" 407 + ] 408 + }, 409 + "fdir@6.4.4_picomatch@4.0.2": { 410 + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", 411 + "dependencies": [ 412 + "picomatch" 413 + ], 414 + "optionalPeers": [ 415 + "picomatch" 416 + ] 417 + }, 418 + "fsevents@2.3.3": { 419 + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 420 + "os": ["darwin"], 421 + "scripts": true 422 + }, 423 + "is-reference@3.0.3": { 424 + "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", 425 + "dependencies": [ 426 + "@types/estree" 427 + ] 428 + }, 429 + "kleur@4.1.5": { 430 + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==" 431 + }, 432 + "locate-character@3.0.0": { 433 + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==" 434 + }, 435 + "magic-string@0.30.17": { 436 + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", 437 + "dependencies": [ 438 + "@jridgewell/sourcemap-codec" 439 + ] 440 + }, 441 + "moment@2.30.1": { 442 + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==" 443 + }, 444 + "mri@1.2.0": { 445 + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==" 446 + }, 447 + "ms@2.1.3": { 448 + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 449 + }, 450 + "mutex-ts@1.2.1": { 451 + "integrity": "sha512-OkcXgf0viuCgYdnm48kiNQ9PzC5OzISQ261svHr/Ybc2vBYC/5xfLXn44hQ+dYRX74v7MCSqV/LKPEbpYdDybw==" 452 + }, 453 + "nanoid@3.3.11": { 454 + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", 455 + "bin": true 456 + }, 457 + "picocolors@1.1.1": { 458 + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" 459 + }, 460 + "picomatch@4.0.2": { 461 + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==" 462 + }, 463 + "postcss@8.5.3": { 464 + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", 465 + "dependencies": [ 466 + "nanoid", 467 + "picocolors", 468 + "source-map-js" 469 + ] 470 + }, 471 + "readdirp@4.1.2": { 472 + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==" 473 + }, 474 + "rollup@4.40.0": { 475 + "integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==", 476 + "dependencies": [ 477 + "@types/estree" 478 + ], 479 + "optionalDependencies": [ 480 + "@rollup/rollup-android-arm-eabi", 481 + "@rollup/rollup-android-arm64", 482 + "@rollup/rollup-darwin-arm64", 483 + "@rollup/rollup-darwin-x64", 484 + "@rollup/rollup-freebsd-arm64", 485 + "@rollup/rollup-freebsd-x64", 486 + "@rollup/rollup-linux-arm-gnueabihf", 487 + "@rollup/rollup-linux-arm-musleabihf", 488 + "@rollup/rollup-linux-arm64-gnu", 489 + "@rollup/rollup-linux-arm64-musl", 490 + "@rollup/rollup-linux-loongarch64-gnu", 491 + "@rollup/rollup-linux-powerpc64le-gnu", 492 + "@rollup/rollup-linux-riscv64-gnu", 493 + "@rollup/rollup-linux-riscv64-musl", 494 + "@rollup/rollup-linux-s390x-gnu", 495 + "@rollup/rollup-linux-x64-gnu", 496 + "@rollup/rollup-linux-x64-musl", 497 + "@rollup/rollup-win32-arm64-msvc", 498 + "@rollup/rollup-win32-ia32-msvc", 499 + "@rollup/rollup-win32-x64-msvc", 500 + "fsevents" 501 + ], 502 + "bin": true 503 + }, 504 + "sade@1.8.1": { 505 + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", 506 + "dependencies": [ 507 + "mri" 508 + ] 509 + }, 510 + "source-map-js@1.2.1": { 511 + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==" 512 + }, 513 + "svelte-check@4.1.6_svelte@5.28.1__acorn@8.14.1_typescript@5.7.3": { 514 + "integrity": "sha512-P7w/6tdSfk3zEVvfsgrp3h3DFC75jCdZjTQvgGJtjPORs1n7/v2VMPIoty3PWv7jnfEm3x0G/p9wH4pecTb0Wg==", 515 + "dependencies": [ 516 + "@jridgewell/trace-mapping", 517 + "chokidar", 518 + "fdir", 519 + "picocolors", 520 + "sade", 521 + "svelte", 522 + "typescript" 523 + ], 524 + "bin": true 525 + }, 526 + "svelte-infinite-loading@1.4.0": { 527 + "integrity": "sha512-Jo+f/yr/HmZQuIiiKKzAHVFXdAUWHW2RBbrcQTil8JVk1sCm/riy7KTJVzjBgQvHasrFQYKF84zvtc9/Y4lFYg==" 528 + }, 529 + "svelte@5.28.1_acorn@8.14.1": { 530 + "integrity": "sha512-iOa9WmfNG95lSOSJdMhdjJ4Afok7IRAQYXpbnxhd5EINnXseG0GVa9j6WPght4eX78XfFez45Fi+uRglGKPV/Q==", 531 + "dependencies": [ 532 + "@ampproject/remapping", 533 + "@jridgewell/sourcemap-codec", 534 + "@sveltejs/acorn-typescript", 535 + "@types/estree", 536 + "acorn", 537 + "aria-query", 538 + "axobject-query", 539 + "clsx", 540 + "esm-env", 541 + "esrap", 542 + "is-reference", 543 + "locate-character", 544 + "magic-string", 545 + "zimmerframe" 546 + ] 547 + }, 548 + "tinyglobby@0.2.13_picomatch@4.0.2": { 549 + "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", 550 + "dependencies": [ 551 + "fdir", 552 + "picomatch" 553 + ] 554 + }, 555 + "typescript@5.7.3": { 556 + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", 557 + "bin": true 558 + }, 559 + "vite@6.3.2_picomatch@4.0.2": { 560 + "integrity": "sha512-ZSvGOXKGceizRQIZSz7TGJ0pS3QLlVY/9hwxVh17W3re67je1RKYzFHivZ/t0tubU78Vkyb9WnHPENSBCzbckg==", 561 + "dependencies": [ 562 + "esbuild", 563 + "fdir", 564 + "picomatch", 565 + "postcss", 566 + "rollup", 567 + "tinyglobby" 568 + ], 569 + "optionalDependencies": [ 570 + "fsevents" 571 + ], 572 + "bin": true 573 + }, 574 + "vitefu@1.0.6_vite@6.3.2__picomatch@4.0.2": { 575 + "integrity": "sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA==", 576 + "dependencies": [ 577 + "vite" 578 + ], 579 + "optionalPeers": [ 580 + "vite" 581 + ] 582 + }, 583 + "zimmerframe@1.1.2": { 584 + "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==" 585 + } 586 + }, 587 + "workspace": { 588 + "packageJson": { 589 + "dependencies": [ 590 + "npm:@atcute/bluesky@^2.0.2", 591 + "npm:@atcute/client@^3.0.1", 592 + "npm:@atcute/identity-resolver@~0.1.2", 593 + "npm:@sveltejs/vite-plugin-svelte@^5.0.3", 594 + "npm:@tsconfig/svelte@^5.0.4", 595 + "npm:moment@^2.30.1", 596 + "npm:mutex-ts@^1.2.1", 597 + "npm:svelte-check@^4.1.5", 598 + "npm:svelte-infinite-loading@^1.4.0", 599 + "npm:svelte@^5.23.1", 600 + "npm:typescript@~5.7.2", 601 + "npm:vite@^6.3.1" 602 + ] 603 + } 604 + } 605 + }
+12
index.html
··· 1 + <!DOCTYPE html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="UTF-8" /> 5 + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 + <title>shimaenaga pds @ veryroundbird.house</title> 7 + </head> 8 + <body> 9 + <div id="app"></div> 10 + <script type="module" src="/src/main.ts"></script> 11 + </body> 12 + </html>
+28
package.json
··· 1 + { 2 + "name": "web", 3 + "private": true, 4 + "version": "0.0.0", 5 + "type": "module", 6 + "scripts": { 7 + "dev": "vite", 8 + "build": "vite build", 9 + "preview": "vite preview", 10 + "check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json" 11 + }, 12 + "dependencies": { 13 + "@atcute/bluesky": "^2.0.2", 14 + "@atcute/client": "^3.0.1", 15 + "@atcute/identity-resolver": "^0.1.2", 16 + "moment": "^2.30.1", 17 + "mutex-ts": "^1.2.1", 18 + "svelte-infinite-loading": "^1.4.0" 19 + }, 20 + "devDependencies": { 21 + "@sveltejs/vite-plugin-svelte": "^5.0.3", 22 + "@tsconfig/svelte": "^5.0.4", 23 + "svelte": "^5.23.1", 24 + "svelte-check": "^4.1.5", 25 + "typescript": "~5.7.2", 26 + "vite": "^6.3.1" 27 + } 28 + }
public/favicon.ico

This is a binary file and will not be displayed.

public/fonts/Recursive_VF_1.085.woff2

This is a binary file and will not be displayed.

+104
src/App.svelte
··· 1 + <script lang="ts"> 2 + import PostComponent from "./lib/PostComponent.svelte"; 3 + import AccountComponent from "./lib/AccountComponent.svelte"; 4 + import InfiniteLoading from "svelte-infinite-loading"; 5 + import { getNextPosts, Post, getAllMetadataFromPds } from "./lib/pdsfetch"; 6 + import { Config } from "../config"; 7 + const accountsPromise = getAllMetadataFromPds(); 8 + import { onMount } from "svelte"; 9 + 10 + let posts: Post[] = []; 11 + 12 + let hue: number = 1; 13 + const cycleColors = async () => { 14 + while (true) { 15 + hue += 1; 16 + if (hue > 360) { 17 + hue = 0; 18 + } 19 + document.documentElement.style.setProperty("--primary-h", hue.toString()); 20 + await new Promise((resolve) => setTimeout(resolve, 10)); 21 + } 22 + } 23 + let clickCounter = 0; 24 + const carameldansenfusion = async () => { 25 + clickCounter++; 26 + if (clickCounter >= 10) { 27 + clickCounter = 0; 28 + cycleColors(); 29 + } 30 + }; 31 + 32 + onMount(() => { 33 + // Fetch initial posts 34 + getNextPosts().then((initialPosts) => { 35 + posts = initialPosts; 36 + }); 37 + }); 38 + // Infinite loading function 39 + const onInfinite = ({ 40 + detail: { loaded, complete }, 41 + }: { 42 + detail: { loaded: () => void; complete: () => void }; 43 + }) => { 44 + getNextPosts().then((newPosts) => { 45 + console.log("Loading next posts..."); 46 + if (newPosts.length > 0) { 47 + posts = [...posts, ...newPosts]; 48 + loaded(); 49 + } else { 50 + complete(); 51 + } 52 + }); 53 + }; 54 + </script> 55 + 56 + <main> 57 + <div id="content"> 58 + {#await accountsPromise} 59 + <p>Loading...</p> 60 + {:then accountsData} 61 + <div id="account"> 62 + <pre id="asciiart"> 63 + █▓░░░░░░░░░▒ 64 + █▓▒ ░▒ 65 + ▓▒▒▒░ ▒ 66 + ▓▒░░░░ ░▓ 67 + █▒ ░░ ░ ░ ▓▒ ░█ 68 + ▓░ ░░ ▒▓░░▒▒░ ▒ 69 + ███████ ██▓▒░▒▒░ ░░░░ ░░░ ▒ 70 + █▓▓▓▓▓▓▓▓▓▓▓▓▓▒▓▓▓▓▓▒▒▓▒▒▒▓░ ▓ 71 + ███▓▒░░▒░░░░▓▓█▓▓▒░ ░ 72 + ▓ ░ 73 + █ ░ ▒ 74 + █░ ▒█ 75 + ▒ ▒ 76 + █▒ █ 77 + ▓ ░█ 78 + ▓▒ ░░ ░▒ 79 + ▓▒▒░░▒▓░ ░░░▒▒▓▓▒▓▓ 80 + █▓█▓▓█ ███▓█ 81 + ████ ████ 82 + </pre> 83 + <h1 onclick={carameldansenfusion} id="header">shimaenaga pds</h1> 84 + <p id="subtitle">a project of <a href="https://veryroundbird.house" target="_blank">veryroundbird.house</a></p> 85 + <p>{accountsData.length} birds nesting here</p> 86 + <div id="accountsList"> 87 + {#each accountsData as accountObject} 88 + <AccountComponent account={accountObject} /> 89 + {/each} 90 + </div> 91 + <footer id="footer">{@html Config.FOOTER_TEXT}</footer> 92 + </div> 93 + {:catch error} 94 + <p>Error: {error.message}</p> 95 + {/await} 96 + 97 + <div id="feed"> 98 + {#each posts as postObject} 99 + <PostComponent post={postObject as Post} /> 100 + {/each} 101 + <InfiniteLoading on:infinite={onInfinite} distance={3000} /> 102 + </div> 103 + </div> 104 + </main>
+4
src/app.css
··· 1 + @import url('./themes/colors.css'); 2 + body { 3 + background-color: red; 4 + }
+37
src/lib/AccountComponent.svelte
··· 1 + <script lang="ts"> 2 + import type { AccountMetadata } from "./pdsfetch"; 3 + const { account }: { account: AccountMetadata } = $props(); 4 + console.log(account); 5 + import { Config } from "../../config"; 6 + </script> 7 + 8 + <button class="accountBtn" type="button" popovertarget="{account.handle.replace('.')}" title="{account.handle}"> 9 + <div class="accountContainer"> 10 + {#if account.avatarCid} 11 + <img 12 + class="avatar" 13 + alt="avatar of {account.displayName}" 14 + width="24" 15 + height="24" 16 + src="{Config.PDS_URL}/xrpc/com.atproto.sync.getBlob?did={account.did}&cid={account.avatarCid}" 17 + /> 18 + {:else} 19 + <img 20 + class="avatar" 21 + alt="no avatar for {account.displayName}" 22 + width="24" 23 + height="24" 24 + src="" 25 + /> 26 + {/if} 27 + </div> 28 + <div class="accountTooltip" popover id="{account.handle.replace('.')}"> 29 + <div class="banner"> 30 + <img class="bannerImg" src="{Config.PDS_URL}/xrpc/com.atproto.sync.getBlob?did={account.did}&cid={account.bannerCid}" alt="{account.displayName}'s banner" width="300" height="100" /> 31 + <img class="avatarInsetImg" src="{Config.PDS_URL}/xrpc/com.atproto.sync.getBlob?did={account.did}&cid={account.avatarCid}" alt="{account.displayName}'s avatar" width="50" height="50" /> 32 + </div> 33 + <div class="displayName">{account.displayName}</div> 34 + <div class="handle"><a href="{Config.FRONTEND_URL}/profile/{account.did}" target="_blank">{account.handle}</a></div> 35 + <div class="desc">{account.description}</div> 36 + </div> 37 + </button>
+156
src/lib/PostComponent.svelte
··· 1 + <script lang="ts"> 2 + import { Post } from "./pdsfetch"; 3 + import { Config } from "../../config"; 4 + import { onMount } from "svelte"; 5 + import moment from "moment"; 6 + 7 + let { post }: { post: Post } = $props(); 8 + 9 + // State for image carousel 10 + let currentImageIndex = $state(0); 11 + 12 + // Functions to navigate carousel 13 + function nextImage() { 14 + if (post.imagesCid && currentImageIndex < post.imagesCid.length - 1) { 15 + currentImageIndex++; 16 + } 17 + } 18 + 19 + function prevImage() { 20 + if (currentImageIndex > 0) { 21 + currentImageIndex--; 22 + } 23 + } 24 + 25 + // Function to preload an image 26 + function preloadImage(index: number): void { 27 + if (!post.imagesCid || index < 0 || index >= post.imagesCid.length) return; 28 + 29 + const img = new Image(); 30 + img.src = `${Config.PDS_URL}/xrpc/com.atproto.sync.getBlob?did=${post.authorDid}&cid=${post.imagesCid[index]}`; 31 + } 32 + 33 + // Preload adjacent images when current index changes 34 + $effect(() => { 35 + if (post.imagesCid && post.imagesCid.length > 1) { 36 + // Preload next image if available 37 + if (currentImageIndex < post.imagesCid.length - 1) { 38 + preloadImage(currentImageIndex + 1); 39 + } 40 + 41 + // Preload previous image if available 42 + if (currentImageIndex > 0) { 43 + preloadImage(currentImageIndex - 1); 44 + } 45 + } 46 + }); 47 + 48 + // Initial preload of images 49 + onMount(() => { 50 + if (post.imagesCid && post.imagesCid.length > 1) { 51 + // Preload the next image if it exists 52 + if (post.imagesCid.length > 1) { 53 + preloadImage(1); 54 + } 55 + } 56 + }); 57 + </script> 58 + 59 + <div class="postContainer"> 60 + <div class="postHeader"> 61 + {#if post.authorAvatarCid} 62 + <img 63 + class="avatar" 64 + src="{Config.PDS_URL}/xrpc/com.atproto.sync.getBlob?did={post.authorDid}&cid={post.authorAvatarCid}" 65 + alt="avatar of {post.displayName}" 66 + /> 67 + {/if} 68 + <div class="headerText"> 69 + <a class="displayName" href="{Config.FRONTEND_URL}/profile/{post.authorDid}" 70 + >{post.displayName}</a 71 + > 72 + <p class="handle"> 73 + <a href="{Config.FRONTEND_URL}/profile/{post.authorHandle}" 74 + >@{post.authorHandle}</a 75 + > 76 + 77 + <a 78 + class="postLink" 79 + href="{Config.FRONTEND_URL}/profile/{post.authorDid}/post/{post.recordName}" 80 + >{moment(post.timenotstamp).isBefore(moment().subtract(1, "month")) 81 + ? moment(post.timenotstamp).format("MMM D, YYYY") 82 + : moment(post.timenotstamp).fromNow()}</a 83 + > 84 + </p> 85 + </div> 86 + </div> 87 + <div class="postContent"> 88 + {#if post.replyingUri} 89 + <a 90 + class="replyingText" 91 + href="{Config.FRONTEND_URL}/profile/{post.replyingUri.repo}/post/{post 92 + .replyingUri.rkey}">replying to {post.replyingUri.repo}</a 93 + > 94 + {/if} 95 + {#if post.quotingUri} 96 + <a 97 + class="quotingText" 98 + href="{Config.FRONTEND_URL}/profile/{post.quotingUri.repo}/post/{post 99 + .quotingUri.rkey}">quoting {post.quotingUri.repo}</a 100 + > 101 + {/if} 102 + <div class="postText">{post.text}</div> 103 + {#if post.imagesCid && post.imagesCid.length > 0} 104 + <div id="carouselContainer"> 105 + <img 106 + class="embedImages" 107 + alt="Post Image {currentImageIndex + 1} of {post.imagesCid.length}" 108 + src="{Config.PDS_URL}/xrpc/com.atproto.sync.getBlob?did={post.authorDid}&cid={post 109 + .imagesCid[currentImageIndex]}" 110 + /> 111 + 112 + {#if post.imagesCid.length > 1} 113 + <div class="carouselControls"> 114 + <button 115 + id="prevBtn" 116 + onclick={prevImage} 117 + disabled={currentImageIndex === 0}>←</button 118 + > 119 + <div class="carouselIndicators"> 120 + {#each post.imagesCid as _, i} 121 + <div 122 + class="indicator {i === currentImageIndex ? 'active' : ''}" 123 + ></div> 124 + {/each} 125 + </div> 126 + <button 127 + class="nextBtn" 128 + onclick={nextImage} 129 + disabled={currentImageIndex === post.imagesCid.length - 1} 130 + >→</button 131 + > 132 + </div> 133 + {/if} 134 + </div> 135 + {/if} 136 + {#if post.videosLinkCid} 137 + <!-- svelte-ignore a11y_media_has_caption --> 138 + <video 139 + class="embedVideo" 140 + src="{Config.PDS_URL}/xrpc/com.atproto.sync.getBlob?did={post.authorDid}&cid={post.videosLinkCid}" 141 + controls 142 + ></video> 143 + {/if} 144 + {#if post.gifLink} 145 + <img 146 + class="embedVideo" 147 + src="{post.gifLink}" 148 + alt="Post GIF" 149 + /> 150 + {/if} 151 + </div> 152 + </div> 153 + 154 + <style> 155 + 156 + </style>
+363
src/lib/pdsfetch.ts
··· 1 + import { simpleFetchHandler, XRPC } from "@atcute/client"; 2 + import "@atcute/bluesky/lexicons"; 3 + import type { 4 + AppBskyActorDefs, 5 + AppBskyActorProfile, 6 + AppBskyFeedPost, 7 + At, 8 + ComAtprotoRepoListRecords, 9 + } from "@atcute/client/lexicons"; 10 + import { 11 + CompositeDidDocumentResolver, 12 + PlcDidDocumentResolver, 13 + WebDidDocumentResolver, 14 + } from "@atcute/identity-resolver"; 15 + import { Config } from "../../config"; 16 + import { Mutex } from "mutex-ts" 17 + // import { ComAtprotoRepoListRecords.Record } from "@atcute/client/lexicons"; 18 + // import { AppBskyFeedPost } from "@atcute/client/lexicons"; 19 + // import { AppBskyActorDefs } from "@atcute/client/lexicons"; 20 + 21 + interface AccountMetadata { 22 + did: At.Did; 23 + displayName: string; 24 + handle: string; 25 + avatarCid: string | null; 26 + currentCursor?: string; 27 + } 28 + 29 + let accountsMetadata: AccountMetadata[] = []; 30 + 31 + interface atUriObject { 32 + repo: string; 33 + collection: string; 34 + rkey: string; 35 + } 36 + class Post { 37 + authorDid: string; 38 + authorAvatarCid: string | null; 39 + postCid: string; 40 + recordName: string; 41 + authorHandle: string; 42 + displayName: string; 43 + text: string; 44 + timestamp: number; 45 + timenotstamp: string; 46 + quotingUri: atUriObject | null; 47 + replyingUri: atUriObject | null; 48 + imagesCid: string[] | null; 49 + videosLinkCid: string | null; 50 + gifLink: string | null; 51 + 52 + constructor( 53 + record: ComAtprotoRepoListRecords.Record, 54 + account: AccountMetadata, 55 + ) { 56 + this.postCid = record.cid; 57 + this.recordName = processAtUri(record.uri).rkey; 58 + this.authorDid = account.did; 59 + this.authorAvatarCid = account.avatarCid; 60 + this.authorHandle = account.handle; 61 + this.displayName = account.displayName; 62 + const post = record.value as AppBskyFeedPost.Record; 63 + this.timenotstamp = post.createdAt; 64 + this.text = post.text; 65 + this.timestamp = Date.parse(post.createdAt); 66 + if (post.reply) { 67 + this.replyingUri = processAtUri(post.reply.parent.uri); 68 + } else { 69 + this.replyingUri = null; 70 + } 71 + this.quotingUri = null; 72 + this.imagesCid = null; 73 + this.videosLinkCid = null; 74 + this.gifLink = null; 75 + switch (post.embed?.$type) { 76 + case "app.bsky.embed.images": 77 + this.imagesCid = post.embed.images.map( 78 + (imageRecord: any) => imageRecord.image.ref.$link, 79 + ); 80 + break; 81 + case "app.bsky.embed.video": 82 + this.videosLinkCid = post.embed.video.ref.$link; 83 + break; 84 + case "app.bsky.embed.record": 85 + this.quotingUri = processAtUri(post.embed.record.uri); 86 + break; 87 + case "app.bsky.embed.recordWithMedia": 88 + this.quotingUri = processAtUri(post.embed.record.record.uri); 89 + switch (post.embed.media.$type) { 90 + case "app.bsky.embed.images": 91 + this.imagesCid = post.embed.media.images.map( 92 + (imageRecord) => imageRecord.image.ref.$link, 93 + ); 94 + 95 + break; 96 + case "app.bsky.embed.video": 97 + this.videosLinkCid = post.embed.media.video.ref.$link; 98 + 99 + break; 100 + } 101 + break; 102 + case "app.bsky.embed.external": // assuming that external embeds are gifs for now 103 + if (post.embed.external.uri.includes(".gif")) { 104 + this.gifLink = post.embed.external.uri; 105 + } 106 + break; 107 + } 108 + } 109 + } 110 + 111 + const processAtUri = (aturi: string): atUriObject => { 112 + const parts = aturi.split("/"); 113 + return { 114 + repo: parts[2], 115 + collection: parts[3], 116 + rkey: parts[4], 117 + }; 118 + }; 119 + 120 + const rpc = new XRPC({ 121 + handler: simpleFetchHandler({ 122 + service: Config.PDS_URL, 123 + }), 124 + }); 125 + 126 + const getDidsFromPDS = async (): Promise<At.Did[]> => { 127 + const { data } = await rpc.get("com.atproto.sync.listRepos", { 128 + params: {}, 129 + }); 130 + return data.repos.map((repo: any) => repo.did) as At.Did[]; 131 + }; 132 + const getAccountMetadata = async ( 133 + did: `did:${string}:${string}`, 134 + ) => { 135 + const account: AccountMetadata = { 136 + did: did, 137 + handle: "", // Guaranteed to be filled out later 138 + displayName: "", 139 + avatarCid: null, 140 + }; 141 + 142 + try { 143 + const { data } = await rpc.get("com.atproto.repo.getRecord", { 144 + params: { 145 + repo: did, 146 + collection: "app.bsky.actor.profile", 147 + rkey: "self", 148 + }, 149 + }); 150 + const value = data.value as AppBskyActorProfile.Record; 151 + account.displayName = value.displayName || ""; 152 + account.description = value.description || ""; 153 + if (value.avatar) { 154 + account.avatarCid = value.avatar.ref["$link"]; 155 + } 156 + if (value.banner) { 157 + account.bannerCid = value.banner.ref["$link"]; 158 + } 159 + } catch (e) { 160 + console.warn(`Error fetching profile for ${did}:`, e); 161 + } 162 + 163 + try { 164 + account.handle = await blueskyHandleFromDid(did); 165 + } catch (e) { 166 + console.error(`Error fetching handle for ${did}:`, e); 167 + return null; 168 + } 169 + 170 + return account; 171 + }; 172 + 173 + const getAllMetadataFromPds = async (): Promise<AccountMetadata[]> => { 174 + const dids = await getDidsFromPDS(); 175 + const metadata = await Promise.all( 176 + dids.map(async (repo: `did:${string}:${string}`) => { 177 + return await getAccountMetadata(repo); 178 + }), 179 + ); 180 + return metadata.filter((account) => account !== null) as AccountMetadata[]; 181 + }; 182 + 183 + const identityResolve = async (did: At.Did) => { 184 + const resolver = new CompositeDidDocumentResolver({ 185 + methods: { 186 + plc: new PlcDidDocumentResolver(), 187 + web: new WebDidDocumentResolver(), 188 + }, 189 + }); 190 + 191 + if (did.startsWith("did:plc:") || did.startsWith("did:web:")) { 192 + const doc = await resolver.resolve( 193 + did as `did:plc:${string}` | `did:web:${string}`, 194 + ); 195 + return doc; 196 + } else { 197 + throw new Error(`Unsupported DID type: ${did}`); 198 + } 199 + }; 200 + 201 + const blueskyHandleFromDid = async (did: At.Did) => { 202 + const doc = await identityResolve(did); 203 + if (doc.alsoKnownAs) { 204 + const handleAtUri = doc.alsoKnownAs.find((url) => url.startsWith("at://")); 205 + const handle = handleAtUri?.split("/")[2]; 206 + if (!handle) { 207 + return "Handle not found"; 208 + } else { 209 + return handle; 210 + } 211 + } else { 212 + return "Handle not found"; 213 + } 214 + }; 215 + 216 + interface PostsAcc { 217 + posts: ComAtprotoRepoListRecords.Record[]; 218 + account: AccountMetadata; 219 + } 220 + const getCutoffDate = (postAccounts: PostsAcc[]) => { 221 + const now = Date.now(); 222 + let cutoffDate: Date | null = null; 223 + postAccounts.forEach((postAcc) => { 224 + const latestPost = new Date( 225 + (postAcc.posts[postAcc.posts.length - 1].value as AppBskyFeedPost.Record) 226 + .createdAt, 227 + ); 228 + if (!cutoffDate) { 229 + cutoffDate = latestPost; 230 + } else { 231 + if (latestPost > cutoffDate) { 232 + cutoffDate = latestPost; 233 + } 234 + } 235 + }); 236 + if (cutoffDate) { 237 + return cutoffDate; 238 + } else { 239 + return new Date(now); 240 + } 241 + }; 242 + 243 + const filterPostsByDate = (posts: PostsAcc[], cutoffDate: Date) => { 244 + // filter posts for each account that are older than the cutoff date and save the cursor of the last post included 245 + const filteredPosts: PostsAcc[] = posts.map((postAcc) => { 246 + const filtered = postAcc.posts.filter((post) => { 247 + const postDate = new Date( 248 + (post.value as AppBskyFeedPost.Record).createdAt, 249 + ); 250 + return postDate >= cutoffDate; 251 + }); 252 + if (filtered.length > 0) { 253 + postAcc.account.currentCursor = processAtUri(filtered[filtered.length - 1].uri).rkey; 254 + } 255 + return { 256 + posts: filtered, 257 + account: postAcc.account, 258 + }; 259 + }); 260 + return filteredPosts; 261 + }; 262 + 263 + const postsMutex = new Mutex(); 264 + // nightmare function. However it works so I am not touching it 265 + const getNextPosts = async () => { 266 + const release = await postsMutex.obtain(); 267 + if (!accountsMetadata.length) { 268 + accountsMetadata = await getAllMetadataFromPds(); 269 + } 270 + 271 + const postsAcc: PostsAcc[] = await Promise.all( 272 + accountsMetadata.map(async (account) => { 273 + const posts = await fetchPostsForUser( 274 + account.did, 275 + account.currentCursor || null, 276 + ); 277 + if (posts) { 278 + return { 279 + posts: posts, 280 + account: account, 281 + }; 282 + } else { 283 + return { 284 + posts: [], 285 + account: account, 286 + }; 287 + } 288 + }), 289 + ); 290 + const recordsFiltered = postsAcc.filter((postAcc) => 291 + postAcc.posts.length > 0 292 + ); 293 + const cutoffDate = getCutoffDate(recordsFiltered); 294 + const recordsCutoff = filterPostsByDate(recordsFiltered, cutoffDate); 295 + // update the accountMetadata with the new cursor 296 + accountsMetadata = accountsMetadata.map((account) => { 297 + const postAcc = recordsCutoff.find( 298 + (postAcc) => postAcc.account.did == account.did, 299 + ); 300 + if (postAcc) { 301 + account.currentCursor = postAcc.account.currentCursor; 302 + } 303 + return account; 304 + } 305 + ); 306 + // throw the records in a big single array 307 + let records = recordsCutoff.flatMap((postAcc) => postAcc.posts); 308 + // sort the records by timestamp 309 + records = records.sort((a, b) => { 310 + const aDate = new Date( 311 + (a.value as AppBskyFeedPost.Record).createdAt, 312 + ).getTime(); 313 + const bDate = new Date( 314 + (b.value as AppBskyFeedPost.Record).createdAt, 315 + ).getTime(); 316 + return bDate - aDate; 317 + }); 318 + // filter out posts that are in the future 319 + if (!Config.SHOW_FUTURE_POSTS) { 320 + const now = Date.now(); 321 + records = records.filter((post) => { 322 + const postDate = new Date( 323 + (post.value as AppBskyFeedPost.Record).createdAt, 324 + ).getTime(); 325 + return postDate <= now; 326 + }); 327 + } 328 + 329 + const newPosts = records.map((record) => { 330 + const account = accountsMetadata.find( 331 + (account) => account.did == processAtUri(record.uri).repo, 332 + ); 333 + if (!account) { 334 + throw new Error( 335 + `Account with DID ${processAtUri(record.uri).repo} not found`, 336 + ); 337 + } 338 + return new Post(record, account); 339 + }); 340 + // release the mutex 341 + release(); 342 + return newPosts; 343 + }; 344 + 345 + const fetchPostsForUser = async (did: At.Did, cursor: string | null) => { 346 + try { 347 + const { data } = await rpc.get("com.atproto.repo.listRecords", { 348 + params: { 349 + repo: did as At.Identifier, 350 + collection: "app.bsky.feed.post", 351 + limit: Config.MAX_POSTS, 352 + cursor: cursor || undefined, 353 + }, 354 + }); 355 + return data.records as ComAtprotoRepoListRecords.Record[]; 356 + } catch (e) { 357 + console.error(`Error fetching posts for ${did}:`, e); 358 + return null; 359 + } 360 + }; 361 + 362 + export { getAllMetadataFromPds, getNextPosts, Post }; 363 + export type { AccountMetadata };
+9
src/main.ts
··· 1 + import { mount } from "svelte"; 2 + import "./app.css"; 3 + import App from "./App.svelte"; 4 + 5 + const app = mount(App, { 6 + target: document.getElementById("app")!, 7 + }); 8 + 9 + export default app;
+2
src/vite-env.d.ts
··· 1 + /// <reference types="svelte" /> 2 + /// <reference types="vite/client" />
+7
svelte.config.js
··· 1 + import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; 2 + 3 + export default { 4 + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess 5 + // for more information about preprocessors 6 + preprocess: vitePreprocess(), 7 + };
+432
themes/birdrights/theme.css
··· 1 + @font-face { 2 + font-family: "Recursive Variable"; 3 + font-weight: 100 700; 4 + font-style: -5deg 5deg; 5 + src: url(/fonts/Recursive_VF_1.085.woff2) format('woff2'); 6 + } 7 + 8 + :root { 9 + /* Color overrides, edit to whatever you want */ 10 + --primary-h: 260; /* Hue */ 11 + --background: #EFD7E4; 12 + --foreground: #333333; 13 + 14 + --link-color: color-mix(in srgb-linear, color-mix(in srgb-linear, var(--background), red 50%), black 25%); 15 + --link-hover-color: color-mix(in srgb-linear, var(--link-color), black 25%); 16 + --background-color: var(--background); 17 + --header-background-color: var(--background); 18 + --content-background-color: rgba(255,255,255,.5); 19 + --text-color: var(--foreground); 20 + --border-color: color-mix(in srgb-linear, var(--text-color), rgba(0,0,0,.15)); 21 + --indicator-inactive-color: var(--link-hover-color); 22 + --indicator-active-color: var(--link-color); 23 + --base-font-size: 14px; 24 + } 25 + 26 + * { 27 + box-sizing: border-box; 28 + } 29 + 30 + body { 31 + margin: 20px; 32 + display: flex; 33 + place-items: center; 34 + min-width: 320px; 35 + min-height: 100vh; 36 + background-color: var(--background-color); 37 + font-family: "Recursive Variable"; 38 + font-size: var(--base-font-size); 39 + color: var(--text-color); 40 + border-color: var(--border-color); 41 + overflow-wrap: break-word; 42 + word-wrap: normal; 43 + word-break: break-word; 44 + hyphens: none; 45 + } 46 + 47 + a { 48 + font-weight: 500; 49 + color: var(--link-color); 50 + text-decoration: inherit; 51 + } 52 + a:hover { 53 + color: var(--link-hover-color); 54 + text-decoration: underline; 55 + } 56 + 57 + h1 { 58 + font-size: 2em; 59 + line-height: 1.1; 60 + margin-bottom: 0; 61 + text-align: center; 62 + } 63 + 64 + #app { 65 + max-width: 600px; 66 + width: 100%; 67 + margin: 0; 68 + padding: 0; 69 + margin-left: auto; 70 + margin-right: auto; 71 + text-align: center; 72 + } 73 + 74 + /* Page Structure */ 75 + #content { 76 + /* split the screen in half, left for accounts, right for posts */ 77 + width: 100%; 78 + margin: 0 auto; 79 + } 80 + 81 + #account { 82 + text-align: center; 83 + margin-bottom: 20px; 84 + } 85 + 86 + #accountsList { 87 + display: grid; 88 + grid-template-columns: repeat(12, 1fr); 89 + gap: 10px; 90 + overflow-y: scroll; 91 + height: 100%; 92 + width: 100%; 93 + padding: 0px; 94 + margin: 0px; 95 + } 96 + 97 + #feed { 98 + width: 100%; 99 + margin-top: 0; 100 + margin-bottom: 0; 101 + } 102 + 103 + /* Header */ 104 + #subtitle { 105 + font-size: 1.1rem; 106 + font-style: oblique 5deg; 107 + margin: 0; 108 + } 109 + 110 + #asciiart { 111 + font-size: .8rem; 112 + line-height: 1; 113 + margin: 0 auto; 114 + display: inline-block; 115 + } 116 + 117 + /* Post Component */ 118 + .postContainer { 119 + border: 1px solid var(--border-color); 120 + background-color: var(--background-color); 121 + margin-bottom: 15px; 122 + overflow-wrap: break-word; 123 + overflow: hidden; 124 + border-radius: 5px 5px 3px 3px; 125 + } 126 + 127 + .postHeader { 128 + display: flex; 129 + flex-direction: row; 130 + align-items: center; 131 + justify-content: start; 132 + background-color: var(--header-background-color); 133 + padding: 0px 0px; 134 + height: fit-content; 135 + border-bottom: 1px solid var(--border-color); 136 + font-weight: bold; 137 + overflow-wrap: break-word; 138 + height: 60px; 139 + } 140 + 141 + .headerText { 142 + margin-left: 10px; 143 + font-size: 0.9em; 144 + text-align: start; 145 + word-break: break-word; 146 + max-width: 80%; 147 + max-height: 95%; 148 + overflow: hidden; 149 + align-self: flex-start; 150 + margin-top: auto; 151 + margin-bottom: auto; 152 + } 153 + 154 + .displayName { 155 + display: block; 156 + color: var(--text-color); 157 + font-size: 1.2em; 158 + padding: 0; 159 + margin: 0; 160 + overflow-wrap: normal; 161 + word-wrap: break-word; 162 + word-break: break-word; 163 + text-overflow: ellipsis; 164 + overflow: hidden; 165 + white-space: nowrap; 166 + width: 100%; 167 + } 168 + 169 + .handle { 170 + display: block; 171 + color: var(--border-color); 172 + font-size: 0.8em; 173 + padding: 0; 174 + margin: 0; 175 + } 176 + 177 + .avatar { 178 + height: 60px; 179 + width: 60px; 180 + margin: 0px; 181 + margin-left: 0px; 182 + overflow: hidden; 183 + object-fit: cover; 184 + border-right: var(--border-color) 1px solid; 185 + } 186 + 187 + .postLink { 188 + color: var(--border-color); 189 + font-size: 0.8em; 190 + padding: 0; 191 + margin: 0; 192 + } 193 + 194 + .postContent { 195 + display: flex; 196 + text-align: start; 197 + flex-direction: column; 198 + padding: 10px; 199 + background-color: var(--content-background-color); 200 + color: var(--text-color); 201 + overflow-wrap: break-word; 202 + white-space: pre-line; 203 + } 204 + 205 + .replyingText { 206 + font-size: 0.7em; 207 + margin: 0; 208 + padding: 0; 209 + padding-bottom: 5px; 210 + } 211 + 212 + .quotingText { 213 + font-size: 0.7em; 214 + margin: 0; 215 + padding: 0; 216 + padding-bottom: 5px; 217 + } 218 + 219 + .postText { 220 + margin: 0; 221 + padding: 0; 222 + overflow-wrap: break-word; 223 + word-wrap: normal; 224 + word-break: break-word; 225 + hyphens: none; 226 + } 227 + 228 + .carouselContainer { 229 + position: relative; 230 + width: 100%; 231 + margin-top: 10px; 232 + display: flex; 233 + flex-direction: column; 234 + align-items: center; 235 + } 236 + 237 + .carouselControls { 238 + display: flex; 239 + justify-content: space-between; 240 + align-items: center; 241 + width: 100%; 242 + max-width: 500px; 243 + margin-top: 5px; 244 + } 245 + 246 + .carouselIndicators { 247 + display: flex; 248 + gap: 5px; 249 + } 250 + 251 + .indicator { 252 + width: 8px; 253 + height: 8px; 254 + background-color: var(--indicator-inactive-color); 255 + } 256 + 257 + .indicator.active { 258 + background-color: var(--indicator-active-color); 259 + } 260 + 261 + .prevBtn, 262 + .nextBtn { 263 + background-color: rgba(31, 17, 69, 0.7); 264 + color: var(--text-color); 265 + border: 1px solid var(--border-color); 266 + width: 30px; 267 + height: 30px; 268 + cursor: pointer; 269 + display: flex; 270 + align-items: center; 271 + justify-content: center; 272 + } 273 + 274 + .prevBtn:disabled, 275 + .nextBtn:disabled { 276 + opacity: 0.5; 277 + cursor: not-allowed; 278 + } 279 + 280 + .embedVideo { 281 + width: 100%; 282 + max-width: 500px; 283 + margin-top: 10px; 284 + align-self: center; 285 + } 286 + 287 + .embedImages { 288 + min-width: min(100%, 500px); 289 + max-width: min(100%, 500px); 290 + max-height: 500px; 291 + object-fit: contain; 292 + 293 + margin: 0; 294 + } 295 + 296 + /* Account Component */ 297 + .accountBtn { 298 + appearance: none; 299 + border: none; 300 + background-color: transparent; 301 + padding: 0; 302 + position: relative; 303 + } 304 + 305 + .accountContainer { 306 + padding: 0px; 307 + border: 1px solid var(--border-color); 308 + min-height: 30px; 309 + overflow: hidden; 310 + border-radius: 3px; 311 + } 312 + 313 + .accountContainer img.avatar { 314 + width: 100%; 315 + height: auto; 316 + border-right: none; 317 + display: block; 318 + } 319 + 320 + .accountName { 321 + margin-left: 10px; 322 + font-size: 1em; 323 + max-width: 80%; 324 + overflow: hidden; 325 + text-overflow: ellipsis; 326 + white-space: nowrap; 327 + } 328 + 329 + .accountTooltip { 330 + border: 1px var(--border-color) solid; 331 + color: var(--text-color); 332 + background-color: var(--content-background-color); 333 + backdrop-filter: blur(5px); 334 + border-radius: 3px; 335 + padding: 10px; 336 + text-align: left; 337 + font-size: 13px; 338 + width: 300px; 339 + } 340 + 341 + .banner { 342 + position: relative; 343 + margin-bottom: 10px; 344 + width: calc(100% + 20px); 345 + margin-left: -10px; 346 + margin-right: -10px; 347 + margin-top: -10px; 348 + } 349 + 350 + .banner img.bannerImg { 351 + width: 100%; 352 + height: 100px; 353 + object-fit: cover; 354 + display: block; 355 + border-bottom: 1px var(--border-color) solid; 356 + } 357 + 358 + .banner .avatarInsetImg { 359 + position: absolute; 360 + left: 10px; 361 + top: 60px; 362 + border-radius: 3px; 363 + border: 1px var(--border-color) solid; 364 + } 365 + 366 + .accountTooltip .displayName { 367 + font-weight: bold; 368 + } 369 + 370 + .no-avatar { 371 + 372 + } 373 + 374 + /* Source Link */ 375 + 376 + #footer { 377 + position: absolute; 378 + bottom: 5px; 379 + right: 5px; 380 + z-index: 99; 381 + opacity: .8; 382 + transition: 0.3s; 383 + font-size: .8em; 384 + text-transform: lowercase; 385 + background-color: rgba(255,255,255,.5); 386 + padding: 2px 5px; 387 + border-radius: 10px; 388 + } 389 + 390 + #footer:hover { 391 + opacity: 1; 392 + } 393 + 394 + /* Responsive Styling */ 395 + @media screen and (max-width: 600px) { 396 + #accountsList { 397 + grid-template-columns: repeat(6, 1fr); 398 + } 399 + } 400 + 401 + /* Scrollbars */ 402 + 403 + ::-webkit-scrollbar { 404 + width: 0px; 405 + background: transparent; 406 + padding: 0; 407 + margin: 0; 408 + } 409 + ::-webkit-scrollbar-thumb { 410 + background: transparent; 411 + border-radius: 0; 412 + } 413 + ::-webkit-scrollbar-track { 414 + background: transparent; 415 + border-radius: 0; 416 + } 417 + ::-webkit-scrollbar-corner { 418 + background: transparent; 419 + border-radius: 0; 420 + } 421 + ::-webkit-scrollbar-button { 422 + background: transparent; 423 + border-radius: 0; 424 + } 425 + 426 + * { 427 + scrollbar-width: none; 428 + scrollbar-color: transparent transparent; 429 + -ms-overflow-style: none; /* IE and Edge */ 430 + -webkit-overflow-scrolling: touch; 431 + -webkit-scrollbar: none; /* Safari */ 432 + }
+423
themes/default/theme.css
··· 1 + /* Modern Theme for pds-dash */ 2 + 3 + :root { 4 + /* Modern color palette */ 5 + --primary-h: 243; 6 + --link-color: hsl(var(--primary-h), 73%, 59%); 7 + --link-hover-color: #4338ca; 8 + --time-color: #8b5cf6; 9 + --background-color: #f8fafc; 10 + --header-background-color: #ffffff; 11 + --content-background-color: #ffffff; 12 + --text-color: #111827; 13 + --text-secondary-color: #4b5563; 14 + --border-color: #e2e8f0; 15 + --indicator-inactive-color: #cbd5e1; 16 + --indicator-active-color: #6366f1; 17 + 18 + /* Modern shadows */ 19 + --button-hover: #f3f4f6; 20 + } 21 + 22 + 23 + body { 24 + margin: 0; 25 + display: flex; 26 + place-items: center; 27 + min-width: 320px; 28 + min-height: 100vh; 29 + background-color: var(--background-color); 30 + font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif; 31 + font-size: 18px; 32 + line-height: 1.5; 33 + color: var(--text-color); 34 + border-color: var(--border-color); 35 + overflow-wrap: break-word; 36 + word-break: break-word; 37 + hyphens: none; 38 + } 39 + 40 + a { 41 + font-weight: 500; 42 + color: var(--link-color); 43 + text-decoration: none; 44 + transition: color 0.15s ease; 45 + } 46 + a:hover { 47 + color: var(--link-hover-color); 48 + } 49 + 50 + h1 { 51 + font-size: 2.5em; 52 + line-height: 1.2; 53 + font-weight: 700; 54 + } 55 + 56 + #app { 57 + max-width: 1400px; 58 + width: 100%; 59 + margin: 0 auto; 60 + padding: 0; 61 + text-align: center; 62 + } 63 + 64 + /* Post Component */ 65 + #postContainer { 66 + display: flex; 67 + flex-direction: column; 68 + border-radius: 12px; 69 + border: 1px solid var(--border-color); 70 + background-color: var(--content-background-color); 71 + margin-bottom: 20px; 72 + overflow-wrap: break-word; 73 + overflow: hidden; 74 + box-shadow: var(--card-shadow); 75 + transition: transform 0.2s ease, box-shadow 0.2s ease; 76 + } 77 + 78 + #postContainer:hover { 79 + transform: translateY(-2px); 80 + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); 81 + } 82 + 83 + #postHeader { 84 + display: flex; 85 + flex-direction: row; 86 + align-items: center; 87 + justify-content: start; 88 + background-color: var(--header-background-color); 89 + padding: 12px 16px; 90 + height: 60px; 91 + border-bottom: 1px solid var(--border-color); 92 + font-weight: 600; 93 + overflow-wrap: break-word; 94 + } 95 + 96 + #displayName { 97 + display: block; 98 + color: var(--text-color); 99 + font-size: 1.1em; 100 + padding: 0; 101 + margin: 0 0 2px 0; 102 + text-overflow: ellipsis; 103 + overflow: hidden; 104 + white-space: nowrap; 105 + width: 100%; 106 + letter-spacing: -0.01em; 107 + } 108 + 109 + #handle { 110 + display: flex; 111 + align-items: center; 112 + color: #6b7280; 113 + font-size: 0.85em; 114 + font-weight: 400; 115 + padding: 0; 116 + margin: 0; 117 + gap: 8px; 118 + } 119 + 120 + #postLink { 121 + color: var(--time-color); 122 + font-size: 0.85em; 123 + padding: 0; 124 + margin: 0; 125 + opacity: 0.9; 126 + } 127 + 128 + #postContent { 129 + display: flex; 130 + text-align: start; 131 + flex-direction: column; 132 + padding: 16px; 133 + background-color: var(--content-background-color); 134 + color: var(--text-color); 135 + overflow-wrap: break-word; 136 + white-space: pre-line; 137 + line-height: 1.6; 138 + } 139 + 140 + #replyingText, #quotingText { 141 + font-size: 0.8em; 142 + margin: 0; 143 + padding: 0 0 10px 0; 144 + color: #6b7280; 145 + } 146 + 147 + #postText { 148 + margin: 0 0 8px 0; 149 + padding: 0; 150 + overflow-wrap: break-word; 151 + word-break: break-word; 152 + hyphens: none; 153 + font-size: 1.05em; 154 + } 155 + 156 + #headerText { 157 + margin-left: 12px; 158 + font-size: 0.9em; 159 + text-align: start; 160 + word-break: break-word; 161 + max-width: 80%; 162 + max-height: 95%; 163 + overflow: hidden; 164 + align-self: flex-start; 165 + margin-top: auto; 166 + margin-bottom: auto; 167 + } 168 + 169 + #carouselContainer { 170 + position: relative; 171 + width: 100%; 172 + margin-top: 12px; 173 + display: flex; 174 + flex-direction: column; 175 + align-items: center; 176 + border-radius: 8px; 177 + overflow: hidden; 178 + } 179 + 180 + #carouselControls { 181 + display: flex; 182 + justify-content: space-between; 183 + align-items: center; 184 + width: 100%; 185 + max-width: 500px; 186 + margin-top: 10px; 187 + } 188 + 189 + #carouselIndicators { 190 + display: flex; 191 + gap: 6px; 192 + } 193 + 194 + .indicator { 195 + width: 6px; 196 + height: 6px; 197 + background-color: var(--indicator-inactive-color); 198 + border-radius: 50%; 199 + transition: background-color 0.2s ease, transform 0.2s ease; 200 + } 201 + 202 + .indicator.active { 203 + background-color: var(--indicator-active-color); 204 + transform: scale(1.3); 205 + } 206 + 207 + #prevBtn, 208 + #nextBtn { 209 + background-color: var(--button-bg); 210 + color: var(--text-color); 211 + border: 1px solid var(--border-color); 212 + width: 32px; 213 + height: 32px; 214 + cursor: pointer; 215 + display: flex; 216 + align-items: center; 217 + justify-content: center; 218 + border-radius: 50%; 219 + transition: background-color 0.15s ease, transform 0.15s ease; 220 + font-size: 16px; 221 + } 222 + 223 + #prevBtn:hover:not(:disabled), 224 + #nextBtn:hover:not(:disabled) { 225 + background-color: var(--button-hover); 226 + transform: scale(1.05); 227 + } 228 + 229 + #prevBtn:disabled, 230 + #nextBtn:disabled { 231 + opacity: 0.4; 232 + cursor: not-allowed; 233 + } 234 + 235 + #embedVideo { 236 + width: 100%; 237 + max-width: 500px; 238 + margin-top: 12px; 239 + align-self: center; 240 + border-radius: 8px; 241 + overflow: hidden; 242 + } 243 + 244 + #embedImages { 245 + min-width: min(100%, 500px); 246 + max-width: min(100%, 500px); 247 + max-height: 500px; 248 + object-fit: contain; 249 + margin: 0; 250 + border-radius: 8px; 251 + } 252 + 253 + /* Account Component */ 254 + #accountContainer { 255 + display: flex; 256 + text-align: start; 257 + align-items: center; 258 + background-color: var(--content-background-color); 259 + padding: 12px; 260 + margin-bottom: 15px; 261 + border: 1px solid var(--border-color); 262 + border-radius: 12px; 263 + transition: background-color 0.15s ease; 264 + } 265 + 266 + #accountContainer:hover { 267 + background-color: var(--hover-bg); 268 + } 269 + 270 + #accountName { 271 + margin-left: 12px; 272 + font-size: 0.95em; 273 + max-width: 80%; 274 + overflow: hidden; 275 + text-overflow: ellipsis; 276 + white-space: nowrap; 277 + font-weight: 500; 278 + } 279 + 280 + #avatar { 281 + width: 48px; 282 + height: 48px; 283 + margin: 0; 284 + object-fit: cover; 285 + border-radius: 50%; 286 + border: 2px solid white; 287 + box-shadow: 0 1px 3px rgba(0,0,0,0.1); 288 + } 289 + 290 + /* App.Svelte Layout */ 291 + #Content { 292 + display: flex; 293 + width: 100%; 294 + height: 100%; 295 + flex-direction: row; 296 + justify-content: space-between; 297 + align-items: center; 298 + background-color: var(--background-color); 299 + color: var(--text-color); 300 + gap: 24px; 301 + } 302 + 303 + #Feed { 304 + overflow-y: auto; 305 + width: 65%; 306 + height: 100vh; 307 + padding-right: 16px; 308 + align-self: flex-start; 309 + } 310 + 311 + #spacer { 312 + padding: 0; 313 + margin: 0; 314 + height: 10vh; 315 + width: 100%; 316 + } 317 + 318 + #Account { 319 + width: 35%; 320 + display: flex; 321 + flex-direction: column; 322 + border: 1px solid var(--border-color); 323 + background-color: var(--content-background-color); 324 + max-height: 80vh; 325 + padding: 24px; 326 + margin-left: 16px; 327 + border-radius: 12px; 328 + box-shadow: var(--card-shadow); 329 + } 330 + 331 + #accountsList { 332 + display: flex; 333 + flex-direction: column; 334 + overflow-y: auto; 335 + height: 100%; 336 + width: 100%; 337 + padding: 8px 0; 338 + margin: 0; 339 + } 340 + 341 + #Header { 342 + text-align: center; 343 + font-size: 1.8em; 344 + margin-bottom: 16px; 345 + font-weight: 700; 346 + background: linear-gradient(to right, var(--link-color), #8b5cf6); 347 + -webkit-background-clip: text; 348 + -webkit-text-fill-color: transparent; 349 + background-clip: text; 350 + } 351 + 352 + /* Mobile Styles */ 353 + @media screen and (max-width: 768px) { 354 + #Content { 355 + flex-direction: column; 356 + width: auto; 357 + padding: 12px; 358 + margin-top: 0; 359 + } 360 + 361 + #Account { 362 + width: calc(100% - 32px); 363 + padding: 16px; 364 + margin-bottom: 20px; 365 + margin-left: 0; 366 + margin-right: 0; 367 + height: auto; 368 + order: -1; 369 + } 370 + 371 + #Feed { 372 + width: 100%; 373 + margin: 0; 374 + padding: 0; 375 + overflow-y: visible; 376 + } 377 + 378 + #spacer { 379 + height: 5vh; 380 + } 381 + 382 + body { 383 + font-size: 16px; 384 + } 385 + 386 + #postHeader { 387 + padding: 10px; 388 + height: auto; 389 + min-height: 50px; 390 + } 391 + } 392 + 393 + /* Scrollbar Styles */ 394 + ::-webkit-scrollbar { 395 + width: 0px; 396 + background: transparent; 397 + padding: 0; 398 + margin: 0; 399 + } 400 + ::-webkit-scrollbar-thumb { 401 + background: transparent; 402 + border-radius: 0; 403 + } 404 + ::-webkit-scrollbar-track { 405 + background: transparent; 406 + border-radius: 0; 407 + } 408 + ::-webkit-scrollbar-corner { 409 + background: transparent; 410 + border-radius: 0; 411 + } 412 + ::-webkit-scrollbar-button { 413 + background: transparent; 414 + border-radius: 0; 415 + } 416 + 417 + * { 418 + scrollbar-width: none; 419 + scrollbar-color: transparent transparent; 420 + -ms-overflow-style: none; /* IE and Edge */ 421 + -webkit-overflow-scrolling: touch; 422 + -webkit-scrollbar: none; /* Safari */ 423 + }
+375
themes/express/theme.css
··· 1 + @import url("https://fonts.googleapis.com/css2?family=Share+Tech+Mono&display=swap"); 2 + 3 + :root { 4 + /* Color overrides, edit to whatever you want */ 5 + --primary-h: 341; /* Hue */ 6 + --background-color: hsl(var(--primary-h), 62%, 30%); 7 + --text-color: hsl(var(--primary-h), 69%, 18%); 8 + --link-color: hsl(var(--primary-h), 100%, 20%); 9 + --link-hover-color: hsl(var(--primary-h), 20%, 20%); 10 + --border-color: hsl(var(--primary-h), 59%, 52%); 11 + --content-background-color: hsl(var(--primary-h), 97%, 73%); 12 + 13 + --header-background-color: hsl(var(--primary-h), 97%, 73%); 14 + --indicator-inactive-color: #4a4a4a; 15 + --indicator-active-color: var(--border-color); 16 + } 17 + 18 + a { 19 + font-weight: 500; 20 + color: var(--link-color); 21 + text-decoration: inherit; 22 + } 23 + a:hover { 24 + color: var(--link-hover-color); 25 + text-decoration: underline; 26 + } 27 + 28 + body { 29 + margin: 0; 30 + display: flex; 31 + place-items: center; 32 + min-width: 320px; 33 + min-height: 100vh; 34 + background-color: var(--background-color); 35 + font-family: "Share Tech Mono", monospace; 36 + font-size: 24px; 37 + color: var(--text-color); 38 + border-color: var(--border-color); 39 + overflow-wrap: break-word; 40 + word-wrap: normal; 41 + word-break: break-word; 42 + hyphens: none; 43 + } 44 + 45 + h1 { 46 + font-size: 3.2em; 47 + line-height: 1.1; 48 + } 49 + 50 + #app { 51 + max-width: 1400px; 52 + width: 100%; 53 + margin: 0; 54 + padding: 0; 55 + margin-left: auto; 56 + margin-right: auto; 57 + text-align: center; 58 + } 59 + 60 + /* Post Component */ 61 + a:hover { 62 + text-decoration: underline; 63 + } 64 + #postContainer { 65 + display: flex; 66 + flex-direction: column; 67 + border: 4px solid var(--border-color); 68 + background-color: var(--background-color); 69 + margin-bottom: 15px; 70 + overflow-wrap: break-word; 71 + box-shadow: var(--border-color) 10px 10px; 72 + } 73 + #postHeader { 74 + display: flex; 75 + flex-direction: row; 76 + align-items: center; 77 + justify-content: start; 78 + background-color: var(--header-background-color); 79 + padding: 0px 0px; 80 + height: fit-content; 81 + 82 + font-weight: bold; 83 + overflow-wrap: break-word; 84 + height: 64px; 85 + } 86 + #displayName { 87 + display: block; 88 + color: var(--text-color); 89 + font-size: 1.2em; 90 + padding: 0; 91 + margin: 0; 92 + overflow-wrap: normal; 93 + word-wrap: break-word; 94 + word-break: break-word; 95 + text-overflow: ellipsis; 96 + overflow: hidden; 97 + white-space: nowrap; 98 + width: 100%; 99 + } 100 + #handle { 101 + display: block; 102 + color: var(--border-color); 103 + font-size: 0.8em; 104 + padding: 0; 105 + margin: 0; 106 + } 107 + 108 + #postLink { 109 + color: var(--link-hover-color); 110 + font-size: 0.8em; 111 + padding: 0; 112 + margin: 0; 113 + } 114 + #postContent { 115 + display: flex; 116 + text-align: start; 117 + flex-direction: column; 118 + padding: 10px; 119 + background-color: var(--content-background-color); 120 + color: var(--text-color); 121 + overflow-wrap: break-word; 122 + white-space: pre-line; 123 + } 124 + #replyingText { 125 + font-size: 0.7em; 126 + margin: 0; 127 + padding: 0; 128 + padding-bottom: 5px; 129 + } 130 + #quotingText { 131 + font-size: 0.7em; 132 + margin: 0; 133 + padding: 0; 134 + padding-bottom: 5px; 135 + } 136 + #postText { 137 + margin: 0; 138 + padding: 0; 139 + overflow-wrap: break-word; 140 + word-wrap: normal; 141 + word-break: break-word; 142 + hyphens: none; 143 + } 144 + #headerText { 145 + margin-left: 10px; 146 + font-size: 0.9em; 147 + text-align: start; 148 + word-break: break-word; 149 + max-width: 80%; 150 + max-height: 95%; 151 + overflow: hidden; 152 + align-self: flex-start; 153 + margin-top: auto; 154 + margin-bottom: auto; 155 + } 156 + #avatar { 157 + height: 30px; 158 + width: 30px; 159 + overflow: hidden; 160 + object-fit: cover; 161 + } 162 + #postContainer #avatar { 163 + height: 60px; 164 + width: 60px; 165 + border-right: var(--border-color) 4px solid; 166 + border-bottom: var(--border-color) 4px solid; 167 + } 168 + #carouselContainer { 169 + position: relative; 170 + width: 100%; 171 + margin-top: 10px; 172 + display: flex; 173 + flex-direction: column; 174 + align-items: center; 175 + } 176 + #carouselControls { 177 + display: flex; 178 + justify-content: space-between; 179 + align-items: center; 180 + width: 100%; 181 + max-width: 500px; 182 + margin-top: 5px; 183 + } 184 + #carouselIndicators { 185 + display: flex; 186 + gap: 5px; 187 + } 188 + .indicator { 189 + width: 8px; 190 + height: 8px; 191 + background-color: var(--indicator-inactive-color); 192 + } 193 + .indicator.active { 194 + background-color: var(--indicator-active-color); 195 + } 196 + #prevBtn, 197 + #nextBtn { 198 + background-color: rgba(31, 17, 69, 0.7); 199 + color: var(--text-color); 200 + border: 4px solid var(--border-color); 201 + width: 30px; 202 + height: 30px; 203 + cursor: pointer; 204 + display: flex; 205 + align-items: center; 206 + justify-content: center; 207 + } 208 + #prevBtn:disabled, 209 + #nextBtn:disabled { 210 + opacity: 0.5; 211 + cursor: not-allowed; 212 + } 213 + #embedVideo { 214 + width: 100%; 215 + max-width: 500px; 216 + margin-top: 10px; 217 + align-self: center; 218 + } 219 + 220 + #embedImages { 221 + min-width: min(100%, 500px); 222 + max-width: min(100%, 500px); 223 + max-height: 500px; 224 + object-fit: contain; 225 + 226 + margin: 0; 227 + } 228 + 229 + /* Account Component */ 230 + #accountContainer { 231 + display: flex; 232 + text-align: start; 233 + align-items: center; 234 + background-color: var(--header-background-color); 235 + padding: 0px; 236 + margin-bottom: 15px; 237 + margin-right: 4px; 238 + border: 4px solid var(--border-color); 239 + box-shadow: var(--border-color) 10px 10px; 240 + min-height: 30px; 241 + } 242 + #accountName { 243 + margin-left: 10px; 244 + font-size: 1em; 245 + max-width: 80%; 246 + 247 + /* replace overflow with ellipsis */ 248 + overflow: hidden; 249 + text-overflow: ellipsis; 250 + white-space: nowrap; 251 + } 252 + 253 + .no-avatar { 254 + margin-left: 40px !important; 255 + } 256 + 257 + /* App.Svelte */ 258 + /* desktop style */ 259 + 260 + #Content { 261 + display: flex; 262 + /* split the screen in half, left for accounts, right for posts */ 263 + width: 100%; 264 + height: 100%; 265 + flex-direction: row; 266 + justify-content: space-between; 267 + align-items: center; 268 + background-color: var(--background-color); 269 + color: var(--text-color); 270 + } 271 + #Feed { 272 + overflow-y: scroll; 273 + width: 65%; 274 + height: 100vh; 275 + padding: 20px; 276 + padding-bottom: 0; 277 + padding-top: 0; 278 + margin-top: 0; 279 + margin-bottom: 0; 280 + } 281 + #spacer { 282 + padding: 0; 283 + margin: 0; 284 + height: 10vh; 285 + width: 100%; 286 + } 287 + #Account { 288 + width: 35%; 289 + display: flex; 290 + flex-direction: column; 291 + border: 4px solid var(--border-color); 292 + background-color: var(--content-background-color); 293 + box-shadow: var(--border-color) 10px 10px; 294 + height: 80vh; 295 + padding: 20px; 296 + margin-left: 20px; 297 + } 298 + #accountsList { 299 + display: flex; 300 + flex-direction: column; 301 + overflow-y: scroll; 302 + height: 100%; 303 + width: 100%; 304 + padding: 0px; 305 + margin: 0px; 306 + } 307 + 308 + #Header { 309 + text-align: center; 310 + font-size: 2em; 311 + margin-bottom: 20px; 312 + } 313 + 314 + /* mobile style */ 315 + @media screen and (max-width: 600px) { 316 + #Content { 317 + flex-direction: column; 318 + width: auto; 319 + padding-left: 0px; 320 + padding-right: 0px; 321 + margin-top: 5%; 322 + } 323 + #Account { 324 + width: 85%; 325 + padding-left: 5%; 326 + padding-right: 5%; 327 + margin-bottom: 20px; 328 + margin-left: 5%; 329 + margin-right: 5%; 330 + height: auto; 331 + } 332 + #Feed { 333 + width: 95%; 334 + margin: 0px; 335 + margin-left: 10%; 336 + margin-right: 10%; 337 + padding: 0px; 338 + overflow-y: visible; 339 + } 340 + 341 + #spacer { 342 + height: 0; 343 + } 344 + } 345 + 346 + ::-webkit-scrollbar { 347 + width: 0px; 348 + background: transparent; 349 + padding: 0; 350 + margin: 0; 351 + } 352 + ::-webkit-scrollbar-thumb { 353 + background: transparent; 354 + border-radius: 0; 355 + } 356 + ::-webkit-scrollbar-track { 357 + background: transparent; 358 + border-radius: 0; 359 + } 360 + ::-webkit-scrollbar-corner { 361 + background: transparent; 362 + border-radius: 0; 363 + } 364 + ::-webkit-scrollbar-button { 365 + background: transparent; 366 + border-radius: 0; 367 + } 368 + 369 + * { 370 + scrollbar-width: none; 371 + scrollbar-color: transparent transparent; 372 + -ms-overflow-style: none; /* IE and Edge */ 373 + -webkit-overflow-scrolling: touch; 374 + -webkit-scrollbar: none; /* Safari */ 375 + }
+32
theming.ts
··· 1 + import { Plugin } from 'vite'; 2 + import { Config } from './config'; 3 + 4 + 5 + // Replaces app.css with the contents of the file specified in the 6 + // config file. 7 + export const themePlugin = (): Plugin => { 8 + const themeFolder = Config.THEME; 9 + console.log(`Using theme folder: ${themeFolder}`); 10 + return { 11 + name: 'theme-generator', 12 + enforce: 'pre', // Ensure this plugin runs first 13 + transform(code, id) { 14 + if (id.endsWith('app.css')) { 15 + // Read the theme file and replace the contents of app.css with it 16 + // Needs full path to the file 17 + const themeCode = Deno.readTextFileSync(Deno.cwd() + '/themes/' + themeFolder + '/theme.css'); 18 + // Replace the contents of app.css with the theme code 19 + 20 + // and add a comment at the top 21 + const themeComment = `/* Generated from ${themeFolder} */\n`; 22 + const themeCodeWithComment = themeComment + themeCode; 23 + // Return the theme code as the new contents of app.css 24 + return { 25 + code: themeCodeWithComment, 26 + map: null, 27 + }; 28 + } 29 + return null; 30 + } 31 + }; 32 + };
+20
tsconfig.app.json
··· 1 + { 2 + "extends": "@tsconfig/svelte/tsconfig.json", 3 + "compilerOptions": { 4 + "target": "ESNext", 5 + "useDefineForClassFields": true, 6 + "module": "ESNext", 7 + "resolveJsonModule": true, 8 + /** 9 + * Typecheck JS in `.svelte` and `.js` files by default. 10 + * Disable checkJs if you'd like to use dynamic types in JS. 11 + * Note that setting allowJs false does not prevent the use 12 + * of JS in `.svelte` files. 13 + */ 14 + "allowJs": true, 15 + "checkJs": true, 16 + "isolatedModules": true, 17 + "moduleDetection": "force" 18 + }, 19 + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"] 20 + }
+7
tsconfig.json
··· 1 + { 2 + "files": [], 3 + "references": [ 4 + { "path": "./tsconfig.app.json" }, 5 + { "path": "./tsconfig.node.json" } 6 + ] 7 + }
+24
tsconfig.node.json
··· 1 + { 2 + "compilerOptions": { 3 + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 4 + "target": "ES2022", 5 + "lib": ["ES2023"], 6 + "module": "ESNext", 7 + "skipLibCheck": true, 8 + 9 + /* Bundler mode */ 10 + "moduleResolution": "bundler", 11 + "allowImportingTsExtensions": true, 12 + "isolatedModules": true, 13 + "moduleDetection": "force", 14 + "noEmit": true, 15 + 16 + /* Linting */ 17 + "strict": true, 18 + "noUnusedLocals": true, 19 + "noUnusedParameters": true, 20 + "noFallthroughCasesInSwitch": true, 21 + "noUncheckedSideEffectImports": true 22 + }, 23 + "include": ["vite.config.ts"] 24 + }
+11
vite.config.ts
··· 1 + import { defineConfig } from "vite"; 2 + import { svelte } from "@sveltejs/vite-plugin-svelte"; 3 + import { themePlugin } from "./theming"; 4 + 5 + // https://vite.dev/config/ 6 + export default defineConfig({ 7 + plugins: [ 8 + themePlugin(), 9 + svelte(), 10 + ], 11 + });