mirror of
https://github.com/ProjectSegfault/website.git
synced 2024-10-13 10:34:31 +05:30
better navbar
This commit is contained in:
parent
926890b324
commit
3ff1e24e7c
54
.github/workflows/docker-dev.yml
vendored
54
.github/workflows/docker-dev.yml
vendored
@ -1,36 +1,34 @@
|
||||
name: Docker dev
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'dev'
|
||||
push:
|
||||
branches:
|
||||
- "dev"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: 'Build'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
build:
|
||||
name: "Build"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: "Build:checkout"
|
||||
uses: actions/checkout@v3
|
||||
- name: "Build:checkout"
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ProjectSegfault
|
||||
password: ${{ secrets.ACCESS_TOKEN }}
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ProjectSegfault
|
||||
password: ${{ secrets.ACCESS_TOKEN }}
|
||||
|
||||
- name: 'Build:dockerimage'
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
tags: ghcr.io/projectsegfault/website:dev
|
||||
context: "."
|
||||
push: true
|
||||
no-cache: true
|
||||
- name: "Build:dockerimage"
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
tags: ghcr.io/projectsegfault/website:dev
|
||||
context: "."
|
||||
push: true
|
||||
no-cache: true
|
||||
|
54
.github/workflows/docker.yml
vendored
54
.github/workflows/docker.yml
vendored
@ -1,36 +1,34 @@
|
||||
name: Docker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: 'Build'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
build:
|
||||
name: "Build"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: "Build:checkout"
|
||||
uses: actions/checkout@v3
|
||||
- name: "Build:checkout"
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ProjectSegfault
|
||||
password: ${{ secrets.ACCESS_TOKEN }}
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ProjectSegfault
|
||||
password: ${{ secrets.ACCESS_TOKEN }}
|
||||
|
||||
- name: 'Build:dockerimage'
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
tags: ghcr.io/projectsegfault/website:latest
|
||||
context: "."
|
||||
push: true
|
||||
no-cache: true
|
||||
- name: "Build:dockerimage"
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
tags: ghcr.io/projectsegfault/website:latest
|
||||
context: "."
|
||||
push: true
|
||||
no-cache: true
|
||||
|
23
README.md
23
README.md
@ -11,7 +11,7 @@ Live at [projectsegfau.lt](https://projectsegfau.lt).
|
||||
- Install [node.js](https://nodejs.org).
|
||||
- Install [pnpm](https://pnpm.io/).
|
||||
- Learn [Svelte](https://svelte.dev).
|
||||
- Add the environment variables from the [environment variables section](#environment-variables).
|
||||
- Add the environment variables from the [environment variables section](#environment-variables).
|
||||
|
||||
### Running a dev server.
|
||||
|
||||
@ -37,13 +37,14 @@ If you want to run the website locally in production follow the steps in [develo
|
||||
|
||||
The website has the following **mandatory** environment variables
|
||||
|
||||
| Name | Description |
|
||||
|:------------------ |:------------------------- |
|
||||
| AUTH_CLIENT_ID | Authentik client ID |
|
||||
| AUTH_CLIENT_SECRET | Authentik client secret |
|
||||
| AUTH_ISSUER | Authentication issuer URL |
|
||||
| AUTH_TRUST_HOST | Your domain |
|
||||
| AUTH_SECRET | Random 32 char secret |
|
||||
| GHOST_URL | Your Ghost CMS URL |
|
||||
| GHOST_API_KEY | Your Ghost CMS API key |
|
||||
| ORIGIN | Your domain |
|
||||
| Name | Description |
|
||||
| :----------------- | :----------------------------------|
|
||||
| AUTH_CLIENT_ID | Authentik client ID |
|
||||
| AUTH_CLIENT_SECRET | Authentik client secret |
|
||||
| AUTH_ISSUER | Authentication issuer URL |
|
||||
| AUTH_TRUST_HOST | Your domain |
|
||||
| AUTH_SECRET | Random 32 char secret |
|
||||
| GHOST_URL | Your Ghost CMS URL |
|
||||
| GHOST_API_KEY | Your Ghost CMS API key |
|
||||
| KUMA_URL | Your Uptime Kuma announcements URL |
|
||||
| ORIGIN | Your domain |
|
||||
|
@ -8,4 +8,4 @@ services:
|
||||
# context: .
|
||||
# dockerfile: Dockerfile
|
||||
ports:
|
||||
- "127.0.0.1:1339:3000"
|
||||
- "127.0.0.1:1339:3000"
|
||||
|
@ -4,7 +4,8 @@
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
html, html.light {
|
||||
html,
|
||||
html.light {
|
||||
--accent: #00a584;
|
||||
--accent-translucent: #00a58498;
|
||||
--font-primary: "JetBrains Mono", monospace;
|
||||
@ -74,4 +75,4 @@ details {
|
||||
|
||||
.button {
|
||||
@apply px-2 py-1 bg-accent text-primary rounded no-underline flex flex-row items-center gap-2;
|
||||
}
|
||||
}
|
||||
|
10
src/app.html
10
src/app.html
@ -2,8 +2,14 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/logo.svg" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link
|
||||
rel="icon"
|
||||
href="%sveltekit.assets%/logo.svg"
|
||||
/>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width"
|
||||
/>
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
|
@ -6,7 +6,14 @@ import type { Profile } from "@auth/core/types";
|
||||
import { redirect, type Handle } from "@sveltejs/kit";
|
||||
import { sequence } from "@sveltejs/kit/hooks";
|
||||
|
||||
const hasAuth = !env.AUTH_CLIENT_ID || !env.AUTH_CLIENT_SECRET || !env.AUTH_ISSUER || !env.AUTH_TRUST_HOST || !env.AUTH_SECRET ? false : true;
|
||||
const hasAuth =
|
||||
!env.AUTH_CLIENT_ID ||
|
||||
!env.AUTH_CLIENT_SECRET ||
|
||||
!env.AUTH_ISSUER ||
|
||||
!env.AUTH_TRUST_HOST ||
|
||||
!env.AUTH_SECRET
|
||||
? false
|
||||
: true;
|
||||
|
||||
export const handle: Handle = sequence(
|
||||
//@ts-ignore
|
||||
@ -19,26 +26,28 @@ export const handle: Handle = sequence(
|
||||
}) as Provider<Profile>
|
||||
]
|
||||
}),
|
||||
hasAuth ? async ({ event, resolve }) => {
|
||||
if (event.url.pathname.startsWith("/admin")) {
|
||||
const session = await event.locals.getSession();
|
||||
if (!session) {
|
||||
throw redirect(303, "/login");
|
||||
}
|
||||
}
|
||||
|
||||
const result = await resolve(event, {
|
||||
transformPageChunk: ({ html }) => html
|
||||
});
|
||||
return result;
|
||||
} : async ({ event, resolve }) => {
|
||||
if (event.url.pathname.startsWith("/admin")) {
|
||||
throw redirect(303, "/login");
|
||||
}
|
||||
|
||||
const result = await resolve(event, {
|
||||
transformPageChunk: ({ html }) => html
|
||||
});
|
||||
return result;
|
||||
}
|
||||
);
|
||||
hasAuth
|
||||
? async ({ event, resolve }) => {
|
||||
if (event.url.pathname.startsWith("/admin")) {
|
||||
const session = await event.locals.getSession();
|
||||
if (!session) {
|
||||
throw redirect(303, "/login");
|
||||
}
|
||||
}
|
||||
|
||||
const result = await resolve(event, {
|
||||
transformPageChunk: ({ html }) => html
|
||||
});
|
||||
return result;
|
||||
}
|
||||
: async ({ event, resolve }) => {
|
||||
if (event.url.pathname.startsWith("/admin")) {
|
||||
throw redirect(303, "/login");
|
||||
}
|
||||
|
||||
const result = await resolve(event, {
|
||||
transformPageChunk: ({ html }) => html
|
||||
});
|
||||
return result;
|
||||
}
|
||||
);
|
||||
|
@ -5,21 +5,38 @@
|
||||
export let isPost: boolean = false;
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-2 flex-1 {isPost ? "nav:(flex-row gap-4)" : ""}">
|
||||
<div class="flex flex-col gap-2 flex-1 {isPost ? 'nav:(flex-row gap-4)' : ''}">
|
||||
{#if post.tags.length > 0}
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<div class="i-ic:outline-bookmarks text-xl -ml-1" />
|
||||
{#each post.tags as tag}
|
||||
<a href="/blog/tags/{tag.slug}" class="no-underline rounded p-1 {isPost ? "bg-secondary" : "bg-primary"}">{tag.name}</a>
|
||||
<a
|
||||
href="/blog/tags/{tag.slug}"
|
||||
class="no-underline rounded p-1 {isPost
|
||||
? 'bg-secondary'
|
||||
: 'bg-primary'}">{tag.name}</a
|
||||
>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{#each post.authors as author}
|
||||
<a href="/blog/authors/{author.slug}" class="flex items-center gap-2 no-underline"><div class="i-ic:outline-person text-xl -ml-1" />{author.name}</a>
|
||||
<a
|
||||
href="/blog/authors/{author.slug}"
|
||||
class="flex items-center gap-2 no-underline"
|
||||
><div class="i-ic:outline-person text-xl -ml-1" />
|
||||
{author.name}</a
|
||||
>
|
||||
{/each}
|
||||
<span class="flex items-center gap-2"><div class="i-ic:outline-calendar-month text-xl -ml-1" /> {dayjs
|
||||
(post.published_at)
|
||||
.format("ddd, DD MMM YYYY HH:mm")}</span>
|
||||
<span class="flex items-center gap-2"><div class="i-ic:outline-edit text-2xl -ml-1" /> {post.plaintext.trim().split(/\s+/).length} words</span>
|
||||
<span class="flex items-center gap-2"><div class="i-ic:outline-import-contacts text-xl -ml-1" /> {post.reading_time} minute read</span>
|
||||
</div>
|
||||
<span class="flex items-center gap-2"
|
||||
><div class="i-ic:outline-calendar-month text-xl -ml-1" />
|
||||
{dayjs(post.published_at).format("ddd, DD MMM YYYY HH:mm")}</span
|
||||
>
|
||||
<span class="flex items-center gap-2"
|
||||
><div class="i-ic:outline-edit text-2xl -ml-1" />
|
||||
{post.plaintext.trim().split(/\s+/).length} words</span
|
||||
>
|
||||
<span class="flex items-center gap-2"
|
||||
><div class="i-ic:outline-import-contacts text-xl -ml-1" />
|
||||
{post.reading_time} minute read</span
|
||||
>
|
||||
</div>
|
||||
|
@ -3,6 +3,10 @@
|
||||
</script>
|
||||
|
||||
<div class="prose flex flex-col text-justify m-auto">
|
||||
<img src={data.post.feature_image} alt="{data.post.title} image" class="rounded">
|
||||
<img
|
||||
src={data.post.feature_image}
|
||||
alt="{data.post.title} image"
|
||||
class="rounded"
|
||||
/>
|
||||
{@html data.post.html}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3,10 +3,15 @@
|
||||
export let isPost: boolean = false;
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-4 p-4 rounded {isPost ? "" : "w-110 bg-secondary"}">
|
||||
<div
|
||||
class="flex flex-col gap-4 p-4 rounded {isPost ? '' : 'w-110 bg-secondary'}"
|
||||
>
|
||||
<slot />
|
||||
|
||||
{#if url}
|
||||
<a href={url} class="text-center">View on Ghost</a>
|
||||
<a
|
||||
href={url}
|
||||
class="text-center">View on Ghost</a
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,3 +1,3 @@
|
||||
<div class="flex flex-row flex-wrap gap-4">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3,4 +3,4 @@
|
||||
</script>
|
||||
|
||||
<span>{post.plaintext.split(" ").slice(0, 20).join(" ") + "..."}</span>
|
||||
<a href="/blog/{post.slug}">Read more...</a>
|
||||
<a href="/blog/{post.slug}">Read more...</a>
|
||||
|
@ -3,9 +3,11 @@
|
||||
export let name: string;
|
||||
</script>
|
||||
|
||||
|
||||
<div class="flex flex-col gap-4">
|
||||
{#each items as item}
|
||||
<a href="/blog/{name}/{item.slug}" class="bg-secondary sm:w-md p-2 rounded no-underline">{item.name}</a>
|
||||
<a
|
||||
href="/blog/{name}/{item.slug}"
|
||||
class="bg-secondary sm:w-md p-2 rounded no-underline">{item.name}</a
|
||||
>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -5,10 +5,17 @@
|
||||
|
||||
{#if !isPost}
|
||||
{#if post.feature_image}
|
||||
<img src={post.feature_image} alt="{post.title} image" class="rounded">
|
||||
<img
|
||||
src={post.feature_image}
|
||||
alt="{post.title} image"
|
||||
class="rounded"
|
||||
/>
|
||||
{/if}
|
||||
<a href="/blog/{post.slug}" class="text-text no-underline hover:underline"><span class="text-xl font-bold">{post.title}</span></a>
|
||||
<a
|
||||
href="/blog/{post.slug}"
|
||||
class="text-text no-underline hover:underline"
|
||||
><span class="text-xl font-bold">{post.title}</span></a
|
||||
>
|
||||
{:else}
|
||||
<span class="text-xl font-bold">{post.title}</span>
|
||||
{/if}
|
||||
|
||||
|
@ -4,4 +4,4 @@ export { default as Title } from "./Title.svelte";
|
||||
export { default as Meta } from "./Meta.svelte";
|
||||
export { default as ReadMore } from "./ReadMore.svelte";
|
||||
export { default as PostContent } from "./PostContent.svelte";
|
||||
export { default as SingleWordLists } from "./SingleWordLists.svelte";
|
||||
export { default as SingleWordLists } from "./SingleWordLists.svelte";
|
||||
|
@ -1,7 +1,11 @@
|
||||
<footer class="sticky top-full">
|
||||
<div class="flex flex-col justify-center sm:flex-row gap-1 border-t border-t-solid border-t-grey p-3 text-sm">
|
||||
<p class="flex flex-row items-center gap-1">Made with <i class="i-simple-icons:svelte text-[#FF3E00] block" /> SvelteKit</p>
|
||||
<div
|
||||
class="flex flex-col justify-center sm:flex-row gap-1 border-t border-t-solid border-t-grey p-3 text-sm"
|
||||
>
|
||||
<p class="flex flex-row items-center gap-1">
|
||||
Made with <i class="i-simple-icons:svelte text-[#FF3E00] block" /> SvelteKit
|
||||
</p>
|
||||
<span class="hidden sm:block">-</span>
|
||||
<a href="https://github.com/ProjectSegfault/website">Source code</a>
|
||||
</div>
|
||||
</footer>
|
||||
</footer>
|
||||
|
@ -1,8 +1,20 @@
|
||||
<div class="flex flex-col gap-6 items-center text-center mt-[7%]">
|
||||
<h1 class="text-5xl font-extrabold text-accent my-0 border-b-0 pb-0">Project Segfault</h1>
|
||||
<h1 class="text-5xl font-extrabold text-accent my-0 border-b-0 pb-0">
|
||||
Project Segfault
|
||||
</h1>
|
||||
<p class="text-2xl">Open source development and hosted services.</p>
|
||||
<div class="flex flex-row gap-4">
|
||||
<a href="/instances" class="button"><div class="i-ic:outline-computer" /> Instances</a>
|
||||
<a href="/donate" class="button !bg-amber !text-black"><div class="i-ic:outline-attach-money" /> Donate</a>
|
||||
<a
|
||||
href="/instances"
|
||||
class="button"
|
||||
><div class="i-ic:outline-computer" />
|
||||
Instances</a
|
||||
>
|
||||
<a
|
||||
href="/donate"
|
||||
class="button !bg-amber !text-black"
|
||||
><div class="i-ic:outline-attach-money" />
|
||||
Donate</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import ThemeToggle from "./ThemeToggle.svelte";
|
||||
import ThemeToggle from "$lib/Nav/ThemeToggle.svelte";
|
||||
import { page } from "$app/stores";
|
||||
import { slide } from "svelte/transition";
|
||||
import { quintOut } from 'svelte/easing';
|
||||
import { slide } from "svelte/transition"
|
||||
import { quintOut } from "svelte/easing";
|
||||
|
||||
$: currentPage = $page.url.pathname;
|
||||
|
||||
@ -14,15 +14,16 @@
|
||||
|
||||
$: showMenuButton = hasJS && isMobile;
|
||||
|
||||
$: menuOpen = !hasJS || hasJS && !isMobile;
|
||||
$: menuOpen = !hasJS || (hasJS && !isMobile);
|
||||
|
||||
$: menuOpenMobile = isMobile && menuOpen;
|
||||
|
||||
$: showThemeToggle = hasJS;
|
||||
|
||||
const toggleMenu = () => menuOpen = !menuOpen;
|
||||
const toggleMenu = () => (menuOpen = !menuOpen);
|
||||
|
||||
const handleNavigation = () => showMenuButton ? menuOpen = false : menuOpen = true;
|
||||
const handleNavigation = () =>
|
||||
showMenuButton ? (menuOpen = false) : (menuOpen = true);
|
||||
|
||||
const menus = [
|
||||
{ name: "Instances", url: "/instances" },
|
||||
@ -48,13 +49,17 @@
|
||||
<svelte:window bind:innerWidth />
|
||||
|
||||
<nav
|
||||
class="bg-primary {menuOpenMobile ? "border-none" : "border-b border-b-solid border-b-grey"} {isMobile ? "py-2" : ""} flex px-2 flex-col justify-between nav:(flex-row items-center)"
|
||||
class:hasJSNav={hasJS}
|
||||
class:noJSNav={!hasJS}
|
||||
class="bg-primary {menuOpenMobile
|
||||
? 'border-none'
|
||||
: 'border-b border-b-solid border-b-grey'} {isMobile
|
||||
? 'py-2'
|
||||
: ''} flex px-2 flex-col justify-between nav:(flex-row items-center) {hasJS
|
||||
? 'sticky top-0 z-50'
|
||||
: 'border-b border-b-solid border-b-grey'}"
|
||||
>
|
||||
<div class="flex flex-row items-center justify-between">
|
||||
<a
|
||||
class="flex items-center decoration-none text-text gap-2 transition-opacity duration-250 hover:opacity-80"
|
||||
class="flex items-center decoration-none text-text gap-2 transition-filter duration-250"
|
||||
href="/"
|
||||
>
|
||||
<img
|
||||
@ -68,17 +73,21 @@
|
||||
{#if showMenuButton}
|
||||
<button
|
||||
on:click={toggleMenu}
|
||||
class="{menuOpen ? "i-ic:outline-close" : "i-ic:outline-menu"} h-4 w-4 cursor-pointer mr-2"
|
||||
class="{menuOpen
|
||||
? 'i-ic:outline-close'
|
||||
: 'i-ic:outline-menu'} h-4 w-4 cursor-pointer mr-2"
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if menuOpen}
|
||||
<div
|
||||
class="links {isMobile ? "!children:py-2" : ""}"
|
||||
class:hasJS={hasJS}
|
||||
class:noJS={!hasJS}
|
||||
transition:slide="{{duration: 300, easing: quintOut }}"
|
||||
class="links flex flex-row gap-2 {isMobile
|
||||
? '!children:py-2'
|
||||
: ''} {hasJS
|
||||
? 'lt-nav:(flex flex-col pt-2 gap-2 fixed bg-primary w-full left-0 top-[2.75rem] p-2 z-50 border-b-solid border-b border-b-grey shadow shadow-secondary)'
|
||||
: 'lt-nav:(grid grid-cols-2 gap-2 pt-2 w-fit)'}"
|
||||
transition:slide={{ duration: 300, easing: quintOut }}
|
||||
>
|
||||
{#each menus as { url, name, external }}
|
||||
<a
|
||||
@ -88,9 +97,7 @@
|
||||
href={url}
|
||||
on:click={handleNavigation}
|
||||
>{#if external}
|
||||
<div
|
||||
class="i-ic:outline-open-in-new mr-2 h-4 w-4"
|
||||
/>
|
||||
<div class="i-ic:outline-open-in-new mr-2 h-4 w-4" />
|
||||
{/if}
|
||||
{name}
|
||||
</a>
|
||||
@ -124,52 +131,14 @@
|
||||
}
|
||||
|
||||
.links > * {
|
||||
@apply py-4 px-2 cursor-pointer text-text decoration-none transition-color duration-250 text-sm font-500 flex items-center hover\:(text-accent);
|
||||
@apply py-4 px-2 text-text decoration-none transition-filter duration-250 text-sm flex items-center;
|
||||
}
|
||||
|
||||
.icon > span {
|
||||
@apply flex text-sm nav\:hidden;
|
||||
@apply text-sm nav\:hidden;
|
||||
}
|
||||
|
||||
.icon {
|
||||
@apply flex flex-row items-center gap-2 text-base;
|
||||
}
|
||||
|
||||
.hasJS {
|
||||
@apply flex flex-col pt-2 gap-2 fixed bg-primary w-full left-0 top-[2.75rem] p-2 z-50 border-b-solid border-b border-b-grey shadow shadow-secondary;
|
||||
}
|
||||
|
||||
.noJS {
|
||||
@apply grid grid-cols-2 gap-2 pt-2 w-fit;
|
||||
}
|
||||
|
||||
.hasJSNav {
|
||||
@apply sticky top-0 z-50;
|
||||
}
|
||||
|
||||
.noJSNav {
|
||||
@apply border-b border-b-solid border-b-grey;
|
||||
}
|
||||
|
||||
@media (min-width: 1090px) {
|
||||
.hasJS {
|
||||
flex-direction: row;
|
||||
padding-top: 0;
|
||||
position: initial;
|
||||
background-color: initial;
|
||||
width: initial;
|
||||
left: initial;
|
||||
top: initial;
|
||||
padding: initial;
|
||||
z-index: initial;
|
||||
border-bottom: initial;
|
||||
box-shadow: initial;
|
||||
}
|
||||
|
||||
.noJS {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding-top: 0;
|
||||
}
|
||||
@apply flex items-center gap-2 text-base;
|
||||
}
|
||||
</style>
|
||||
|
@ -19,6 +19,10 @@
|
||||
on:click={toggle}
|
||||
class="text-text flex items-center text-sm"
|
||||
>
|
||||
<div class="i-ic:{theme === 'dark' ? 'outline-light-mode' : 'outline-dark-mode'} h-4 w-4" />
|
||||
<div
|
||||
class="i-ic:{theme === 'dark'
|
||||
? 'outline-light-mode'
|
||||
: 'outline-dark-mode'} h-4 w-4"
|
||||
/>
|
||||
<span class="ml-2 nav:(hidden ml-1)">Toggle theme</span>
|
||||
</button>
|
||||
|
@ -5,4 +5,4 @@
|
||||
|
||||
<p class="my-4 {classes}">
|
||||
<slot />
|
||||
</p>
|
||||
</p>
|
||||
|
@ -4,7 +4,10 @@
|
||||
</script>
|
||||
|
||||
{#key pathname}
|
||||
<div in:fly={{ x: -10, duration: 250, delay: 250 }} out:fly={{ x: 5, duration: 250 }}>
|
||||
<div
|
||||
in:fly={{ x: -10, duration: 250, delay: 250 }}
|
||||
out:fly={{ x: 5, duration: 250 }}
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
{/key}
|
||||
{/key}
|
||||
|
@ -1,8 +1,8 @@
|
||||
<script>
|
||||
import { page } from '$app/stores';
|
||||
import { page } from "$app/stores";
|
||||
</script>
|
||||
|
||||
<h1>
|
||||
{$page.status}
|
||||
<p class="text-base font-normal mt-4">{$page.error?.message}</p>
|
||||
</h1>
|
||||
</h1>
|
||||
|
@ -13,18 +13,27 @@
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{$page.data.title} | Project Segfault {$page.url.pathname.startsWith("/blog") ? "blog" : ""}</title>
|
||||
<title
|
||||
>{$page.data.title} | Project Segfault {$page.url.pathname.startsWith(
|
||||
"/blog"
|
||||
)
|
||||
? "blog"
|
||||
: ""}</title
|
||||
>
|
||||
{#if $page.data.description}
|
||||
<meta name="description" content={$page.data.description} />
|
||||
<meta
|
||||
name="description"
|
||||
content={$page.data.description}
|
||||
/>
|
||||
{/if}
|
||||
</svelte:head>
|
||||
|
||||
<Nav />
|
||||
|
||||
<main class="px-8 mb-8 max-w-90rem m-auto">
|
||||
<PageTransition pathname={data.pathname}>
|
||||
<slot />
|
||||
</PageTransition>
|
||||
</main>
|
||||
<main class="px-8 mb-8 max-w-90rem m-auto">
|
||||
<PageTransition pathname={data.pathname}>
|
||||
<slot />
|
||||
</PageTransition>
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
|
@ -3,5 +3,5 @@ import type { LayoutLoad } from "./$types";
|
||||
export const load = (async ({ url: { pathname } }) => {
|
||||
return {
|
||||
pathname
|
||||
}
|
||||
}) satisfies LayoutLoad
|
||||
};
|
||||
}) satisfies LayoutLoad;
|
||||
|
@ -11,7 +11,7 @@ export const load = (async () => {
|
||||
const meta = {
|
||||
title: "Home",
|
||||
description: "Open source development and hosted services."
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await axios(env.KUMA_URL, { httpsAgent: agent });
|
||||
@ -24,4 +24,4 @@ export const load = (async () => {
|
||||
} catch (err) {
|
||||
return { error: true, message: "Error: " + err };
|
||||
}
|
||||
}) satisfies PageServerLoad;
|
||||
}) satisfies PageServerLoad;
|
||||
|
@ -31,22 +31,40 @@
|
||||
{#if !data.error}
|
||||
{#if data.announcements.incident}
|
||||
<div class="flex flex-col items-center mt-16">
|
||||
<div class="flex flex-col prose break-words rounded p-4 lt-sm:max-w-74 sm:(p-8) {backgroundColor === "#212529" ? "text-text" : "text-black"}" style="background-color: {backgroundColor};">
|
||||
<div
|
||||
class="flex flex-col prose break-words rounded p-4 lt-sm:max-w-74 sm:(p-8) {backgroundColor ===
|
||||
'#212529'
|
||||
? 'text-text'
|
||||
: 'text-black'}"
|
||||
style="background-color: {backgroundColor};"
|
||||
>
|
||||
{#if data.announcements.incident.title}
|
||||
<span class="text-xl font-semibold">{data.announcements.incident.title}</span>
|
||||
<span class="text-xl font-semibold"
|
||||
>{data.announcements.incident.title}</span
|
||||
>
|
||||
{/if}
|
||||
|
||||
{#if data.announcements.incident.content}
|
||||
<p>{@html sanitizeHtml(data.announcements.incident.content.replace(/\n/g, "<br />"))}</p>
|
||||
<p>
|
||||
{@html sanitizeHtml(
|
||||
data.announcements.incident.content.replace(
|
||||
/\n/g,
|
||||
"<br />"
|
||||
)
|
||||
)}
|
||||
</p>
|
||||
{/if}
|
||||
|
||||
<span>Created - {data.announcements.incident.createdDate}</span>
|
||||
{#if data.announcements.incident.lastUpdatedDate}
|
||||
<span>Updated - {data.announcements.incident.lastUpdatedDate}</span>
|
||||
<span
|
||||
>Updated - {data.announcements.incident
|
||||
.lastUpdatedDate}</span
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<p>{data.message}</p>
|
||||
{/if}
|
||||
{/if}
|
||||
|
@ -5,4 +5,4 @@
|
||||
</script>
|
||||
|
||||
<h1>{data.title}</h1>
|
||||
<p>Nothing here yet.</p>
|
||||
<p>Nothing here yet.</p>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type { PageLoad } from "./$types";
|
||||
|
||||
export const load = (() => {
|
||||
return {
|
||||
title: "Admin dashboard"
|
||||
};
|
||||
}) satisfies PageLoad;
|
||||
return {
|
||||
title: "Admin dashboard"
|
||||
};
|
||||
}) satisfies PageLoad;
|
||||
|
@ -4,10 +4,10 @@ import fetchGhost from "./fetchGhost";
|
||||
export const load = (async ({ fetch }) => {
|
||||
const meta = {
|
||||
title: "Blog"
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
posts: fetchGhost("posts"),
|
||||
...meta
|
||||
};
|
||||
}) satisfies PageServerLoad;
|
||||
}) satisfies PageServerLoad;
|
||||
|
@ -2,14 +2,35 @@
|
||||
import type { PageData } from "./$types";
|
||||
export let data: PageData;
|
||||
|
||||
import { PostsContainer, PostOuter, Title, Meta, ReadMore } from "$lib/BlogCard";
|
||||
import {
|
||||
PostsContainer,
|
||||
PostOuter,
|
||||
Title,
|
||||
Meta,
|
||||
ReadMore
|
||||
} from "$lib/BlogCard";
|
||||
</script>
|
||||
|
||||
<div class="h1-no-lg flex flex-col sm:(flex-row items-center) gap-4">
|
||||
<span class="text-4xl font-bold">{data.title}</span>
|
||||
<a href="/blog/tags" class="button sm:w-fit"><div class="i-ic:outline-bookmarks" /> Tags</a>
|
||||
<a href="/blog/authors" class="button sm:w-fit"><div class="i-ic:outline-people text-xl" /> Authors</a>
|
||||
<a href="https://blog.projectsegfau.lt/rss" class="button sm:w-fit !bg-[#ee802f]"><div class="i-simple-icons:rss" /> RSS</a>
|
||||
<a
|
||||
href="/blog/tags"
|
||||
class="button sm:w-fit"
|
||||
><div class="i-ic:outline-bookmarks" />
|
||||
Tags</a
|
||||
>
|
||||
<a
|
||||
href="/blog/authors"
|
||||
class="button sm:w-fit"
|
||||
><div class="i-ic:outline-people text-xl" />
|
||||
Authors</a
|
||||
>
|
||||
<a
|
||||
href="https://blog.projectsegfau.lt/rss"
|
||||
class="button sm:w-fit !bg-[#ee802f]"
|
||||
><div class="i-simple-icons:rss" />
|
||||
RSS</a
|
||||
>
|
||||
</div>
|
||||
|
||||
{#if !data.posts.error}
|
||||
@ -24,4 +45,4 @@
|
||||
</PostsContainer>
|
||||
{:else}
|
||||
<p>{data.posts.message}</p>
|
||||
{/if}
|
||||
{/if}
|
||||
|
@ -8,11 +8,11 @@ export const load = (async ({ params, fetch }) => {
|
||||
|
||||
const meta = {
|
||||
title: !allPosts.error ? data.posts[0].title : ""
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
post: !allPosts.error ? data.posts[0] : {},
|
||||
allPosts: allPosts,
|
||||
...meta
|
||||
};
|
||||
}) satisfies PageServerLoad;
|
||||
}) satisfies PageServerLoad;
|
||||
|
@ -1,19 +1,39 @@
|
||||
<script lang="ts">
|
||||
import { PostOuter, Title, Meta, PostContent, ReadMore, PostsContainer } from "$lib/BlogCard";
|
||||
import {
|
||||
PostOuter,
|
||||
Title,
|
||||
Meta,
|
||||
PostContent,
|
||||
ReadMore,
|
||||
PostsContainer
|
||||
} from "$lib/BlogCard";
|
||||
|
||||
import type { PageData } from "./$types";
|
||||
export let data: PageData;
|
||||
|
||||
$: index = !data.allPosts.error ? data.allPosts.posts.findIndex((post: { slug: string; }) => post.slug === data.post.slug) : null;
|
||||
$: index = !data.allPosts.error
|
||||
? data.allPosts.posts.findIndex(
|
||||
(post: { slug: string }) => post.slug === data.post.slug
|
||||
)
|
||||
: null;
|
||||
$: next = !data.allPosts.error ? data.allPosts.posts[index - 1] : null;
|
||||
$: previous = !data.allPosts.error ? data.allPosts.posts[index + 1] : null;
|
||||
</script>
|
||||
|
||||
{#if !data.allPosts.error}
|
||||
<PostOuter url={data.post.url} isPost>
|
||||
<PostOuter
|
||||
url={data.post.url}
|
||||
isPost
|
||||
>
|
||||
<div class="text-center mt-4 flex flex-col items-center gap-4">
|
||||
<Title post={data.post} isPost />
|
||||
<Meta post={data.post} isPost />
|
||||
<Title
|
||||
post={data.post}
|
||||
isPost
|
||||
/>
|
||||
<Meta
|
||||
post={data.post}
|
||||
isPost
|
||||
/>
|
||||
</div>
|
||||
<PostContent {data} />
|
||||
</PostOuter>
|
||||
@ -27,7 +47,7 @@
|
||||
<ReadMore post={previous} />
|
||||
</PostOuter>
|
||||
{/if}
|
||||
|
||||
|
||||
{#if next}
|
||||
<PostOuter>
|
||||
<h1 class="more-posts">Next post</h1>
|
||||
@ -46,4 +66,4 @@
|
||||
</style>
|
||||
{:else}
|
||||
<p>{data.allPosts.message}</p>
|
||||
{/if}
|
||||
{/if}
|
||||
|
@ -6,7 +6,7 @@ export const load = (async ({ fetch }) => {
|
||||
|
||||
const meta = {
|
||||
title: "Blog authors"
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
authors: data,
|
||||
|
@ -8,7 +8,10 @@
|
||||
<h1>{data.title}</h1>
|
||||
|
||||
{#if !data.authors.error}
|
||||
<SingleWordLists items={data.authors.authors} name="authors" />
|
||||
<SingleWordLists
|
||||
items={data.authors.authors}
|
||||
name="authors"
|
||||
/>
|
||||
{:else}
|
||||
<p>{data.authors.message}</p>
|
||||
{/if}
|
||||
{/if}
|
||||
|
@ -3,24 +3,25 @@ import fetchGhost from "../../fetchGhost";
|
||||
|
||||
export const load = (async ({ params, fetch }) => {
|
||||
const data = await fetchGhost("posts", "&filter=author:" + params.author);
|
||||
|
||||
const authorsLoop = !data.error ? data.posts[0].authors.map((author: { slug: string; name: any; }) => {
|
||||
if (author.slug === params.author) {
|
||||
return author.name;
|
||||
}
|
||||
}) : [];
|
||||
|
||||
const authorsLoop = !data.error
|
||||
? data.posts[0].authors.map((author: { slug: string; name: any }) => {
|
||||
if (author.slug === params.author) {
|
||||
return author.name;
|
||||
}
|
||||
})
|
||||
: [];
|
||||
|
||||
const authorName = authorsLoop.filter((tag: any) => tag !== undefined)[0];
|
||||
|
||||
const meta = {
|
||||
title: "Blog author " + authorName,
|
||||
description: "Blog posts by " + authorName,
|
||||
description: "Blog posts by " + authorName
|
||||
};
|
||||
|
||||
return {
|
||||
posts: data,
|
||||
authorName,
|
||||
...meta,
|
||||
...meta
|
||||
};
|
||||
}) satisfies PageServerLoad;
|
||||
|
||||
|
@ -2,7 +2,13 @@
|
||||
import type { PageData } from "./$types";
|
||||
export let data: PageData;
|
||||
|
||||
import { PostsContainer, PostOuter, Title, Meta, ReadMore } from "$lib/BlogCard";
|
||||
import {
|
||||
PostsContainer,
|
||||
PostOuter,
|
||||
Title,
|
||||
Meta,
|
||||
ReadMore
|
||||
} from "$lib/BlogCard";
|
||||
</script>
|
||||
|
||||
<h1>Blog author <span class="text-accent">{data.authorName}</span></h1>
|
||||
@ -19,4 +25,4 @@
|
||||
</PostsContainer>
|
||||
{:else}
|
||||
<p>{data.posts.message}</p>
|
||||
{/if}
|
||||
{/if}
|
||||
|
@ -6,9 +6,18 @@ const agent = new Agent({
|
||||
family: 4
|
||||
});
|
||||
|
||||
const fetchGhost = async (action: string, additional?: string ) => {
|
||||
const fetchGhost = async (action: string, additional?: string) => {
|
||||
try {
|
||||
const request = await axios(env.GHOST_URL + "/ghost/api/content/" + action + "/?key=" + env.GHOST_API_KEY + "&include=authors,tags&limit=all&formats=html,plaintext" + (additional ? additional : ""), { httpsAgent: agent });
|
||||
const request = await axios(
|
||||
env.GHOST_URL +
|
||||
"/ghost/api/content/" +
|
||||
action +
|
||||
"/?key=" +
|
||||
env.GHOST_API_KEY +
|
||||
"&include=authors,tags&limit=all&formats=html,plaintext" +
|
||||
(additional ? additional : ""),
|
||||
{ httpsAgent: agent }
|
||||
);
|
||||
|
||||
if (request.status === 200) {
|
||||
return request.data;
|
||||
@ -18,6 +27,6 @@ const fetchGhost = async (action: string, additional?: string ) => {
|
||||
} catch (err) {
|
||||
return { error: true, message: "Error: " + err };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default fetchGhost;
|
||||
export default fetchGhost;
|
||||
|
@ -6,10 +6,10 @@ export const load = (async () => {
|
||||
|
||||
const meta = {
|
||||
title: "Blog tags"
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
tags: data,
|
||||
...meta
|
||||
}
|
||||
}) satisfies PageServerLoad;
|
||||
};
|
||||
}) satisfies PageServerLoad;
|
||||
|
@ -8,7 +8,10 @@
|
||||
<h1>{data.title}</h1>
|
||||
|
||||
{#if !data.tags.error}
|
||||
<SingleWordLists items={data.tags.tags} name="tags" />
|
||||
<SingleWordLists
|
||||
items={data.tags.tags}
|
||||
name="tags"
|
||||
/>
|
||||
{:else}
|
||||
<p>{data.tags.message}</p>
|
||||
{/if}
|
||||
{/if}
|
||||
|
@ -4,21 +4,23 @@ import fetchGhost from "../../fetchGhost";
|
||||
export const load = (async ({ params, fetch }) => {
|
||||
const data = await fetchGhost("posts", "&filter=tags:" + params.tag);
|
||||
|
||||
const tagsLoop = !data.error ? data.posts[0].tags.map((tag: { slug: string; name: any; }) => {
|
||||
if (tag.slug === params.tag) {
|
||||
return tag.name;
|
||||
}
|
||||
}) : [];
|
||||
const tagsLoop = !data.error
|
||||
? data.posts[0].tags.map((tag: { slug: string; name: any }) => {
|
||||
if (tag.slug === params.tag) {
|
||||
return tag.name;
|
||||
}
|
||||
})
|
||||
: [];
|
||||
|
||||
const tagName = tagsLoop.filter((tag: any) => tag !== undefined)[0];
|
||||
|
||||
const meta = {
|
||||
title: "Blog tag " + tagName
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
posts: data,
|
||||
tagName: tagName,
|
||||
...meta
|
||||
}
|
||||
}) satisfies PageServerLoad;
|
||||
};
|
||||
}) satisfies PageServerLoad;
|
||||
|
@ -2,7 +2,13 @@
|
||||
import type { PageData } from "./$types";
|
||||
export let data: PageData;
|
||||
|
||||
import { PostsContainer, PostOuter, Title, Meta, ReadMore } from "$lib/BlogCard";
|
||||
import {
|
||||
PostsContainer,
|
||||
PostOuter,
|
||||
Title,
|
||||
Meta,
|
||||
ReadMore
|
||||
} from "$lib/BlogCard";
|
||||
</script>
|
||||
|
||||
<h1>Blog tag <span class="text-accent">{data.tagName}</span></h1>
|
||||
@ -19,4 +25,4 @@
|
||||
</PostsContainer>
|
||||
{:else}
|
||||
<p>{data.posts.message}</p>
|
||||
{/if}
|
||||
{/if}
|
||||
|
@ -4,17 +4,33 @@
|
||||
export let data: PageData;
|
||||
</script>
|
||||
|
||||
|
||||
<h1>{data.title}</h1>
|
||||
|
||||
<h2>Matrix</h2>
|
||||
|
||||
<p>We have a Matrix space for general discussion, support and announcements about Project Segfault over at <a href="https://matrix.to/#/#project-segfault:projectsegfau.lt/">this link</a>.</p>
|
||||
<p>
|
||||
We have a Matrix space for general discussion, support and announcements
|
||||
about Project Segfault over at <a
|
||||
href="https://matrix.to/#/#project-segfault:projectsegfau.lt/"
|
||||
>this link</a
|
||||
>.
|
||||
</p>
|
||||
|
||||
<h2>Email</h2>
|
||||
|
||||
<p>Our primary email address is <a href="mailto:contact@projectsegfau.lt">contact@projectsegfau.lt</a>. You can use this as a way to send feedback or other stuff to us if you don't have or don't want to make a Matrix account. When waiting for us to answer make sure to check your spam, since some email providers block non-popular domains.</p>
|
||||
<p>
|
||||
Our primary email address is <a href="mailto:contact@projectsegfau.lt"
|
||||
>contact@projectsegfau.lt</a
|
||||
>. You can use this as a way to send feedback or other stuff to us if you
|
||||
don't have or don't want to make a Matrix account. When waiting for us to
|
||||
answer make sure to check your spam, since some email providers block
|
||||
non-popular domains.
|
||||
</p>
|
||||
|
||||
<h2>Members</h2>
|
||||
|
||||
<p>You can contact individual members by using the links provided in <a href="/team">the team page</a>.</p>
|
||||
<p>
|
||||
You can contact individual members by using the links provided in <a
|
||||
href="/team">the team page</a
|
||||
>.
|
||||
</p>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type { PageLoad } from "./$types";
|
||||
|
||||
export const load = (() => {
|
||||
return {
|
||||
title: "Contact"
|
||||
};
|
||||
}) satisfies PageLoad;
|
||||
return {
|
||||
title: "Contact"
|
||||
};
|
||||
}) satisfies PageLoad;
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
<script lang="ts">
|
||||
import CryptoInfo from "./CryptoInfo.svelte";
|
||||
import type { PageData } from "./$types";
|
||||
@ -10,26 +9,55 @@
|
||||
|
||||
<h2>What we do with donations</h2>
|
||||
|
||||
<p>These donations primarily help us pay for our VPSes, domain names and other expenses related to crucial infrastructure we have to maintain. We also sometimes donate to developers who maintain software we rely heavily on such as our authentication provider.</p>
|
||||
<p>
|
||||
These donations primarily help us pay for our VPSes, domain names and other
|
||||
expenses related to crucial infrastructure we have to maintain. We also
|
||||
sometimes donate to developers who maintain software we rely heavily on such
|
||||
as our authentication provider.
|
||||
</p>
|
||||
|
||||
<h2>Donation methods</h2>
|
||||
|
||||
<p>You can currently donate by credit card through <a href="https://liberapay.com">Liberapay</a> and cryptocurrencies.</p>
|
||||
<p>
|
||||
You can currently donate by credit card through <a
|
||||
href="https://liberapay.com">Liberapay</a
|
||||
> and cryptocurrencies.
|
||||
</p>
|
||||
|
||||
<h3>Credit card</h3>
|
||||
<a href="https://liberapay.com/ProjectSegfault/donate" class="button !bg-amber !text-black w-fit"><div class="i-simple-icons:liberapay" /> Liberapay</a>
|
||||
<a
|
||||
href="https://liberapay.com/ProjectSegfault/donate"
|
||||
class="button !bg-amber !text-black w-fit"
|
||||
><div class="i-simple-icons:liberapay" />
|
||||
Liberapay</a
|
||||
>
|
||||
|
||||
<h3>Cryptocurrencies</h3>
|
||||
<p>You can use <a href="https://projectsegfau.lt">projectsegfau.lt</a> as a crypto wallet address in supported OpenAlias clients such as <a href="https://mymonero.com">MyMonero</a>, <a href="https://electrum.org">Electrum</a> and <a href="https://electrum-ltc.org">Electrum-LTC</a>.</p>
|
||||
<p>
|
||||
You can use <a href="https://projectsegfau.lt">projectsegfau.lt</a> as a
|
||||
crypto wallet address in supported OpenAlias clients such as
|
||||
<a href="https://mymonero.com">MyMonero</a>,
|
||||
<a href="https://electrum.org">Electrum</a>
|
||||
and <a href="https://electrum-ltc.org">Electrum-LTC</a>.
|
||||
</p>
|
||||
|
||||
<h4>Monero</h4>
|
||||
|
||||
<CryptoInfo address="47L7Qsto7XcifY3CdG18ySe5Tt83kpFLDLve9jQwbc9taPBLNGv6ZrJNUKpMG9Nj9zHgCZ4FQMSyt75e8Jvx12JFLtJyFdA" qr="Monero.png" />
|
||||
<CryptoInfo
|
||||
address="47L7Qsto7XcifY3CdG18ySe5Tt83kpFLDLve9jQwbc9taPBLNGv6ZrJNUKpMG9Nj9zHgCZ4FQMSyt75e8Jvx12JFLtJyFdA"
|
||||
qr="Monero.png"
|
||||
/>
|
||||
|
||||
<h4>Bitcoin</h4>
|
||||
|
||||
<CryptoInfo address="bc1qrc8ywgp95a6p3zausp4nff70qzstp6h8z86sxd" qr="Bitcoin.png" />
|
||||
<CryptoInfo
|
||||
address="bc1qrc8ywgp95a6p3zausp4nff70qzstp6h8z86sxd"
|
||||
qr="Bitcoin.png"
|
||||
/>
|
||||
|
||||
<h4>Litecoin</h4>
|
||||
|
||||
<CryptoInfo address="ltc1qn3ald586h2ntt0n3zkvwsmju2e5vndgtvvgatj" qr="Litecoin.png" />
|
||||
<CryptoInfo
|
||||
address="ltc1qn3ald586h2ntt0n3zkvwsmju2e5vndgtvvgatj"
|
||||
qr="Litecoin.png"
|
||||
/>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type { PageLoad } from "./$types";
|
||||
|
||||
export const load = (() => {
|
||||
return {
|
||||
title: "Donate"
|
||||
};
|
||||
}) satisfies PageLoad;
|
||||
return {
|
||||
title: "Donate"
|
||||
};
|
||||
}) satisfies PageLoad;
|
||||
|
@ -6,13 +6,19 @@
|
||||
{#if address}
|
||||
<details class="p-0">
|
||||
<summary>Address</summary>
|
||||
<code class="break-words whitespace-normal">49burTxWHyqa9NkkC9PV33D79PrwARMq8aic4XezTx36i66qyLA3afYXicycTTA5st93CV5Rr9AGkKpeE5GPueRN2PkfFQN</code>
|
||||
<code class="break-words whitespace-normal"
|
||||