├── .dockerignore ├── .npmrc ├── static ├── logo.png ├── qr │ ├── UPI.png │ ├── Bitcoin.png │ ├── Litecoin.png │ └── Monero.png ├── favicon.png ├── icons │ ├── mailu.png │ ├── rimgo.png │ ├── akkoma.png │ ├── nitter.png │ ├── pubnix.png │ ├── teddit.png │ ├── vikunja.png │ ├── librarian.png │ ├── libreddit.png │ ├── plausible.png │ ├── safetwitch.png │ ├── libretranslate.png │ ├── anonymousoverflow.png │ ├── hyperpipe.svg │ ├── cinny.svg │ ├── hydrogen.svg │ ├── kbin.svg │ ├── matrix.svg │ ├── element.svg │ ├── searxng.svg │ ├── FreshRSS-logo.svg │ ├── gitea.svg │ ├── xmpp.svg │ ├── authentik.svg │ ├── ente.svg │ ├── hedgedoc.svg │ ├── invidious.svg │ ├── healthchecks.svg │ ├── rssbridge-short.svg │ ├── breezewiki.svg │ ├── piped.svg │ ├── gothub.svg │ ├── jitsi.svg │ ├── owncloud.svg │ ├── simplelogin.svg │ ├── nextcloud.svg │ ├── mozhi.svg │ ├── shoelace.svg │ └── vaultwarden.svg ├── JetBrainsMono.woff2 └── logo.svg ├── src ├── lib │ ├── BlogCard │ │ ├── PostsContainer.svelte │ │ ├── ReadMore.svelte │ │ ├── PostContent.svelte │ │ ├── SingleWordLists.svelte │ │ ├── PostOuter.svelte │ │ ├── index.ts │ │ ├── Title.svelte │ │ └── Meta.svelte │ ├── PMargin.svelte │ ├── Nav │ │ ├── Logo.svelte │ │ ├── Link.svelte │ │ ├── ThemeToggle.svelte │ │ └── Nav.svelte │ ├── PageTransition.svelte │ ├── Footer.svelte │ └── Hero.svelte ├── routes │ ├── team │ │ ├── +page.ts │ │ ├── Team.json │ │ └── +page.svelte │ ├── contact │ │ ├── +page.ts │ │ └── +page.svelte │ ├── donate │ │ ├── +page.ts │ │ ├── CryptoInfo.svelte │ │ └── +page.svelte │ ├── pubnix │ │ ├── faq │ │ │ ├── +page.ts │ │ │ └── +page.svelte │ │ ├── +page.server.ts │ │ ├── users │ │ │ ├── +page.server.ts │ │ │ └── +page.svelte │ │ ├── +page.svelte │ │ ├── User.svelte │ │ └── register │ │ │ ├── +page.server.ts │ │ │ └── +page.svelte │ ├── legal │ │ ├── tos │ │ │ ├── +page.ts │ │ │ └── +page.svelte │ │ ├── privacy-policy │ │ │ ├── +page.ts │ │ │ └── +page.svelte │ │ ├── +page.ts │ │ └── +page.svelte │ ├── +layout.ts │ ├── +error.svelte │ ├── instances │ │ ├── advanced │ │ │ ├── +page.server.ts │ │ │ └── +page.svelte │ │ ├── +page.server.ts │ │ └── +page.svelte │ ├── blog │ │ ├── +page.server.ts │ │ ├── tags │ │ │ ├── +page.server.ts │ │ │ ├── +page.svelte │ │ │ └── [tag] │ │ │ │ ├── +page.svelte │ │ │ │ └── +page.server.ts │ │ ├── authors │ │ │ ├── +page.server.ts │ │ │ ├── +page.svelte │ │ │ └── [author] │ │ │ │ ├── +page.svelte │ │ │ │ └── +page.server.ts │ │ ├── fetchGhost.ts │ │ ├── [title] │ │ │ ├── +page.server.ts │ │ │ └── +page.svelte │ │ └── +page.svelte │ ├── +page.server.ts │ ├── +layout.svelte │ └── +page.svelte ├── app.d.ts ├── stores.ts ├── app.html ├── app.css └── hooks.server.ts ├── .gitignore ├── vite.config.ts ├── Dockerfile ├── .prettierignore ├── .prettierrc ├── compose.yml ├── svelte.config.js ├── tsconfig.json ├── flake.nix ├── .github └── workflows │ ├── docker-dev.yml │ └── docker.yml ├── LICENSE ├── uno.config.ts ├── package.json ├── flake.lock └── README.md /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/logo.png -------------------------------------------------------------------------------- /static/qr/UPI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/qr/UPI.png -------------------------------------------------------------------------------- /static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/favicon.png -------------------------------------------------------------------------------- /static/icons/mailu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/icons/mailu.png -------------------------------------------------------------------------------- /static/icons/rimgo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/icons/rimgo.png -------------------------------------------------------------------------------- /static/qr/Bitcoin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/qr/Bitcoin.png -------------------------------------------------------------------------------- /static/qr/Litecoin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/qr/Litecoin.png -------------------------------------------------------------------------------- /static/qr/Monero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/qr/Monero.png -------------------------------------------------------------------------------- /static/icons/akkoma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/icons/akkoma.png -------------------------------------------------------------------------------- /static/icons/nitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/icons/nitter.png -------------------------------------------------------------------------------- /static/icons/pubnix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/icons/pubnix.png -------------------------------------------------------------------------------- /static/icons/teddit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/icons/teddit.png -------------------------------------------------------------------------------- /static/icons/vikunja.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/icons/vikunja.png -------------------------------------------------------------------------------- /src/lib/BlogCard/PostsContainer.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /static/JetBrainsMono.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/JetBrainsMono.woff2 -------------------------------------------------------------------------------- /static/icons/librarian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/icons/librarian.png -------------------------------------------------------------------------------- /static/icons/libreddit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/icons/libreddit.png -------------------------------------------------------------------------------- /static/icons/plausible.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/icons/plausible.png -------------------------------------------------------------------------------- /static/icons/safetwitch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/icons/safetwitch.png -------------------------------------------------------------------------------- /static/icons/libretranslate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/icons/libretranslate.png -------------------------------------------------------------------------------- /static/icons/anonymousoverflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectSegfault/website/HEAD/static/icons/anonymousoverflow.png -------------------------------------------------------------------------------- /src/routes/team/+page.ts: -------------------------------------------------------------------------------- 1 | import type { PageLoad } from "./$types"; 2 | 3 | export const load = (() => { 4 | return { 5 | title: "Team" 6 | }; 7 | }) satisfies PageLoad; 8 | -------------------------------------------------------------------------------- /src/lib/PMargin.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |

