├── .dockerignore
├── .github
└── workflows
│ ├── docker-dev.yml
│ └── docker.yml
├── .gitignore
├── .npmrc
├── .prettierignore
├── .prettierrc
├── Dockerfile
├── LICENSE
├── README.md
├── compose.yml
├── flake.lock
├── flake.nix
├── package.json
├── pnpm-lock.yaml
├── src
├── app.css
├── app.d.ts
├── app.html
├── hooks.server.ts
├── lib
│ ├── BlogCard
│ │ ├── Meta.svelte
│ │ ├── PostContent.svelte
│ │ ├── PostOuter.svelte
│ │ ├── PostsContainer.svelte
│ │ ├── ReadMore.svelte
│ │ ├── SingleWordLists.svelte
│ │ ├── Title.svelte
│ │ └── index.ts
│ ├── Footer.svelte
│ ├── Hero.svelte
│ ├── Nav
│ │ ├── Link.svelte
│ │ ├── Logo.svelte
│ │ ├── Nav.svelte
│ │ └── ThemeToggle.svelte
│ ├── PMargin.svelte
│ └── PageTransition.svelte
├── routes
│ ├── +error.svelte
│ ├── +layout.svelte
│ ├── +layout.ts
│ ├── +page.server.ts
│ ├── +page.svelte
│ ├── admin
│ │ ├── +page.svelte
│ │ └── +page.ts
│ ├── blog
│ │ ├── +page.server.ts
│ │ ├── +page.svelte
│ │ ├── [title]
│ │ │ ├── +page.server.ts
│ │ │ └── +page.svelte
│ │ ├── authors
│ │ │ ├── +page.server.ts
│ │ │ ├── +page.svelte
│ │ │ └── [author]
│ │ │ │ ├── +page.server.ts
│ │ │ │ └── +page.svelte
│ │ ├── fetchGhost.ts
│ │ └── tags
│ │ │ ├── +page.server.ts
│ │ │ ├── +page.svelte
│ │ │ └── [tag]
│ │ │ ├── +page.server.ts
│ │ │ └── +page.svelte
│ ├── contact
│ │ ├── +page.svelte
│ │ └── +page.ts
│ ├── donate
│ │ ├── +page.svelte
│ │ ├── +page.ts
│ │ └── CryptoInfo.svelte
│ ├── instances
│ │ ├── +page.server.ts
│ │ ├── +page.svelte
│ │ ├── advanced
│ │ │ ├── +page.server.ts
│ │ │ └── +page.svelte
│ │ └── instances.ts
│ ├── legal
│ │ ├── +page.svelte
│ │ ├── +page.ts
│ │ ├── privacy-policy
│ │ │ ├── +page.svelte
│ │ │ └── +page.ts
│ │ └── tos
│ │ │ ├── +page.svelte
│ │ │ └── +page.ts
│ ├── login
│ │ ├── +page.server.ts
│ │ └── +page.svelte
│ ├── pubnix
│ │ ├── +page.server.ts
│ │ ├── +page.svelte
│ │ ├── User.svelte
│ │ ├── faq
│ │ │ ├── +page.svelte
│ │ │ └── +page.ts
│ │ ├── register
│ │ │ ├── +page.server.ts
│ │ │ └── +page.svelte
│ │ └── users
│ │ │ ├── +page.server.ts
│ │ │ └── +page.svelte
│ └── team
│ │ ├── +page.svelte
│ │ ├── +page.ts
│ │ └── Team.json
└── stores.ts
├── static
├── JetBrainsMono.woff2
├── favicon.png
├── icons
│ ├── FreshRSS-logo.svg
│ ├── akkoma.png
│ ├── anonymousoverflow.png
│ ├── authentik.svg
│ ├── breezewiki.svg
│ ├── cinny.svg
│ ├── cockpit.svg
│ ├── element.svg
│ ├── ente.svg
│ ├── gitea.svg
│ ├── gothub.svg
│ ├── healthchecks.svg
│ ├── hedgedoc.svg
│ ├── hydrogen.svg
│ ├── hyperpipe.svg
│ ├── invidious.svg
│ ├── jitsi.svg
│ ├── kbin.svg
│ ├── librarian.png
│ ├── libreddit.png
│ ├── libretranslate.png
│ ├── mailu.png
│ ├── matrix.svg
│ ├── mozhi.svg
│ ├── nextcloud.svg
│ ├── nitter.png
│ ├── owncloud.svg
│ ├── piped.svg
│ ├── plausible.png
│ ├── pubnix.png
│ ├── rimgo.png
│ ├── rssbridge-short.svg
│ ├── safetwitch.png
│ ├── searxng.svg
│ ├── shoelace.svg
│ ├── simplelogin.svg
│ ├── teddit.png
│ ├── timetagger.svg
│ ├── vaultwarden.svg
│ ├── vikunja.png
│ ├── wikijs.svg
│ └── xmpp.svg
├── logo.png
├── logo.svg
└── qr
│ ├── Bitcoin.png
│ ├── Litecoin.png
│ ├── Monero.png
│ └── UPI.png
├── svelte.config.js
├── tsconfig.json
├── uno.config.ts
└── vite.config.ts
/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/.github/workflows/docker-dev.yml:
--------------------------------------------------------------------------------
1 | name: Docker dev
2 |
3 | on:
4 | push:
5 | branches:
6 | - "dev"
7 |
8 | jobs:
9 | build:
10 | name: "Build"
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Set up QEMU
14 | uses: docker/setup-qemu-action@v2
15 | - name: Set up Docker Buildx
16 | uses: docker/setup-buildx-action@v2
17 |
18 | - name: "Build:checkout"
19 | uses: actions/checkout@v3
20 |
21 | - name: Log in to the Container registry
22 | uses: docker/login-action@v2
23 | with:
24 | registry: ghcr.io
25 | username: ProjectSegfault
26 | password: ${{ secrets.ACCESS_TOKEN }}
27 |
28 | - name: "Build:dockerimage"
29 | uses: docker/build-push-action@v3
30 | with:
31 | tags: ghcr.io/projectsegfault/website:dev
32 | context: "."
33 | push: true
34 | no-cache: true
35 |
--------------------------------------------------------------------------------
/.github/workflows/docker.yml:
--------------------------------------------------------------------------------
1 | name: Docker
2 |
3 | on:
4 | push:
5 | branches:
6 | - "master"
7 |
8 | jobs:
9 | build:
10 | name: "Build"
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Set up QEMU
14 | uses: docker/setup-qemu-action@v2
15 | - name: Set up Docker Buildx
16 | uses: docker/setup-buildx-action@v2
17 |
18 | - name: "Build:checkout"
19 | uses: actions/checkout@v3
20 |
21 | - name: Log in to the Container registry
22 | uses: docker/login-action@v2
23 | with:
24 | registry: ghcr.io
25 | username: ProjectSegfault
26 | password: ${{ secrets.ACCESS_TOKEN }}
27 |
28 | - name: "Build:dockerimage"
29 | uses: docker/build-push-action@v3
30 | with:
31 | tags: ghcr.io/projectsegfault/website:latest
32 | context: "."
33 | push: true
34 | no-cache: true
35 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | engine-strict=true
2 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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"]
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 - present, Project Segfault team
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.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Project Segfault website
2 |
3 | Live at [projectsegfau.lt](https://projectsegfau.lt).
4 |
5 | ## Developing
6 |
7 | > You need a lot of infrastructure to run a complete version of the website including: Ghost CMS deployment and Authentik authentication.
8 |
9 | ### Prerequisites
10 |
11 | - Install [node.js](https://nodejs.org).
12 | - Install [pnpm](https://pnpm.io/).
13 | - Learn [Svelte](https://svelte.dev).
14 | - Add the environment variables from the [environment variables section](#environment-variables).
15 |
16 | ### Running a dev server.
17 |
18 | 1. Clone the repository using `git clone https://github.com/ProjectSegfault/website`.
19 | 2. Change directory into the clone using `cd ./website`.
20 | 3. Install dependencies using `pnpm i`.
21 | 4. Run the dev server using `pnpm dev`.
22 | 5. Open a browser on `http://localhost:5173/` and you should see the website running locally!
23 |
24 | ## Running in production
25 |
26 | In production you can run the website through Docker Compose or locally. We strongly recommend using Docker since it makes everything 10 times easier.
27 |
28 | ### Docker
29 |
30 | First install Docker and Docker Compose on your system (use Linux if you are sane). After that add the environment variables from the [environment variables section](#environment-variables) and run `docker compose up -d` in the directory of the source code (or just the compose.yml file if you aren't building from source). If you are using Portainer (if you aren't, start using it) you should add a new stack in the Stacks section and select the compose file option, then copy the compose.yml file.
31 |
32 | ### Locally
33 |
34 | If you want to run the website locally in production follow the steps in [developing](#developing) but use `node build` instead of `pnpm dev` and expect the website to be in `http://localhost:3000`.
35 |
36 | ## Environment variables
37 |
38 | The website has the following **mandatory** environment variables
39 |
40 | | Name | Description |
41 | | :----------------- | :--------------------------------------------- |
42 | | AUTH_CLIENT_ID | Authentik client ID |
43 | | AUTH_CLIENT_SECRET | Authentik client secret |
44 | | AUTH_ISSUER | Authentication issuer URL |
45 | | AUTH_TRUST_HOST | Your domain |
46 | | AUTH_SECRET | Random 32 char secret |
47 | | GHOST_URL | Your Ghost CMS URL |
48 | | GHOST_API_KEY | Your Ghost CMS API key |
49 | | KUMA_URL | Your Uptime Kuma announcements URL |
50 | | ORIGIN | Your domain |
51 | | ADDRESS_HEADER | Header used to retrieve client IP (Caddy only) |
52 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/flake.lock:
--------------------------------------------------------------------------------
1 | {
2 | "nodes": {
3 | "flake-utils": {
4 | "inputs": {
5 | "systems": "systems"
6 | },
7 | "locked": {
8 | "lastModified": 1689068808,
9 | "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
10 | "owner": "numtide",
11 | "repo": "flake-utils",
12 | "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
13 | "type": "github"
14 | },
15 | "original": {
16 | "id": "flake-utils",
17 | "type": "indirect"
18 | }
19 | },
20 | "nixpkgs": {
21 | "locked": {
22 | "lastModified": 1691209513,
23 | "narHash": "sha256-V8e6wywJ34DgwP4sDSWpHMPx3OC+k1l/xPSQTfdPj5U=",
24 | "owner": "NixOS",
25 | "repo": "nixpkgs",
26 | "rev": "cc0e47cd36a2d6815eba5abf3317e519abd35571",
27 | "type": "github"
28 | },
29 | "original": {
30 | "owner": "NixOS",
31 | "ref": "master",
32 | "repo": "nixpkgs",
33 | "type": "github"
34 | }
35 | },
36 | "root": {
37 | "inputs": {
38 | "flake-utils": "flake-utils",
39 | "nixpkgs": "nixpkgs",
40 | "systems": "systems_2"
41 | }
42 | },
43 | "systems": {
44 | "locked": {
45 | "lastModified": 1681028828,
46 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
47 | "owner": "nix-systems",
48 | "repo": "default",
49 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
50 | "type": "github"
51 | },
52 | "original": {
53 | "owner": "nix-systems",
54 | "repo": "default",
55 | "type": "github"
56 | }
57 | },
58 | "systems_2": {
59 | "locked": {
60 | "lastModified": 1681028828,
61 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
62 | "owner": "nix-systems",
63 | "repo": "default",
64 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
65 | "type": "github"
66 | },
67 | "original": {
68 | "owner": "nix-systems",
69 | "repo": "default",
70 | "type": "github"
71 | }
72 | }
73 | },
74 | "root": "root",
75 | "version": 7
76 | }
77 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "project-segfault-website",
3 | "version": "3.0.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "vite dev",
7 | "build": "vite build",
8 | "preview": "vite preview",
9 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
10 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
11 | "lint": "prettier --plugin-search-dir . --check .",
12 | "format": "prettier --plugin-search-dir . --write ."
13 | },
14 | "devDependencies": {
15 | "@iconify-json/ic": "^1.2.1",
16 | "@iconify-json/simple-icons": "^1.2.11",
17 | "@sveltejs/adapter-node": "^4.0.1",
18 | "@sveltejs/kit": "^2.7.7",
19 | "@types/sanitize-html": "^2.13.0",
20 | "@unocss/reset": "^0.58.9",
21 | "axios": "^1.7.7",
22 | "dayjs": "^1.11.13",
23 | "prettier": "^3.3.3",
24 | "prettier-plugin-svelte": "^3.2.7",
25 | "sanitize-html": "^2.13.1",
26 | "svelte": "^4.2.19",
27 | "svelte-check": "^3.8.6",
28 | "svelte-dark-mode": "^2.1.0",
29 | "tslib": "^2.8.1",
30 | "typescript": "^5.6.3",
31 | "unocss": "^0.58.9",
32 | "vite": "^5.4.10"
33 | },
34 | "type": "module",
35 | "dependencies": {
36 | "@auth/core": "^0.22.0",
37 | "@auth/sveltekit": "^0.8.0",
38 | "@sveltejs/vite-plugin-svelte": "^3.1.2",
39 | "@unocss/extractor-svelte": "^0.58.9",
40 | "joi": "^17.13.3",
41 | "snarkdown": "^2.0.0",
42 | "svelte-hcaptcha": "^0.1.1"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/app.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: "JetBrains Mono";
3 | src: url("/JetBrainsMono.woff2");
4 | font-display: swap;
5 | }
6 |
7 | html,
8 | html.light {
9 | --accent: #00a584;
10 | --accent-translucent: #00a58498;
11 | --font-primary: "JetBrains Mono", monospace;
12 | --primary: #ffffff;
13 | --secondary: #e9e9e9;
14 | --tertiary: #939393;
15 | --text: #444444;
16 | --grey: #cecece;
17 | --alt: #ddd;
18 | --alt-text: #333;
19 | --black: #151515;
20 | --body-text: #666;
21 | color-scheme: light;
22 | }
23 |
24 | html.dark {
25 | --primary: #151515;
26 | --secondary: #1d1d1d;
27 | --tertiary: #353535;
28 | --text: #ffffffde;
29 | --grey: #5454547a;
30 | --alt: #333;
31 | --alt-text: #ddd;
32 | --body-text: #bbb;
33 | color-scheme: dark;
34 | }
35 |
36 | @media (prefers-color-scheme: dark) {
37 | html {
38 | --primary: #151515;
39 | --secondary: #1d1d1d;
40 | --tertiary: #353535;
41 | --text: #ffffffde;
42 | --grey: #5454547a;
43 | --alt: #333;
44 | --alt-text: #ddd;
45 | --body-text: #bbb;
46 | color-scheme: dark;
47 | }
48 | }
49 |
50 | body {
51 | @apply bg-primary text-text font-primary m-0 leading-loose min-h-screen transition-colors duration-200;
52 | }
53 |
54 | ::selection {
55 | @apply bg-accentTranslucent;
56 | }
57 |
58 | a {
59 | @apply text-accent underline underline-offset-4 transition-filter duration-200;
60 | }
61 |
62 | a:hover {
63 | @apply brightness-70;
64 | }
65 |
66 | h1 {
67 | @apply text-4xl font-bold mt-8 mb-2 border-b-2 border-accent pb-2;
68 | }
69 |
70 | .h1-no-lg {
71 | @apply mt-8 mb-2 border-b-2 border-accent pb-2;
72 | }
73 |
74 | h2 {
75 | @apply text-3xl font-bold mt-8 mb-2;
76 | }
77 |
78 | h3 {
79 | @apply text-2xl font-bold mt-8 mb-2;
80 | }
81 |
82 | h4 {
83 | @apply text-xl font-bold mt-8 mb-2;
84 | }
85 |
86 | p {
87 | color: var(--body-text);
88 | }
89 |
90 | /* Between-paragraph spacing */
91 | p + p {
92 | @apply mt-4;
93 | }
94 |
95 | summary {
96 | @apply cursor-pointer;
97 | }
98 |
99 | .button {
100 | @apply px-2 py-1 bg-accent text-primary rounded no-underline flex flex-row items-center gap-2;
101 | }
102 |
--------------------------------------------------------------------------------
/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/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
13 |
18 | %sveltekit.head%
19 |
20 |
21 | %sveltekit.body%
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/hooks.server.ts:
--------------------------------------------------------------------------------
1 | import { SvelteKitAuth } from "@auth/sveltekit";
2 | import Authentik from "@auth/core/providers/authentik";
3 | import { env } from "$env/dynamic/private";
4 | import type { Provider } from "@auth/core/providers";
5 | import type { Profile } from "@auth/core/types";
6 | import { redirect, type Handle } from "@sveltejs/kit";
7 | import { sequence } from "@sveltejs/kit/hooks";
8 | import {
9 | announcements,
10 | pubnixUsers,
11 | blogPosts,
12 | blogTags,
13 | blogAuthors
14 | } from "./stores";
15 | import axios from "axios";
16 | import { Agent } from "https";
17 |
18 | const agent = new Agent({
19 | family: 4
20 | });
21 |
22 | const hasAuth =
23 | !env.AUTH_CLIENT_ID ||
24 | !env.AUTH_CLIENT_SECRET ||
25 | !env.AUTH_ISSUER ||
26 | !env.AUTH_TRUST_HOST ||
27 | !env.AUTH_SECRET
28 | ? false
29 | : true;
30 |
31 | export const handle: Handle = sequence(
32 | //@ts-ignore
33 | SvelteKitAuth({
34 | providers: [
35 | Authentik({
36 | clientId: env.AUTH_CLIENT_ID,
37 | clientSecret: env.AUTH_CLIENT_SECRET,
38 | issuer: env.AUTH_ISSUER
39 | }) as Provider
40 | ]
41 | }),
42 | hasAuth
43 | ? async ({ event, resolve }) => {
44 | if (event.url.pathname.startsWith("/admin")) {
45 | const session = await event.locals.getSession();
46 | if (!session) {
47 | throw redirect(303, "/login");
48 | }
49 | }
50 |
51 | const result = await resolve(event, {
52 | transformPageChunk: ({ html }) => html
53 | });
54 | return result;
55 | }
56 | : async ({ event, resolve }) => {
57 | if (event.url.pathname.startsWith("/admin")) {
58 | throw redirect(303, "/login");
59 | }
60 |
61 | const result = await resolve(event, {
62 | transformPageChunk: ({ html }) => html
63 | });
64 | return result;
65 | }
66 | );
67 |
68 | export const fetchGhost = async (action: string, additional?: string) => {
69 | return await axios(
70 | env.GHOST_URL +
71 | "/ghost/api/content/" +
72 | action +
73 | "/?key=" +
74 | env.GHOST_API_KEY +
75 | "&include=authors,tags&limit=all&formats=html,plaintext" +
76 | additional || "",
77 | { httpsAgent: agent, timeout: 10000 }
78 | );
79 | };
80 |
81 | const updateMap = async () => {
82 | try {
83 | const res = await axios(env.KUMA_URL, {
84 | httpsAgent: agent,
85 | timeout: 10000
86 | });
87 |
88 | if (res.status === 200) {
89 | announcements.set(res.data);
90 | } else {
91 | announcements.set({ error: true, message: "Error: " + res.status });
92 | }
93 | } catch (err) {
94 | announcements.set({ error: true, message: "Error: " + err });
95 | }
96 |
97 | try {
98 | const res = await axios("https://publapi.p.projectsegfau.lt/users", {
99 | httpsAgent: agent,
100 | timeout: 10000
101 | });
102 |
103 | if (res.status === 200) {
104 | pubnixUsers.set(res.data);
105 | } else {
106 | pubnixUsers.set({ error: true, message: "Error: " + res.status });
107 | }
108 | } catch (err) {
109 | pubnixUsers.set({ error: true, message: "Error: " + err });
110 | }
111 |
112 | try {
113 | const res = await fetchGhost("posts");
114 |
115 | if (res.status === 200) {
116 | blogPosts.set(res.data);
117 | } else {
118 | blogPosts.set({ error: true, message: "Error: " + res.status });
119 | }
120 | } catch (err) {
121 | blogPosts.set({ error: true, message: "Error: " + err });
122 | }
123 |
124 | try {
125 | const res = await fetchGhost("tags");
126 |
127 | if (res.status === 200) {
128 | blogTags.set(res.data);
129 | } else {
130 | blogTags.set({ error: true, message: "Error: " + res.status });
131 | }
132 | } catch (err) {
133 | blogTags.set({ error: true, message: "Error: " + err });
134 | }
135 |
136 | try {
137 | const res = await fetchGhost("authors");
138 |
139 | if (res.status === 200) {
140 | blogAuthors.set(res.data);
141 | } else {
142 | blogAuthors.set({ error: true, message: "Error: " + res.status });
143 | }
144 | } catch (err) {
145 | blogAuthors.set({ error: true, message: "Error: " + err });
146 | }
147 | };
148 |
149 | updateMap();
150 |
151 | setInterval(updateMap, 30000);
152 |
--------------------------------------------------------------------------------
/src/lib/BlogCard/Meta.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 | {#if post.tags.length > 0}
10 |
11 |
12 | {#each post.tags as tag}
13 |
{tag.name}
19 | {/each}
20 |
21 | {/if}
22 | {#each post.authors as author}
23 |
27 | {author.name}
29 | {/each}
30 |
32 | {dayjs(post.published_at).format("ddd, DD MMM YYYY HH:mm")}
34 |
36 | {post.plaintext.trim().split(/\s+/).length} words
38 |
40 | {post.reading_time} minute read
42 |
43 |
--------------------------------------------------------------------------------
/src/lib/BlogCard/PostContent.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | {#if data.post.feature_image}
7 |
12 | {/if}
13 | {@html data.post.html}
14 |
15 |
--------------------------------------------------------------------------------
/src/lib/BlogCard/PostOuter.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
9 |
10 |
11 | {#if url}
12 |
View on Ghost
16 | {/if}
17 |
18 |
--------------------------------------------------------------------------------
/src/lib/BlogCard/PostsContainer.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/lib/BlogCard/ReadMore.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 | {post.plaintext.split(" ").slice(0, 20).join(" ") + "..."}
6 | Read more...
7 |
--------------------------------------------------------------------------------
/src/lib/BlogCard/SingleWordLists.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 | {#each items as item}
8 |
{item.name}
12 | {/each}
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/BlogCard/Title.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 | {#if !isPost}
7 | {#if post.feature_image}
8 |
13 | {/if}
14 | {post.title}
19 | {:else}
20 | {post.title}
21 | {/if}
22 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/src/lib/Footer.svelte:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/src/lib/Hero.svelte:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | Open-source development and hosted services.
7 |
8 |
28 |
29 |
--------------------------------------------------------------------------------
/src/lib/Nav/Link.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
20 | {#if link.icon}
21 |
22 | {/if}
23 | {link.text}
24 |
25 |
--------------------------------------------------------------------------------
/src/lib/Nav/Logo.svelte:
--------------------------------------------------------------------------------
1 |
5 |
10 | Project Segfault
12 |
--------------------------------------------------------------------------------
/src/lib/Nav/Nav.svelte:
--------------------------------------------------------------------------------
1 |
76 |
77 |
82 |
83 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | (showMenu = !showMenu)}
95 | aria-label="Toggle menu"
96 | >
97 |
102 |
103 |
104 |
105 |
106 |
126 |
127 |
128 |
129 |
130 |
131 |
137 | {#each links as link}
138 |
139 | {/each}
140 |
141 |
142 |
143 |
148 |
149 |
--------------------------------------------------------------------------------
/src/lib/Nav/ThemeToggle.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 |
23 |
28 | Toggle theme
29 |
30 |
31 |
36 |
--------------------------------------------------------------------------------
/src/lib/PMargin.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/lib/PageTransition.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 | {#key pathname}
7 |
11 |
12 |
13 | {/key}
14 |
--------------------------------------------------------------------------------
/src/routes/+error.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | {$page.status}
7 | {$page.error?.message}
8 |
9 |
--------------------------------------------------------------------------------
/src/routes/+layout.svelte:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 | {title}
21 | {#if $page.data.description}
22 |
26 | {/if}
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/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/+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/routes/+page.svelte:
--------------------------------------------------------------------------------
1 |
29 |
30 |
31 |
32 | {#if !data.announcements.error}
33 | {#if data.announcements.incident}
34 |
35 |
42 | {#if data.announcements.incident.title}
43 |
{data.announcements.incident.title}
46 | {/if}
47 |
48 | {#if data.announcements.incident.content}
49 |
50 | {@html snarkdown(
51 | sanitizeHtml(
52 | data.announcements.incident.content.replace(
53 | /\n/g,
54 | " "
55 | )
56 | )
57 | )}
58 |
59 | {/if}
60 |
61 |
Created - {data.announcements.incident.createdDate}
62 | {#if data.announcements.incident.lastUpdatedDate}
63 |
Updated - {data.announcements.incident.lastUpdatedDate}
65 | UTC
67 | {/if}
68 |
69 |
70 | {/if}
71 | {:else}
72 | {data.announcements.message}
73 | {/if}
74 |
--------------------------------------------------------------------------------
/src/routes/admin/+page.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 | {data.title}
8 | Nothing here yet.
9 |
--------------------------------------------------------------------------------
/src/routes/admin/+page.ts:
--------------------------------------------------------------------------------
1 | import type { PageLoad } from "./$types";
2 |
3 | export const load = (() => {
4 | return {
5 | title: "Admin dashboard"
6 | };
7 | }) satisfies PageLoad;
8 |
--------------------------------------------------------------------------------
/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/+page.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
35 |
36 | {#if !data.posts.error}
37 |
38 | {#each data.posts.posts as post}
39 |
40 |
41 |
42 |
43 |
44 | {/each}
45 |
46 | {:else}
47 | {data.posts.message}
48 | {/if}
49 |
--------------------------------------------------------------------------------
/src/routes/blog/[title]/+page.server.ts:
--------------------------------------------------------------------------------
1 | import type { PageServerLoad } from "./$types";
2 | import fetchGhost from "../fetchGhost";
3 | import { blogPosts } from "../../../stores";
4 | import { get } from "svelte/store";
5 |
6 | export const load = (async ({ params, fetch }) => {
7 | const data = await fetchGhost("posts/slug/" + params.title);
8 |
9 | const allPosts = get(blogPosts);
10 | const meta = {
11 | title: !allPosts.error ? data.posts[0].title : ""
12 | };
13 |
14 | return {
15 | post: !allPosts.error ? data.posts[0] : {},
16 | allPosts: allPosts,
17 | ...meta
18 | };
19 | }) satisfies PageServerLoad;
20 |
--------------------------------------------------------------------------------
/src/routes/blog/[title]/+page.svelte:
--------------------------------------------------------------------------------
1 |
22 |
23 | {#if !data.allPosts.error}
24 |
28 |
29 |
33 |
37 |
38 |
39 |
40 |
41 |
42 | {#if previous}
43 |
44 | Previous post
45 |
46 |
47 |
48 |
49 | {/if}
50 |
51 | {#if next}
52 |
53 | Next post
54 |
55 |
56 |
57 |
58 | {/if}
59 |
60 |
61 |
62 |
67 | {:else}
68 | {data.allPosts.message}
69 | {/if}
70 |
--------------------------------------------------------------------------------
/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/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/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/routes/blog/authors/[author]/+page.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 | Blog author {data.authorName}
15 |
16 | {#if !data.posts.error}
17 |
18 | {#each data.posts.posts as post}
19 |
20 |
21 |
22 |
23 |
24 | {/each}
25 |
26 | {:else}
27 | {data.posts.message}
28 | {/if}
29 |
--------------------------------------------------------------------------------
/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/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/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/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/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 |
22 |
23 |
24 | {/each}
25 |
26 | {:else}
27 | {data.posts.message}
28 | {/if}
29 |
--------------------------------------------------------------------------------
/src/routes/contact/+page.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 | {data.title}
8 |
9 | Matrix
10 |
11 |
12 | We have a Matrix space for general discussion, support and announcements
13 | about Project Segfault over at #project-segfault:projectsegfau.lt .
17 |
18 |
19 | XMPP
20 |
21 |
22 | We have an XMPP MUC for general discussion about Project Segfault over at #general@conference.projectsegfau.lt .
26 |
27 |
28 | Email
29 |
30 |
31 | Our primary email address is contact@projectsegfau.lt . You can use this as a way to send feedback or other stuff to us if you
34 | don't have or don't want to make a Matrix account. When waiting for us to
35 | answer make sure to check your spam, since some email providers block
36 | non-popular domains.
37 |
38 |
39 | We also have a PGP key which you can find on keys.openpgp.org .
43 |
44 |
45 | Members
46 |
47 |
48 | You can contact individual members by using the links provided in the team page .
51 |
52 |
--------------------------------------------------------------------------------
/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.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 | {data.title}
9 |
10 | What we do with donations?
11 |
12 |
13 | These donations primarily help us pay for our VPSes, domain names and other
14 | expenses related to crucial infrastructure we have to maintain. We also
15 | sometimes donate to developers who maintain software we rely heavily on.
16 |
17 |
18 | Donation methods
19 |
20 |
21 | You can currently donate by credit card through Liberapay , UPI (for Indians) and cryptocurrencies.
24 |
25 |
26 | Credit card
27 |
31 | Liberapay
33 |
34 | UPI
35 |
39 |
40 | Cryptocurrencies
41 |
42 | You can use projectsegfau.lt as a
43 | crypto wallet address in supported OpenAlias clients such as
44 | MyMonero ,
45 | Electrum
46 | and Electrum-LTC .
47 |
48 |
49 |
50 |
54 | Monero
55 |
56 |
57 |
62 |
63 |
64 |
68 | Bitcoin
69 |
70 |
71 |
76 |
77 |
78 |
82 | Litecoin
83 |
84 |
85 |
90 |
91 |
96 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/src/routes/donate/CryptoInfo.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 | {#if address}
8 |
9 | Address
10 | {address}
11 |
12 | {/if}
13 |
14 | {#if qr}
15 |
16 | QR code
17 |
22 |
27 |
28 |
29 | {/if}
30 |
--------------------------------------------------------------------------------
/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/instances/+page.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
56 |
57 |
58 | {#if longUrl}
59 | {#each data.instances as category}
60 |
61 |
{category.name}
62 |
82 |
83 | {/each}
84 | {:else}
85 | {#each data.instances as category}
86 |
87 |
{category.name}
88 |
113 |
114 | {/each}
115 | {/if}
116 |
117 |
--------------------------------------------------------------------------------
/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/routes/instances/advanced/+page.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 |
16 |
17 |
18 | {#each data.instances as category}
19 | {#each category.data as instance}
20 |
{instance.name}
21 |
22 | {#if instance.geo}
23 | GeoDNS
24 | {/if}
25 | {#if instance.eu}
26 | EU
27 | {/if}
28 | {#if instance.us}
29 | US
30 | {/if}
31 | {#if instance.in}
32 | IN
33 | {/if}
34 | {#if instance.short_geo}
35 | GeoDNS (Short URL)
36 | {/if}
37 | {#if instance.short_eu}
38 | EU (Short URL)
39 | {/if}
40 | {#if instance.short_us}
41 | US (Short URL)
42 | {/if}
43 | {#if instance.short_in}
44 | IN (Short URL)
45 | {/if}
46 | {#if instance.tor}
47 | Tor
48 | {/if}
49 |
50 | {/each}
51 | {/each}
52 |
53 |
54 |
59 |
--------------------------------------------------------------------------------
/src/routes/legal/+page.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 | {data.title}
9 | {data.description}
10 |
11 |
12 |
21 |
22 | Legal FAQ
23 |
24 | What do I do if a user is disturbing me?
25 |
26 |
27 | If you are being disturbed by a user on our services, then you should
28 | immediately contact us. You can do that by sending us an email
31 | or through our Matrix
32 | support channel .
33 | If you prefer to keep your report private on Matrix, contact one of our team
34 | members directly. You can find their info on our
35 | team page .
36 |
37 |
38 | How can I trust you?
39 |
40 |
41 | We have a privacy policy which outlines how
42 | we collect and handle your data.
43 |
44 |
45 |
50 |
--------------------------------------------------------------------------------
/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/legal/privacy-policy/+page.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 | {data.title}
9 |
10 | We don't collect more information than we need to.
11 |
12 | We have disabled request logging. This is because it is extremely
14 | identifiable. This means that, for example, what website you visited and
15 | what path you visited (like https://libreddit.projectsegfau.lt/r/cats), your
16 | IP address, your User-Agent will not be logged by us!
18 | Some services require us to enable traffic logging, such as Nitter and
20 | Libreddit, This is required to prevent abuse of those proxies who have
21 | recently become harder and harder to proxy due to their active sabotage of
22 | proxies. We also log traffic from all services in order to get a better
23 | understanding of how much traffic we get and how we can improve our
24 | services. Your IP and User-Agent are not logged in this case, we only need
25 | to know how much traffic we get to prioritize our resources.
26 |
27 |
28 | We may occasionally log all traffic for a short period of time in order to
29 | prevent abuse of our services. This is only done when we detect some attack
30 | against our services, The logs are deleted after the attack is over.
31 | Information collected are: IP address, User-Agent, Request path, Request
32 | method, Request body, Request headers, Response status code.
33 |
34 |
35 | If you want the data we've collected on you to be sent, please contact us
37 | on Matrix in this room , or e-mail us at
40 | contact@projectsegfau.lt . You
41 | don't need an account on our Matrix instance in order to chat there, you can
42 | choose from a bunch of public instances or make your own.
44 |
45 | For our website and blog
46 |
47 |
48 | We don't give any of the data we collect to anyone outside of Project
49 | Segfault.
50 |
51 |
52 | What we just described above won't be sold or given to anyone outside of
54 | Project Segfault, except for anonymous analytics like the website. Some data
55 | could be given to law enforcement if they have a warrant.
57 |
58 | There is no reason for anyone outside of Project Segfault to see your data.
60 | In fact, Project Segfault really has no reason to see your data, unless
61 | there's something to suspect.
63 |
64 | Data may be cleared at any point upon request, but...
65 |
66 | There are times when we are unable to delete "your" data because we
68 | sometimes we do not have a concept of "you". If you don't create an account
69 | on the services you use, we have no way to know what data is tied to "you"
70 | as most logs are anonymized.
72 |
73 | Often times you can clear your own data simply by deleting your account.
76 |
77 | As we said, you can request any GDPR/Privacy things in this Matrix room . But, if there's any ongoing investigations and a law enforcement agency
81 | contacts us, we will comply. But, we will only do it if we can verify it's
82 | official and they have a warrant.
84 |
85 | Last updated 25.01.2024 15:30 UTC+1
86 |
--------------------------------------------------------------------------------
/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/legal/tos/+page.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 | {data.title}
9 |
10 |
11 |
12 | Do not use our services to (D)DOS or attempt to disrupt someone else’s
13 | online stability.
14 |
15 | Do not use our services to dox someone.
16 |
17 | Do not do anything on our services that would be illegal in the
18 | USA, Netherlands, and India. (Example: CSAM, Loli, Drugs etc...)
19 |
20 | Do not harass people using our services.
21 |
22 | While we do try to keep your data safe, you have to acknowledge that we
23 | are not responsible if anything unintentional happens (such as data
24 | loss, inability to extract your data due to the server being down or
25 | something else.). It is also your responsibility to keep a backup of
26 | your data if it matters to you.
27 |
28 |
29 | The services provided by Project Segfault are provided as is. We do not
30 | warrant the reliability, accessibility or quality of our services and we
31 | are not responsible for ANY DAMAGES WHATSOEVER by using our services.
32 |
33 |
34 |
35 | If you fail to comply with these terms we will terminate your access to our
37 | services and if you've done something illegal, report you to the police.
39 |
40 | We will only report people to the police if they are using our services to
42 | do something that is morally unacceptable. We will do so without issuing any
43 | warnings.
45 |
--------------------------------------------------------------------------------
/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/login/+page.server.ts:
--------------------------------------------------------------------------------
1 | import { env } from "$env/dynamic/private";
2 | import type { PageServerLoad } from "./$types";
3 |
4 | export const load = (async ({ locals }) => {
5 | const meta = {
6 | title: "Login"
7 | };
8 |
9 | const hasAuth =
10 | !env.AUTH_CLIENT_ID ||
11 | !env.AUTH_CLIENT_SECRET ||
12 | !env.AUTH_ISSUER ||
13 | !env.AUTH_TRUST_HOST ||
14 | !env.AUTH_SECRET
15 | ? false
16 | : true;
17 |
18 | return {
19 | session: hasAuth ? await locals.getSession() : undefined,
20 | hasAuth,
21 | ...meta
22 | };
23 | }) satisfies PageServerLoad;
24 |
--------------------------------------------------------------------------------
/src/routes/login/+page.svelte:
--------------------------------------------------------------------------------
1 |
9 |
10 | {data.title}
11 |
12 | {#if data.hasAuth}
13 | {#if Object.keys($page.data.session || {}).length}
14 |
15 |
16 | Signed in as
17 |
20 |
21 |
Go to admin dashboard
22 |
signOut()}
24 | class={buttonStyles}
25 | >
26 | Sign out
28 |
29 | {:else}
30 |
31 |
You are not signed in
32 |
signIn("authentik")}
34 | class={buttonStyles}
35 | >
36 | Sign in using Authentik
38 |
39 | {/if}
40 | {:else}
41 |
47 | {/if}
48 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/src/routes/pubnix/+page.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
35 |
36 | Online users
37 |
38 | {#if !data.users.error}
39 | {#if data.users.users.some(isOnline)}
40 |
41 | There {onlineUserCount === 1 ? "is" : "are"}
42 | {onlineUserCount}
43 | {onlineUserCount === 1 ? "user" : "users"} online out of {userCount}
44 | users.
45 |
46 |
47 | {#each data.users.users as user}
48 | {#if user.online}
49 |
50 | {/if}
51 | {/each}
52 |
53 | {:else}
54 | No users online
55 | {/if}
56 | {:else}
57 | {data.users.message}
58 | {/if}
59 |
--------------------------------------------------------------------------------
/src/routes/pubnix/User.svelte:
--------------------------------------------------------------------------------
1 |
20 |
21 |
25 |
26 |
29 |
30 |
31 | {#if user.fullName}
32 | {user.fullName} ({user.name})
33 | {:else}
34 | {user.name}
35 | {/if}
36 | {#if user.op}
37 | - Admin
38 | {/if}
39 |
40 | {#if user.desc}
41 |
{user.desc}
42 | {/if}
43 | {#if user.loc}
44 |
{user.loc}
45 | {/if}
46 |
Joined: {dayjs.unix(user.created).format("DD/MM/YYYY")}
49 |
50 |
51 | {#if user.email}
52 |
56 | {/if}
57 |
58 | {#if user.matrix}
59 |
63 | {/if}
64 |
65 | {#if user.fediverse}
66 |
71 | {/if}
72 |
73 | {#if user.website}
74 |
78 | {/if}
79 |
80 | {#if user.capsule}
81 |
Gemini
86 | {/if}
87 |
88 |
89 |
--------------------------------------------------------------------------------
/src/routes/pubnix/faq/+page.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 | {data.title}
8 |
9 | What is a pubnix?
10 | A pubnix is a Unix server provided by a person or a group to the public
12 | with non-commercial recreational goals.
14 | A pubnix is a server running UNIX or a UNIX-like operating system that is
16 | opened to the public.
18 | What can I do on the pubnix?
19 | Quite a lot! You can run containers, set up a website, and learn some
21 | amount of Linux system administration.
23 | How do I get started?
24 | First, you need to register an account .
26 | After registering, you need to wait a while because we manually check each
27 | registration. If you get accepted, you will receive an email.
29 | What are your system's specs?
30 | Guess you'll have to find out. Join today!
31 | I joined, but I have no idea what to do.
32 | No worries! We put out tutorials on how to do common things on our wiki .
37 | Do you have a place to discuss the pubnix?
38 | Yep! We have a Matrix room
42 | and an
43 | XMPP MUC to discuss the pubnix.
48 | 10GB isn't enough for me!
49 | Money doesn't grow on trees :P. To make the project sustainable, we have
51 | decided to make extra storage (upto 30GB) on the Pubnix require at minimum
52 | an yearly donation of 10$ (or equivalent in UPI/Crypto). Once you have
53 | donated, please contact us so we can give you the extra
54 | storage once verified.
56 |
--------------------------------------------------------------------------------
/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/pubnix/register/+page.server.ts:
--------------------------------------------------------------------------------
1 | import type { Actions, PageServerLoad } from "./$types";
2 | import Joi from "joi";
3 | import { fail } from "@sveltejs/kit";
4 |
5 | export const load = (() => {
6 | return {
7 | title: "Pubnix registration"
8 | };
9 | }) satisfies PageServerLoad;
10 |
11 | export const actions: Actions = {
12 | default: async ({ request, fetch, getClientAddress }) => {
13 | const formData = await request.formData();
14 |
15 | const BodyTypeSchema = Joi.object({
16 | username: Joi.string()
17 | .required()
18 | .pattern(/^[a-z_][a-z0-9_]{0,20}$/)
19 | .message("Invalid username ([A-Za-z0-9_])"),
20 | email: Joi.string().email().required(),
21 | ssh: Joi.string()
22 | .required()
23 | .pattern(
24 | /^(ssh-rsa|ssh-ed25519|ecdsa-sha2-nistp256|ecdsa-sha2-nistp384|ecdsa-sha2-nistp521) [A-Za-z0-9+/]+[=]{0,3}( [^@]+@[^@]+)?$/
25 | )
26 | .message("Invalid SSH key"),
27 | ip: Joi.string().required().ip(),
28 | "h-captcha-response": Joi.string().required().messages({
29 | "any.only": "Captcha is required."
30 | })
31 | });
32 |
33 | formData.append("ip", getClientAddress());
34 |
35 | if (
36 | BodyTypeSchema.validate(Object.fromEntries(formData.entries()))
37 | .error
38 | ) {
39 | return fail(400, {
40 | error: true,
41 | message: String(
42 | BodyTypeSchema.validate(
43 | Object.fromEntries(formData.entries())
44 | ).error
45 | )
46 | });
47 | } else {
48 | try {
49 | const request = await fetch(
50 | "https://publapi.p.projectsegfau.lt/signup",
51 | {
52 | method: "POST",
53 | headers: {
54 | "Content-Type": "application/x-www-form-urlencoded"
55 | },
56 | body: new URLSearchParams(formData as any).toString()
57 | }
58 | );
59 |
60 | const json = await request.json();
61 |
62 | if (request.ok) {
63 | return {
64 | success: true,
65 | message: json.message,
66 | username: json.username,
67 | email: json.email
68 | };
69 | } else {
70 | return fail(400, {
71 | error: true,
72 | message: "Error: " + request.status
73 | });
74 | }
75 | } catch (err) {
76 | return { error: true, message: "Error: " + err };
77 | }
78 | }
79 | }
80 | };
81 |
--------------------------------------------------------------------------------
/src/routes/pubnix/register/+page.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 | {data.title}
12 |
13 |
86 |
87 |
108 |
--------------------------------------------------------------------------------
/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/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/team/+page.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 | {data.title}
9 |
10 |
11 | {#each Team as member}
12 |
15 |
16 |
{member.name} - {member.position}
17 | {#if member.description}
18 |
{member.description}
19 | {/if}
20 |
21 |
22 | {#if member.website}
23 |
28 | {/if}
29 |
30 | {#if member.matrix}
31 |
36 | {/if}
37 |
38 | {#if member.xmpp}
39 |
43 | {/if}
44 |
45 | {#if member.fedi}
46 |
51 | {/if}
52 |
53 | {#if member.git}
54 |
58 | {/if}
59 |
60 | {#if member.email}
61 |
65 | {/if}
66 |
67 | {#if member.pgp}
68 |
73 | {/if}
74 |
75 |
76 | {/each}
77 |
78 |
--------------------------------------------------------------------------------
/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/routes/team/Team.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "Arya",
4 | "description": "Libre Software Enthusiast and Project Segfault Sysadmin",
5 | "position": "Sysadmin & India Server Owner",
6 | "website": "https://aryak.me",
7 | "matrix": "https://matrix.to/#/@aryak:projectsegfau.lt",
8 | "xmpp": "https://join.jabber.network/#arya@projectsegfau.lt",
9 | "fedi": "https://social.projectsegfau.lt/aryak",
10 | "git": "https://codeberg.org/aryak",
11 | "email": "arya@projectsegfau.lt",
12 | "pgp": "https://keys.openpgp.org/vks/v1/by-fingerprint/9D56914428A62CF1B6A32175842D12BDA50DF120"
13 | },
14 | {
15 | "name": "Devrand",
16 | "matrix": "https://matrix.to/#/@openssl_rand:projectsegfau.lt/",
17 | "position": "Sysadmin",
18 | "description": "High schooler who is interested in internet freedom, programming, and open source software. (Previously openssl_rand)",
19 | "email": "mailto:openssl_rand@projectsegfau.lt"
20 | },
21 | {
22 | "name": "Midou",
23 | "description": "A random person with an obsession for online cat pics, also happens to be the sysadmin of the project",
24 | "matrix": "https://matrix.to/#/@midou:projectsegfau.lt/",
25 | "position": "Sysadmin",
26 | "git": "https://github.com/Midou36O/",
27 | "website": "https://midou.dev",
28 | "email": "midou@projectsegfau.lt",
29 | "pgp": "https://keys.openpgp.org/vks/v1/by-fingerprint/E2CA3E4AAC6FF624A1EB993FFC7429AE78981D71"
30 | },
31 | {
32 | "name": "MrLeRien",
33 | "discord": "https://discord.com/users/213634643327582208/",
34 | "matrix": "https://matrix.to/#/@mrlerien:projectsegfau.lt/",
35 | "position": "Finance Manager",
36 | "description": "using windows server for soleil levant was a mistake"
37 | },
38 | {
39 | "name": "py_",
40 | "description": "self-proclaimed front-end dev",
41 | "position": "Webdev",
42 | "website": "https://py.p.psf.lt",
43 | "matrix": "https://matrix.to/#/@py_:catgirl.cloud",
44 | "git": "https://github.com/Supercolbat"
45 | }
46 | ]
47 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/static/JetBrainsMono.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/JetBrainsMono.woff2
--------------------------------------------------------------------------------
/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/favicon.png
--------------------------------------------------------------------------------
/static/icons/FreshRSS-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
60 |
--------------------------------------------------------------------------------
/static/icons/akkoma.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/icons/akkoma.png
--------------------------------------------------------------------------------
/static/icons/anonymousoverflow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/icons/anonymousoverflow.png
--------------------------------------------------------------------------------
/static/icons/authentik.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/static/icons/breezewiki.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/static/icons/cinny.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/static/icons/element.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/static/icons/ente.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/static/icons/gitea.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
10 |
20 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/static/icons/gothub.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
40 |
45 |
50 |
55 |
60 |
63 |
64 |
66 |
70 |
75 |
80 |
83 |
86 |
89 |
102 |
115 |
116 |
119 |
132 |
146 |
147 |
148 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/static/icons/healthchecks.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
22 |
24 |
43 |
45 |
46 |
48 | image/svg+xml
49 |
51 |
52 |
53 |
54 |
55 |
60 |
66 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/static/icons/hedgedoc.svg:
--------------------------------------------------------------------------------
1 |
6 |
8 |
10 |
11 |
12 |
13 |
14 |
16 |
18 |
20 |
21 |
22 |
23 |
25 |
27 |
29 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/static/icons/hydrogen.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/static/icons/hyperpipe.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/static/icons/invidious.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/static/icons/jitsi.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/static/icons/kbin.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/static/icons/librarian.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/icons/librarian.png
--------------------------------------------------------------------------------
/static/icons/libreddit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/icons/libreddit.png
--------------------------------------------------------------------------------
/static/icons/libretranslate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/icons/libretranslate.png
--------------------------------------------------------------------------------
/static/icons/mailu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/icons/mailu.png
--------------------------------------------------------------------------------
/static/icons/matrix.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 | Matrix (protocol) logo
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/static/icons/mozhi.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
39 |
41 |
47 |
53 |
59 |
65 |
71 |
72 |
76 |
85 |
88 |
95 |
102 |
109 |
116 |
123 |
126 |
131 |
136 |
141 |
142 |
143 |
144 |
145 |
--------------------------------------------------------------------------------
/static/icons/nextcloud.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 | image/svg+xml
--------------------------------------------------------------------------------
/static/icons/nitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/icons/nitter.png
--------------------------------------------------------------------------------
/static/icons/owncloud.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/static/icons/piped.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/static/icons/plausible.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/icons/plausible.png
--------------------------------------------------------------------------------
/static/icons/pubnix.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/icons/pubnix.png
--------------------------------------------------------------------------------
/static/icons/rimgo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/icons/rimgo.png
--------------------------------------------------------------------------------
/static/icons/rssbridge-short.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
35 |
37 |
41 |
49 |
53 |
57 |
63 |
69 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/static/icons/safetwitch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/icons/safetwitch.png
--------------------------------------------------------------------------------
/static/icons/searxng.svg:
--------------------------------------------------------------------------------
1 |
2 |
13 |
15 |
17 |
18 |
20 | image/svg+xml
21 |
23 |
24 |
25 |
26 |
27 |
30 |
36 |
42 |
46 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/static/icons/shoelace.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
36 |
38 |
46 |
48 |
52 |
56 |
57 |
60 |
64 |
65 |
73 |
75 |
79 |
83 |
84 |
87 |
91 |
92 |
100 |
104 |
105 |
106 |
110 |
115 |
119 |
123 |
128 |
133 |
134 |
135 |
138 |
141 |
145 |
150 |
155 |
156 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/static/icons/simplelogin.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/static/icons/teddit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/icons/teddit.png
--------------------------------------------------------------------------------
/static/icons/vikunja.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/icons/vikunja.png
--------------------------------------------------------------------------------
/static/icons/xmpp.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/static/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/logo.png
--------------------------------------------------------------------------------
/static/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
39 |
41 |
58 |
66 |
71 |
77 |
82 |
87 |
93 |
94 |
95 |
100 |
104 |
111 |
112 |
113 |
121 |
122 |
--------------------------------------------------------------------------------
/static/qr/Bitcoin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/qr/Bitcoin.png
--------------------------------------------------------------------------------
/static/qr/Litecoin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/qr/Litecoin.png
--------------------------------------------------------------------------------
/static/qr/Monero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/qr/Monero.png
--------------------------------------------------------------------------------
/static/qr/UPI.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectSegfault/website/afb90c1a8d6ceb2f76d6829c6eca4ebaa2578766/static/qr/UPI.png
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/uno.config.ts:
--------------------------------------------------------------------------------
1 | import {
2 | defineConfig,
3 | presetIcons,
4 | presetTypography,
5 | transformerVariantGroup,
6 | transformerDirectives,
7 | presetWind
8 | } from "unocss";
9 |
10 | import extractorSvelte from "@unocss/extractor-svelte";
11 |
12 | export default defineConfig({
13 | extractors: [extractorSvelte],
14 |
15 | presets: [
16 | presetIcons(),
17 | presetWind({
18 | dark: "class"
19 | }),
20 | presetTypography()
21 | ],
22 |
23 | transformers: [transformerVariantGroup(), transformerDirectives()],
24 |
25 | safelist: [
26 | "i-ic:outline-dark-mode",
27 | "i-ic:outline-light-mode",
28 | "i-ic:baseline-toggle-on",
29 | "i-ic:baseline-toggle-off"
30 | ],
31 |
32 | theme: {
33 | fontFamily: {
34 | primary: ["var(--font-primary)"]
35 | },
36 | colors: {
37 | accent: "var(--accent)",
38 | accentTranslucent: "var(--accent-translucent)",
39 | primary: "var(--primary)",
40 | secondary: "var(--secondary)",
41 | tertiary: "var(--tertiary)",
42 | text: "var(--text)",
43 | grey: "var(--grey)",
44 | alt: "var(--alt)",
45 | altText: "var(--alt-text)"
46 | },
47 | breakpoints: {
48 | sm: "640px",
49 | md: "768px",
50 | lg: "1024px",
51 | xl: "1280px",
52 | "2xl": "1536px",
53 | nav: "890px",
54 | navPlus1: "891px"
55 | }
56 | }
57 | });
58 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------