diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..581839a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2025 Witchcraft Systems + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 6194e14..d9eb2ea 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,62 @@ # pds-dash -Frontend with stats for your ATProto PDS \ No newline at end of file +a frontend dashboard with stats for your ATProto PDS. + +## setup + +### prerequisites + +- [deno](https://deno.com/manual/getting_started/installation) + +### installing + +clone the repo, install dependencies using deno: + +```sh +deno install +``` + +### development server + +local develompent server with hot reloading: + +```sh +deno task dev +``` + +### building + +to build the optimized bundle run: + +```sh +deno task build +``` + +the output will be in the `dist/` directory. + +## deploying + +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. + +## configuring + +[`config.ts`](config.ts) is the main configuration file, you can find more information in the file itself. + +## theming + +the colors are designated in [`src/app.css`](src/app.css) as variables, go crazy with them + +the rest is done by editing the css files and style tags directly, good luck + +relevant files: + +- [`src/App.svelte`](src/App.svelte) +- [`src/app.css`](src/app.css) +- [`src/lib/AccountComponent.svelte`](src/lib/AccountComponent.svelte) +- [`src/lib/PostComponent.svelte`](src/lib/PostComponent.svelte) + +the favicon is located at [`public/favicon.ico`](public/favicon.ico) + +## license + +MIT diff --git a/config.ts b/config.ts index b8284a6..8d09cf6 100644 --- a/config.ts +++ b/config.ts @@ -2,27 +2,36 @@ * Configuration module for the PDS Dashboard */ export class Config { - /** - * The base URL of the PDS (Personal Data Server) - * @default "https://pds.witchcraft.systems" - */ - static readonly PDS_URL: string = "https://pds.witchcraft.systems"; + /** + * The base URL of the PDS (Personal Data Server) + * @default "https://pds.witchcraft.systems" + */ + static readonly PDS_URL: string = "https://pds.witchcraft.systems"; - /** - * The base URL of the frontend service for linking to replies - * @default "https://deer.social" - */ - static readonly FRONTEND_URL: string = "https://deer.social"; + /** + * The base URL of the frontend service for linking to replies/quotes/accounts etc. + * @default "https://deer.social" + */ + static readonly FRONTEND_URL: string = "https://deer.social"; - /** - * Maximum number of posts to fetch from the PDS per user - * @default 10 - */ - static readonly MAX_POSTS_PER_USER: number = 22; + /** + * Maximum number of posts to fetch from the PDS per request + * Should be around 20 for about 10 users on the pds + * The more users you have, the lower the number should be + * since sorting is slow and is done on the frontend + * @default 20 + */ + static readonly MAX_POSTS: number = 20; - /** - * Footer text for the dashboard - * @default "Astrally projected from witchcraft.systems" - */ - static readonly FOOTER_TEXT: string = "Astrally projected from witchcraft.systems"; -} \ No newline at end of file + /** + * Footer text for the dashboard, you probably want to change this + */ + static readonly FOOTER_TEXT: string = + "Astrally projected from witchcraft.systems