7 | 8 |

9 | -------------------------------------------------------------------------------- /src/routes/contact/+page.ts: -------------------------------------------------------------------------------- 1 | import type { PageLoad } from "./$types"; 2 | 3 | export const load = (() => { 4 | return { 5 | title: "Contact" 6 | }; 7 | }) satisfies PageLoad; 8 | -------------------------------------------------------------------------------- /src/routes/donate/+page.ts: -------------------------------------------------------------------------------- 1 | import type { PageLoad } from "./$types"; 2 | 3 | export const load = (() => { 4 | return { 5 | title: "Donate" 6 | }; 7 | }) satisfies PageLoad; 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | vite.config.js.timestamp-* 10 | vite.config.ts.timestamp-* 11 | -------------------------------------------------------------------------------- /src/routes/pubnix/faq/+page.ts: -------------------------------------------------------------------------------- 1 | import type { PageLoad } from "./$types"; 2 | 3 | export const load = (() => { 4 | return { 5 | title: "Pubnix FAQ" 6 | }; 7 | }) satisfies PageLoad; 8 | -------------------------------------------------------------------------------- /src/routes/legal/tos/+page.ts: -------------------------------------------------------------------------------- 1 | import type { PageLoad } from "./$types"; 2 | 3 | export const load = (() => { 4 | return { 5 | title: "Terms of service" 6 | }; 7 | }) satisfies PageLoad; 8 | -------------------------------------------------------------------------------- /src/routes/+layout.ts: -------------------------------------------------------------------------------- 1 | import type { LayoutLoad } from "./$types"; 2 | 3 | export const load = (async ({ url: { pathname } }) => { 4 | return { 5 | pathname 6 | }; 7 | }) satisfies LayoutLoad; 8 | -------------------------------------------------------------------------------- /src/routes/legal/privacy-policy/+page.ts: -------------------------------------------------------------------------------- 1 | import type { PageLoad } from "./$types"; 2 | 3 | export const load = (() => { 4 | return { 5 | title: "Privacy policy" 6 | }; 7 | }) satisfies PageLoad; 8 | -------------------------------------------------------------------------------- /src/routes/+error.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |

6 | {$page.status} 7 |

{$page.error?.message}

8 |

9 | -------------------------------------------------------------------------------- /src/lib/BlogCard/ReadMore.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | {post.plaintext.split(" ").slice(0, 20).join(" ") + "..."} 6 | Read more... 7 | -------------------------------------------------------------------------------- /src/lib/Nav/Logo.svelte: -------------------------------------------------------------------------------- 1 | 5 | Project Segfault logo 10 | Project Segfault 12 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from "@sveltejs/kit/vite"; 2 | import unoCSS from "unocss/vite"; 3 | import type { UserConfig } from "vite"; 4 | 5 | const config: UserConfig = { 6 | plugins: [sveltekit(), unoCSS()] 7 | }; 8 | 9 | export default config; 10 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18-alpine 2 | 3 | WORKDIR /usr/src/app 4 | 5 | COPY package.json ./ 6 | COPY pnpm-lock.yaml ./ 7 | 8 | RUN npm install -g pnpm 9 | 10 | RUN pnpm i 11 | 12 | COPY . . 13 | 14 | RUN pnpm build 15 | 16 | EXPOSE 3000 17 | 18 | CMD ["node", "build/index.js"] -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | 15 | # Ignore NixOS flake lock 16 | flake.lock 17 | -------------------------------------------------------------------------------- /src/routes/legal/+page.ts: -------------------------------------------------------------------------------- 1 | import type { PageLoad } from "./$types"; 2 | 3 | export const load = (() => { 4 | return { 5 | title: "Boring legal stuff", 6 | description: 7 | "These are some documents concerning transparency, privacy and safety." 8 | }; 9 | }) satisfies PageLoad; 10 | -------------------------------------------------------------------------------- /src/routes/instances/advanced/+page.server.ts: -------------------------------------------------------------------------------- 1 | import instances from "../instances"; 2 | import type { PageServerLoad } from "./$types"; 3 | 4 | export const load = (() => { 5 | const meta = { 6 | title: "Instances" 7 | }; 8 | 9 | return { instances, ...meta }; 10 | }) satisfies PageServerLoad; 11 | -------------------------------------------------------------------------------- /src/lib/PageTransition.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | {#key pathname} 7 |
11 | 12 |
13 | {/key} 14 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 4, 3 | "useTabs": true, 4 | "bracketSpacing": true, 5 | "singleAttributePerLine": true, 6 | "trailingComma": "none", 7 | "plugins": ["prettier-plugin-svelte"], 8 | "pluginSearchDirs": ["."], 9 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] 10 | } 11 | -------------------------------------------------------------------------------- /src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | // and what to do when importing types 4 | declare global { 5 | namespace App { 6 | // interface Error {} 7 | // interface Locals {} 8 | // interface PageData {} 9 | // interface Platform {} 10 | } 11 | } 12 | 13 | export {}; 14 | -------------------------------------------------------------------------------- /src/lib/BlogCard/PostContent.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 | {#if data.post.feature_image} 7 | {data.post.title} image 12 | {/if} 13 | {@html data.post.html} 14 |
15 | -------------------------------------------------------------------------------- /src/lib/BlogCard/SingleWordLists.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |
7 | {#each items as item} 8 | {item.name} 12 | {/each} 13 |
14 | -------------------------------------------------------------------------------- /src/routes/blog/+page.server.ts: -------------------------------------------------------------------------------- 1 | import type { PageServerLoad } from "./$types"; 2 | import { blogPosts } from "../../stores"; 3 | import { get } from "svelte/store"; 4 | 5 | export const load = (async () => { 6 | const meta = { 7 | title: "Blog" 8 | }; 9 | 10 | return { 11 | posts: get(blogPosts), 12 | ...meta 13 | }; 14 | }) satisfies PageServerLoad; 15 | -------------------------------------------------------------------------------- /src/routes/blog/tags/+page.server.ts: -------------------------------------------------------------------------------- 1 | import type { PageServerLoad } from "./$types"; 2 | import fetchGhost from "../fetchGhost"; 3 | 4 | export const load = (async () => { 5 | const data = await fetchGhost("tags"); 6 | 7 | const meta = { 8 | title: "Blog tags" 9 | }; 10 | 11 | return { 12 | tags: data, 13 | ...meta 14 | }; 15 | }) satisfies PageServerLoad; 16 | -------------------------------------------------------------------------------- /src/routes/pubnix/+page.server.ts: -------------------------------------------------------------------------------- 1 | import type { PageServerLoad } from "./$types"; 2 | import { pubnixUsers } from "../../stores"; 3 | import { get } from "svelte/store"; 4 | 5 | export const load = (async () => { 6 | const meta = { 7 | title: "Pubnix" 8 | }; 9 | 10 | return { 11 | users: get(pubnixUsers), 12 | ...meta 13 | }; 14 | }) satisfies PageServerLoad; 15 | -------------------------------------------------------------------------------- /compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | website: 3 | container_name: website 4 | image: ghcr.io/projectsegfault/website:latest 5 | restart: unless-stopped 6 | # uncomment these lines if you want to build from source 7 | #build: 8 | # context: . 9 | # dockerfile: Dockerfile 10 | ports: 11 | - "127.0.0.1:1339:3000" 12 | -------------------------------------------------------------------------------- /src/lib/BlogCard/PostOuter.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |
9 | 10 | 11 | {#if url} 12 | View on Ghost 16 | {/if} 17 |
18 | -------------------------------------------------------------------------------- /src/routes/pubnix/users/+page.server.ts: -------------------------------------------------------------------------------- 1 | import type { PageServerLoad } from "./$types"; 2 | import { pubnixUsers } from "../../../stores"; 3 | import { get } from "svelte/store"; 4 | 5 | export const load = (async () => { 6 | const meta = { 7 | title: "Pubnix users" 8 | }; 9 | 10 | return { 11 | users: get(pubnixUsers), 12 | ...meta 13 | }; 14 | }) satisfies PageServerLoad; 15 | -------------------------------------------------------------------------------- /src/stores.ts: -------------------------------------------------------------------------------- 1 | import { writable, type Writable } from "svelte/store"; 2 | 3 | export const announcements: Writable<{}> = writable({}); 4 | 5 | export const pubnixUsers: Writable<{}> = writable({}); 6 | 7 | export const blogPosts: Writable<{}> = writable({}); 8 | 9 | export const blogTags: Writable<{}> = writable({}); 10 | 11 | export const blogAuthors: Writable<{}> = writable({}); 12 | -------------------------------------------------------------------------------- /src/routes/blog/authors/+page.server.ts: -------------------------------------------------------------------------------- 1 | import type { PageServerLoad } from "./$types"; 2 | import fetchGhost from "../fetchGhost"; 3 | 4 | export const load = (async ({ fetch }) => { 5 | const data = await fetchGhost("authors"); 6 | 7 | const meta = { 8 | title: "Blog authors" 9 | }; 10 | 11 | return { 12 | authors: data, 13 | ...meta 14 | }; 15 | }) satisfies PageServerLoad; 16 | -------------------------------------------------------------------------------- /src/routes/blog/tags/+page.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |

{data.title}

9 | 10 | {#if !data.tags.error} 11 | 15 | {:else} 16 |

{data.tags.message}

17 | {/if} 18 | -------------------------------------------------------------------------------- /src/routes/blog/authors/+page.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |

{data.title}

9 | 10 | {#if !data.authors.error} 11 | 15 | {:else} 16 |

{data.authors.message}

17 | {/if} 18 | -------------------------------------------------------------------------------- /src/routes/+page.server.ts: -------------------------------------------------------------------------------- 1 | import type { PageServerLoad } from "./$types"; 2 | import { announcements } from "../stores"; 3 | import { get } from "svelte/store"; 4 | 5 | export const load = (async () => { 6 | const meta = { 7 | title: "Home", 8 | description: "Open-source development and hosted services." 9 | }; 10 | 11 | return { 12 | announcements: get(announcements), 13 | ...meta 14 | }; 15 | }) satisfies PageServerLoad; 16 | -------------------------------------------------------------------------------- /src/lib/Footer.svelte: -------------------------------------------------------------------------------- 1 |
2 |
5 |

6 | Made with SvelteKit 7 |

8 | 9 | Source code 10 |
11 |
12 | -------------------------------------------------------------------------------- /svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from "@sveltejs/adapter-node"; 2 | import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors 7 | // for more information about preprocessors 8 | preprocess: vitePreprocess(), 9 | 10 | kit: { 11 | adapter: adapter() 12 | } 13 | }; 14 | 15 | export default config; 16 | -------------------------------------------------------------------------------- /src/lib/BlogCard/index.ts: -------------------------------------------------------------------------------- 1 | export { default as PostsContainer } from "./PostsContainer.svelte"; 2 | export { default as PostOuter } from "./PostOuter.svelte"; 3 | export { default as Title } from "./Title.svelte"; 4 | export { default as Meta } from "./Meta.svelte"; 5 | export { default as ReadMore } from "./ReadMore.svelte"; 6 | export { default as PostContent } from "./PostContent.svelte"; 7 | export { default as SingleWordLists } from "./SingleWordLists.svelte"; 8 | -------------------------------------------------------------------------------- /static/icons/hyperpipe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/routes/instances/+page.server.ts: -------------------------------------------------------------------------------- 1 | import instances from "./instances"; 2 | import type { PageServerLoad } from "./$types"; 3 | 4 | export const load = (({ url }) => { 5 | const meta = { 6 | title: "Instances" 7 | }; 8 | 9 | // If the ?short url query exists, then longUrl is false 10 | // Every other case is true 11 | const queryLongUrl = !url.searchParams.has("short"); 12 | 13 | return { 14 | instances, 15 | queryLongUrl, 16 | ...meta 17 | }; 18 | }) satisfies PageServerLoad; 19 | -------------------------------------------------------------------------------- /src/routes/blog/fetchGhost.ts: -------------------------------------------------------------------------------- 1 | import { fetchGhost as func } from "../../hooks.server"; 2 | 3 | const fetchGhost = async (action: string, additional?: string) => { 4 | try { 5 | const request = await func(action, additional); 6 | 7 | if (request.status === 200) { 8 | return request.data; 9 | } else { 10 | return { error: true, message: "Error: " + request.status }; 11 | } 12 | } catch (err) { 13 | return { error: true, message: "Error: " + err }; 14 | } 15 | }; 16 | 17 | export default fetchGhost; 18 | -------------------------------------------------------------------------------- /src/lib/BlogCard/Title.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | {#if !isPost} 7 | {#if post.feature_image} 8 | {post.title} image 13 | {/if} 14 | {post.title} 19 | {:else} 20 | {post.title} 21 | {/if} 22 | -------------------------------------------------------------------------------- /src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 13 | 18 | %sveltekit.head% 19 | 20 | 21 |
%sveltekit.body%
22 | 23 | 24 | -------------------------------------------------------------------------------- /src/lib/Nav/Link.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 20 | {#if link.icon} 21 |
22 | {/if} 23 | {link.text} 24 | 25 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true 12 | } 13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 14 | // 15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 16 | // from the referenced tsconfig.json - TypeScript does not merge them in 17 | } 18 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs.nixpkgs.url = "github:NixOS/nixpkgs/master"; 3 | inputs.systems.url = "github:nix-systems/default"; 4 | 5 | outputs = { 6 | self, 7 | nixpkgs, 8 | flake-utils, 9 | systems, 10 | }: 11 | flake-utils.lib.eachSystem (import systems) 12 | (system: let 13 | pkgs = import nixpkgs { 14 | inherit system; 15 | }; 16 | in { 17 | devShells.default = pkgs.mkShell { 18 | buildInputs = [ 19 | pkgs.nodejs 20 | 21 | # Package manager 22 | pkgs.nodePackages.pnpm 23 | ]; 24 | }; 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /src/routes/pubnix/users/+page.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |

{data.title}

9 | 10 | {#if !data.users.error} 11 | {#if data.users.users.length > 0} 12 |

13 | There are {data.users.users.length} users on the pubnix. 14 |

15 |
16 | {#each data.users.users as user} 17 | 18 | {/each} 19 |
20 | {:else} 21 |

No users

22 | {/if} 23 | {:else} 24 |

{data.users.message}

25 | {/if} 26 | -------------------------------------------------------------------------------- /src/routes/blog/tags/[tag]/+page.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |

Blog tag {data.tagName}

15 | 16 | {#if !data.posts.error} 17 | 18 | {#each data.posts.posts as post} 19 | 20 | 21 | <Meta {post} /> 22 | <ReadMore {post} /> 23 | </PostOuter> 24 | {/each} 25 | </PostsContainer> 26 | {:else} 27 | <p>{data.posts.message}</p> 28 | {/if} 29 | -------------------------------------------------------------------------------- /src/routes/donate/CryptoInfo.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | export let name: string = ""; 3 | export let address: string = ""; 4 | export let qr: string = ""; 5 | </script> 6 | 7 | {#if address} 8 | <details class="p-0"> 9 | <summary>Address</summary> 10 | <code class="break-words whitespace-normal">{address}</code> 11 | </details> 12 | {/if} 13 | 14 | {#if qr} 15 | <details class="p-0"> 16 | <summary>QR code</summary> 17 | <a 18 | href="/qr/{qr}" 19 | target="_blank" 20 | rel="noreferrer" 21 | > 22 | <img 23 | src="/qr/{qr}" 24 | alt="QR code to {name} address" 25 | class="mt-2" 26 | /> 27 | </a> 28 | </details> 29 | {/if} 30 | -------------------------------------------------------------------------------- /src/routes/blog/authors/[author]/+page.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import type { PageData } from "./$types"; 3 | export let data: PageData; 4 | 5 | import { 6 | PostsContainer, 7 | PostOuter, 8 | Title, 9 | Meta, 10 | ReadMore 11 | } from "$lib/BlogCard"; 12 | </script> 13 | 14 | <h1>Blog author <span class="text-accent">{data.authorName}</span></h1> 15 | 16 | {#if !data.posts.error} 17 | <PostsContainer> 18 | {#each data.posts.posts as post} 19 | <PostOuter> 20 | <Title {post} /> 21 | <Meta {post} /> 22 | <ReadMore {post} /> 23 | </PostOuter> 24 | {/each} 25 | </PostsContainer> 26 | {:else} 27 | <p>{data.posts.message}</p> 28 | {/if} 29 | -------------------------------------------------------------------------------- /src/routes/blog/tags/[tag]/+page.server.ts: -------------------------------------------------------------------------------- 1 | import type { PageServerLoad } from "./$types"; 2 | import fetchGhost from "../../fetchGhost"; 3 | 4 | export const load = (async ({ params, fetch }) => { 5 | const data = await fetchGhost("posts", "&filter=tags:" + params.tag); 6 | 7 | const tagsLoop = !data.error 8 | ? data.posts[0].tags.map((tag: { slug: string; name: any }) => { 9 | if (tag.slug === params.tag) { 10 | return tag.name; 11 | } 12 | }) 13 | : []; 14 | 15 | const tagName = tagsLoop.filter((tag: any) => tag !== undefined)[0]; 16 | 17 | const meta = { 18 | title: "Blog tag " + tagName 19 | }; 20 | 21 | return { 22 | posts: data, 23 | tagName: tagName, 24 | ...meta 25 | }; 26 | }) satisfies PageServerLoad; 27 | -------------------------------------------------------------------------------- /src/routes/blog/[title]/+page.server.ts: -------------------------------------------------------------------------------- 1 | import type { PageServerLoad, PageServerLoadEvent } from "./$types"; 2 | import { blogPosts } from "../../../stores"; 3 | import { get } from "svelte/store"; 4 | 5 | // yes this was made by gitbub copilot 6 | 7 | const load: PageServerLoad = async ({ params }: PageServerLoadEvent) => { 8 | const allPosts = get(blogPosts) as { error?: boolean; posts?: any[] }; 9 | let post: any = {}; 10 | let title = ""; 11 | if (allPosts && !allPosts.error && Array.isArray(allPosts.posts)) { 12 | post = allPosts.posts.find((p: any) => p.slug === params.title) || {}; 13 | title = post.title || ""; 14 | } 15 | return { 16 | post, 17 | allPosts, 18 | title 19 | }; 20 | }; 21 | 22 | export { load }; 23 | -------------------------------------------------------------------------------- /src/lib/Hero.svelte: -------------------------------------------------------------------------------- 1 | <div class="flex flex-col gap-6 items-center text-center mt-[7%]"> 2 | <h1 class="text-5xl font-extrabold text-accent my-0 border-b-0 pb-0"> 3 | Project Segfault 4 | </h1> 5 | <p class="text-2xl text-text"> 6 | Open-source development and hosted services. 7 | </p> 8 | <div class="flex gap-4 flex-col w-full sm:(flex-row justify-center)"> 9 | <a 10 | href="/instances" 11 | class="button" 12 | ><div class="i-ic:outline-computer" /> 13 | Instances</a 14 | > 15 | <a 16 | href="/donate" 17 | class="button !bg-amber !text-black" 18 | ><div class="i-ic:outline-attach-money" /> 19 | Donate</a 20 | > 21 | <a 22 | href="/pubnix" 23 | class="button !bg-purple" 24 | ><div class="i-simple-icons:linux" /> 25 | Pubnix</a 26 | > 27 | </div> 28 | </div> 29 | -------------------------------------------------------------------------------- /src/routes/blog/authors/[author]/+page.server.ts: -------------------------------------------------------------------------------- 1 | import type { PageServerLoad } from "./$types"; 2 | import fetchGhost from "../../fetchGhost"; 3 | 4 | export const load = (async ({ params, fetch }) => { 5 | const data = await fetchGhost("posts", "&filter=author:" + params.author); 6 | 7 | const authorsLoop = !data.error 8 | ? data.posts[0].authors.map((author: { slug: string; name: any }) => { 9 | if (author.slug === params.author) { 10 | return author.name; 11 | } 12 | }) 13 | : []; 14 | 15 | const authorName = authorsLoop.filter((tag: any) => tag !== undefined)[0]; 16 | 17 | const meta = { 18 | title: "Blog author " + authorName, 19 | description: "Blog posts by " + authorName 20 | }; 21 | 22 | return { 23 | posts: data, 24 | authorName, 25 | ...meta 26 | }; 27 | }) satisfies PageServerLoad; 28 | -------------------------------------------------------------------------------- /src/lib/Nav/ThemeToggle.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { afterUpdate } from "svelte"; 3 | import DarkMode from "svelte-dark-mode"; 4 | 5 | let theme: "dark" | "light"; 6 | 7 | afterUpdate(() => { 8 | document.documentElement.className = theme; 9 | }); 10 | 11 | let toggle = () => { 12 | theme = theme === "dark" ? "light" : "dark"; 13 | }; 14 | </script> 15 | 16 | <DarkMode bind:theme /> 17 | 18 | <button 19 | on:click={toggle} 20 | class="theme-toggle button text-text flex items-center text-sm navPlus1:!p-x-[.25rem]" 21 | aria-label="Toggle theme" 22 | > 23 | <div 24 | class="i-ic:{theme === 'dark' 25 | ? 'outline-light-mode' 26 | : 'outline-dark-mode'} h-4 w-4" 27 | /> 28 | <span class="navPlus1:(hidden)">Toggle theme</span> 29 | </button> 30 | 31 | <style> 32 | .theme-toggle:hover { 33 | @apply brightness-70; 34 | } 35 | </style> 36 | -------------------------------------------------------------------------------- /static/icons/cinny.svg: -------------------------------------------------------------------------------- 1 | <!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In --> 2 | <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" x="0px" y="0px" width="18px" height="18px" viewBox="0 0 18 18" enable-background="new 0 0 18 18" xml:space="preserve"> 3 | <defs> 4 | </defs> 5 | <g> 6 | <g> 7 | <circle fill="#FFFFFF" cx="9" cy="9" r="8.5"/> 8 | </g> 9 | <g> 10 | <path d="M9,0C4,0,0,4,0,9c0,5,4,9,9,9c5,0,9-4,9-9C18,4,14,0,9,0z M1.2,10.8l3.5-2.3c0-0.1,0-0.2,0-0.3c0-1.8,1.3-3.2,3.1-3.4 c0.1,0,0.2,0,0.4,0c1.2,0,2.3,0.6,2.9,1.6c0.3-0.1,0.6-0.1,0.9-0.1c0.4,0,0.8,0,1.2,0.1c0.7,0.2,1.4,0.5,2,0.9 C14.6,7.1,14,7,13.3,7c-1.2,0-2.2,0.4-2.9,1.4c-0.7,0.9-1.1,2-1.1,3.2c0,1.5-0.4,2.9-1.3,4.2c-0.3,0.4-0.5,0.7-0.8,1 C4.2,16.1,1.9,13.8,1.2,10.8z"/> 11 | <circle cx="9.5" cy="6.4" r="0.5"/> 12 | </g> 13 | </g> 14 | </svg> -------------------------------------------------------------------------------- /static/icons/hydrogen.svg: -------------------------------------------------------------------------------- 1 | <svg width="384" height="384" viewBox="0 0 384 384" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <path fill-rule="evenodd" clip-rule="evenodd" d="M64.1212 192C64.1212 121.375 121.375 64.1212 192 64.1212C219.695 64.1212 245.333 72.9249 266.269 87.8864C264.331 92.1063 263.25 96.8018 263.25 101.75C263.25 120.113 278.136 135 296.5 135C299.74 135 302.871 134.536 305.832 133.672C314.811 151.161 319.879 170.989 319.879 192C319.879 262.626 262.626 319.879 192 319.879C121.375 319.879 64.1212 262.626 64.1212 192ZM320.589 124.669C331.148 144.792 337.121 167.698 337.121 192C337.121 272.148 272.148 337.121 192 337.121C111.852 337.121 46.8792 272.148 46.8792 192C46.8792 111.852 111.852 46.8792 192 46.8792C223.884 46.8792 253.367 57.1615 277.313 74.5912C282.733 70.7544 289.353 68.4998 296.5 68.4998C314.863 68.4998 329.75 83.3863 329.75 101.75C329.75 110.634 326.266 118.704 320.589 124.669Z" fill="#0DBD8B"/> 3 | <circle cx="192" cy="192" r="85.5" fill="#0DBD8B"/> 4 | </svg> -------------------------------------------------------------------------------- /src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import "uno.css"; 3 | import "@unocss/reset/tailwind.css"; 4 | import "../app.css"; 5 | 6 | import Nav from "$lib/Nav/Nav.svelte"; 7 | import Footer from "$lib/Footer.svelte"; 8 | import { page } from "$app/stores"; 9 | import PageTransition from "$lib/PageTransition.svelte"; 10 | import type { LayoutData } from "./$types"; 11 | 12 | const title = $page.url.pathname.startsWith("/blog") 13 | ? `${$page.data.title} | Project Segfault blog` 14 | : `${$page.data.title} | Project Segfault`; 15 | 16 | export let data: LayoutData; 17 | </script> 18 | 19 | <svelte:head> 20 | <title>{title} 21 | {#if $page.data.description} 22 | 26 | {/if} 27 | 28 | 29 |