Source (github mirror)"; + + /** + * Whether to show the posts that are in the future + * @default false + */ + static readonly SHOW_FUTURE_POSTS: boolean = false; +} diff --git a/deno.lock b/deno.lock index df8c920..724a5c0 100644 --- a/deno.lock +++ b/deno.lock @@ -6,7 +6,9 @@ "npm:@atcute/identity-resolver@~0.1.2": "0.1.2_@atcute+identity@0.1.3", "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", "npm:@tsconfig/svelte@^5.0.4": "5.0.4", + "npm:moment@^2.30.1": "2.30.1", "npm:svelte-check@^4.1.5": "4.1.6_svelte@5.28.1__acorn@8.14.1_typescript@5.7.3", + "npm:svelte-infinite-loading@^1.4.0": "1.4.0", "npm:svelte@^5.23.1": "5.28.1_acorn@8.14.1", "npm:typescript@~5.7.2": "5.7.3", "npm:vite@^6.3.1": "6.3.2_picomatch@4.0.2" @@ -337,6 +339,9 @@ "@jridgewell/sourcemap-codec" ] }, + "moment@2.30.1": { + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==" + }, "mri@1.2.0": { "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==" }, @@ -411,6 +416,9 @@ "typescript" ] }, + "svelte-infinite-loading@1.4.0": { + "integrity": "sha512-Jo+f/yr/HmZQuIiiKKzAHVFXdAUWHW2RBbrcQTil8JVk1sCm/riy7KTJVzjBgQvHasrFQYKF84zvtc9/Y4lFYg==" + }, "svelte@5.28.1_acorn@8.14.1": { "integrity": "sha512-iOa9WmfNG95lSOSJdMhdjJ4Afok7IRAQYXpbnxhd5EINnXseG0GVa9j6WPght4eX78XfFez45Fi+uRglGKPV/Q==", "dependencies": [ @@ -470,7 +478,9 @@ "npm:@atcute/identity-resolver@~0.1.2", "npm:@sveltejs/vite-plugin-svelte@^5.0.3", "npm:@tsconfig/svelte@^5.0.4", + "npm:moment@^2.30.1", "npm:svelte-check@^4.1.5", + "npm:svelte-infinite-loading@^1.4.0", "npm:svelte@^5.23.1", "npm:typescript@~5.7.2", "npm:vite@^6.3.1" diff --git a/index.html b/index.html index f71d006..adcfab3 100644 --- a/index.html +++ b/index.html @@ -1,4 +1,4 @@ - + diff --git a/package.json b/package.json index 59269d2..1db6461 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,9 @@ "dependencies": { "@atcute/bluesky": "^2.0.2", "@atcute/client": "^3.0.1", - "@atcute/identity-resolver": "^0.1.2" + "@atcute/identity-resolver": "^0.1.2", + "moment": "^2.30.1", + "svelte-infinite-loading": "^1.4.0" }, "devDependencies": { "@sveltejs/vite-plugin-svelte": "^5.0.3", diff --git a/public/vite.svg b/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/App.svelte b/src/App.svelte index 6a635b1..733320e 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -1,48 +1,71 @@
- {#await accountsPromise} -

Loading...

- {:then accountsData} -
-

ATProto PDS

-

Home to {accountsData.length} accounts

-
- {#each accountsData as accountObject} - - {/each} + {#await accountsPromise} +

Loading...

+ {:then accountsData} +
+

ATProto PDS

+

Home to {accountsData.length} accounts

+
+ {#each accountsData as accountObject} + + {/each} +
+

{@html Config.FOOTER_TEXT}

-

{@html Config.FOOTER_TEXT}

-
- {:catch error} -

Error: {error.message}

- {/await} + {:catch error} +

Error: {error.message}

+ {/await} - {#await postsPromise} -

Loading...

- {:then postsData}
- {#each postsData as postObject} + {#each posts as postObject} {/each} +
- {/await}
diff --git a/src/lib/PostComponent.svelte b/src/lib/PostComponent.svelte index 894540d..dc0b874 100644 --- a/src/lib/PostComponent.svelte +++ b/src/lib/PostComponent.svelte @@ -2,6 +2,7 @@ import { Post } from "./pdsfetch"; import { Config } from "../../config"; import { onMount } from "svelte"; + import moment from "moment"; let { post }: { post: Post } = $props(); @@ -76,7 +77,9 @@ {post.timenotstamp}{moment(post.timenotstamp).isBefore(moment().subtract(1, "month")) + ? moment(post.timenotstamp).format("MMM D, YYYY") + : moment(post.timenotstamp).fromNow()}

@@ -110,7 +113,7 @@
@@ -122,7 +125,7 @@
@@ -131,6 +134,7 @@
{/if} {#if post.videosLinkCid} +