Prettier Linting
Some checks failed
Run Tests on Code / test (push) Has been cancelled
Build Docker Image on Pull Request / test (pull_request) Failing after 3m47s

This commit is contained in:
Neshura 2024-01-06 14:02:30 +01:00
parent 7f3eb2888a
commit 4254015cd8
Signed by: Neshura
GPG key ID: B6983AAA6B9A7A6C
11 changed files with 243 additions and 201 deletions

View file

@ -1,12 +1,17 @@
<svelte:options runes={true} /> <svelte:options runes={true} />
<script lang="ts"> <script lang="ts">
import {onMount} from "svelte"; import { onMount } from 'svelte';
import sanitizeHtml from "sanitize-html"; import sanitizeHtml from 'sanitize-html';
import {Skeleton} from "$lib/components/ui/skeleton/index.js"; import { Skeleton } from '$lib/components/ui/skeleton/index.js';
import {DoubleArrowUp} from "radix-icons-svelte"; import { DoubleArrowUp } from 'radix-icons-svelte';
let { account, maxToots, accountId, excludeReplies }: { account: string, maxToots?: number, accountId?: string, excludeReplies: boolean } = $props(); let {
account,
maxToots,
accountId,
excludeReplies
}: { account: string; maxToots?: number; accountId?: string; excludeReplies: boolean } = $props();
let toots: Toot[] = $state([]); let toots: Toot[] = $state([]);
let loading = $state(false); let loading = $state(false);
@ -14,7 +19,7 @@
onMount(() => { onMount(() => {
loading = true; loading = true;
loadToots(account, accountId, maxToots, excludeReplies); loadToots(account, accountId, maxToots, excludeReplies);
}) });
interface Toot { interface Toot {
created_at: string; created_at: string;
@ -29,7 +34,7 @@
}; };
reblog?: Toot; reblog?: Toot;
media_attachments: { media_attachments: {
type: "unknown" | "image" | "gifv" | "video" | "audio"; type: 'unknown' | 'image' | 'gifv' | 'video' | 'audio';
url: string; url: string;
preview_url: string; preview_url: string;
description: string; description: string;
@ -41,7 +46,7 @@
userURL: string, userURL: string,
limit: number, limit: number,
excludeReplies: boolean, excludeReplies: boolean,
accountId?: string, accountId?: string
): Promise<Toot[]> { ): Promise<Toot[]> {
const url = new URL(userURL); const url = new URL(userURL);
@ -53,35 +58,29 @@
// Extract username from URL. // Extract username from URL.
const parts = /@(\w+)$/.exec(url.pathname); const parts = /@(\w+)$/.exec(url.pathname);
if (!parts) { if (!parts) {
throw "not a Mastodon user URL"; throw 'not a Mastodon user URL';
} }
const username = parts[1]; const username = parts[1];
// Look up user ID from username. // Look up user ID from username.
const lookupURL = Object.assign(new URL(url), { const lookupURL = Object.assign(new URL(url), {
pathname: "/api/v1/accounts/lookup", pathname: '/api/v1/accounts/lookup',
search: `?acct=${username}`, search: `?acct=${username}`
}); });
return (await (await fetch(lookupURL)).json())["id"]; return (await (await fetch(lookupURL)).json())['id'];
})()); })());
// Fetch toots. // Fetch toots.
const tootURL = Object.assign(new URL(url), { const tootURL = Object.assign(new URL(url), {
pathname: `/api/v1/accounts/${userId}/statuses`, pathname: `/api/v1/accounts/${userId}/statuses`,
search: `?limit=${limit ?? 5}&exclude_replies=${!!excludeReplies}`, search: `?limit=${limit ?? 5}&exclude_replies=${!!excludeReplies}`
}); });
return await (await fetch(tootURL)).json(); return await (await fetch(tootURL)).json();
} }
function loadToots() { function loadToots() {
getToots( getToots(account, maxToots ?? 5, excludeReplies === true, accountId).then((data) => {
account,
maxToots ?? 5,
excludeReplies === true,
accountId,
).then((data) => {
toots = data; toots = data;
loading = false; loading = false;
}); });
@ -90,9 +89,15 @@
{#snippet avatar(toot)} {#snippet avatar(toot)}
<a class="flex flex-row gap-2" href={toot.account.url}> <a class="flex flex-row gap-2" href={toot.account.url}>
<img class="rounded-md" width="48px" height="48px" src={toot.account.avatar} alt="{toot.account.username} avatar"/> <img
class="rounded-md"
width="48px"
height="48px"
src={toot.account.avatar}
alt="{toot.account.username} avatar"
/>
<div class="flex flex-col items-start"> <div class="flex flex-col items-start">
<span class="hover:underline font-bold h-6">{toot.account.display_name}</span> <span class="h-6 font-bold hover:underline">{toot.account.display_name}</span>
<span class="h-4 text-sm text-muted">@{toot.account.username}</span> <span class="h-4 text-sm text-muted">@{toot.account.username}</span>
</div> </div>
</a> </a>
@ -103,23 +108,26 @@
<div class="[&>p>span>a]:hover:underline"> <div class="[&>p>span>a]:hover:underline">
{@html sanitizeHtml(toot.content)} {@html sanitizeHtml(toot.content)}
</div> </div>
{#each toot.media_attachments.filter((att) => att.type === "image") as image} {#each toot.media_attachments.filter((att) => att.type === 'image') as image}
<a class="block rounded-md aspect-16/9 w-full overflow-hidden" href={image.url} target="_blank" rel="noopener noreferrer"> <a
<img class="h-full w-full object-cover" src={image.preview_url} alt={image.description}/> class="block aspect-16/9 w-full overflow-hidden rounded-md"
href={image.url}
target="_blank"
rel="noopener noreferrer"
>
<img class="h-full w-full object-cover" src={image.preview_url} alt={image.description} />
</a> </a>
{/each} {/each}
</div> </div>
{/snippet} {/snippet}
<ol class="w-full"> <ol class="w-full">
{#if loading} {#if loading}
{#each Array(maxToots ?? 5) as placeholder} {#each Array(maxToots ?? 5) as placeholder}
<li class="flex flex-col gap-3 px-4 py-3"> <li class="flex flex-col gap-3 px-4 py-3">
<div class="flex flex-row justify-between"> <div class="flex flex-row justify-between">
<div class="flex flex-row gap-2"> <div class="flex flex-row gap-2">
<Skeleton class="h-12 w-12 rounded-md"/> <Skeleton class="h-12 w-12 rounded-md" />
<div class="flex flex-col items-start gap-1"> <div class="flex flex-col items-start gap-1">
<Skeleton class="h-6 w-24"></Skeleton> <Skeleton class="h-6 w-24"></Skeleton>
<Skeleton class="h-4 w-20"></Skeleton> <Skeleton class="h-4 w-20"></Skeleton>
@ -136,14 +144,23 @@
{#if toot.reblog} {#if toot.reblog}
<div class="flex flex-row justify-between"> <div class="flex flex-row justify-between">
<div class="flex flex-col gap-1"> <div class="flex flex-col gap-1">
<a class="items-center flex flex-row gap-1" href={toot.account.url}> <a class="flex flex-row items-center gap-1" href={toot.account.url}>
<DoubleArrowUp /> <DoubleArrowUp />
<img class="rounded-md" width="23px" height="23px" src={toot.account.avatar} alt="{toot.account.username} avatar"/> <img
<span class="hover:underline font-bold h-6">{toot.account.display_name}</span> class="rounded-md"
width="23px"
height="23px"
src={toot.account.avatar}
alt="{toot.account.username} avatar"
/>
<span class="h-6 font-bold hover:underline">{toot.account.display_name}</span>
</a> </a>
{@render avatar(toot.reblog)} {@render avatar(toot.reblog)}
</div> </div>
<a class="flex flex-col items-center hover:underline text-sm text-muted" href={toot.url}> <a
class="flex flex-col items-center text-sm text-muted hover:underline"
href={toot.url}
>
<time datetime={toot.created_at}> <time datetime={toot.created_at}>
{new Date(toot.created_at).toLocaleDateString()} {new Date(toot.created_at).toLocaleDateString()}
</time> </time>
@ -156,7 +173,10 @@
{:else} {:else}
<div class="flex flex-row justify-between"> <div class="flex flex-row justify-between">
{@render avatar(toot)} {@render avatar(toot)}
<a class="flex flex-col items-center hover:underline text-sm text-muted" href={toot.url}> <a
class="flex flex-col items-center text-sm text-muted hover:underline"
href={toot.url}
>
<time datetime={toot.created_at}> <time datetime={toot.created_at}>
{new Date(toot.created_at).toLocaleDateString()} {new Date(toot.created_at).toLocaleDateString()}
</time> </time>

View file

@ -1,4 +1,4 @@
import Root from "./separator.svelte"; import Root from './separator.svelte';
export { export {
Root, Root,

View file

@ -1,19 +1,19 @@
<script lang="ts"> <script lang="ts">
import { Separator as SeparatorPrimitive } from "bits-ui"; import { Separator as SeparatorPrimitive } from 'bits-ui';
import { cn } from "$lib/utils"; import { cn } from '$lib/utils';
type $$Props = SeparatorPrimitive.Props; type $$Props = SeparatorPrimitive.Props;
let className: $$Props["class"] = undefined; let className: $$Props['class'] = undefined;
export let orientation: $$Props["orientation"] = "horizontal"; export let orientation: $$Props['orientation'] = 'horizontal';
export let decorative: $$Props["decorative"] = undefined; export let decorative: $$Props['decorative'] = undefined;
export { className as class }; export { className as class };
</script> </script>
<SeparatorPrimitive.Root <SeparatorPrimitive.Root
class={cn( class={cn(
"shrink-0 bg-border", 'shrink-0 bg-border',
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]", orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
className className
)} )}
{orientation} {orientation}

View file

@ -1,4 +1,4 @@
import { writable } from 'svelte/store'; import { writable } from 'svelte/store';
import {io} from "socket.io-client"; import { io } from 'socket.io-client';
export let socketStore = writable(io('https://status.neshweb.net/')); export let socketStore = writable(io('https://status.neshweb.net/'));

View file

@ -1,4 +1,4 @@
import {type Writable, writable} from 'svelte/store'; import { type Writable, writable } from 'svelte/store';
import type {Heartbeat} from "$lib/types/uptime-kuma-types"; import type { Heartbeat } from '$lib/types/uptime-kuma-types';
export let uptimeStore: Writable<Map<number, Heartbeat>> = writable(new Map()); export let uptimeStore: Writable<Map<number, Heartbeat>> = writable(new Map());

View file

@ -3,18 +3,20 @@
<script> <script>
import '../app.pcss'; import '../app.pcss';
import Header from './Header.svelte'; import Header from './Header.svelte';
import { socketStore } from "$lib/stores/socketStore"; import { socketStore } from '$lib/stores/socketStore';
import {beforeNavigate} from "$app/navigation"; import { beforeNavigate } from '$app/navigation';
$effect(() => { $effect(() => {
beforeNavigate((navigation) => { beforeNavigate((navigation) => {
const servers = navigation.to.url.pathname === "/servers" || navigation.from.url.pathname === "/servers" const servers =
const services = navigation.to.url.pathname === "/services" || navigation.from.url.pathname === "/services" navigation.to.url.pathname === '/servers' || navigation.from.url.pathname === '/servers';
if ( ! (servers && services) ) { const services =
$socketStore.close() navigation.to.url.pathname === '/services' || navigation.from.url.pathname === '/services';
if (!(servers && services)) {
$socketStore.close();
} }
}) });
}) });
</script> </script>
<Header /> <Header />

View file

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import {Separator} from "$lib/components/ui/separator"; import { Separator } from '$lib/components/ui/separator';
import {OpenInNewWindow} from "radix-icons-svelte"; import { OpenInNewWindow } from 'radix-icons-svelte';
import Emfed from "$lib/components/Emfed.svelte"; import Emfed from '$lib/components/Emfed.svelte';
</script> </script>
<svelte:head> <svelte:head>
@ -9,32 +9,55 @@
<meta name="description" content="Landing Page for neshweb.net" /> <meta name="description" content="Landing Page for neshweb.net" />
</svelte:head> </svelte:head>
<div class="grid max-h-full grid-cols-3 gap-4 justify-center overflow-auto p-8"> <div class="grid max-h-full grid-cols-3 justify-center gap-4 overflow-auto p-8">
<div class="flex flex-col items-center col-span-2"> <div class="col-span-2 flex flex-col items-center">
<div class="flex flex-col border rounded-md p-4 bg-black/55 backdrop-blur-sm gap-y-2"> <div class="flex flex-col gap-y-2 rounded-md border bg-black/55 p-4 backdrop-blur-sm">
<h1 class="text-2xl text-center" >Home Page</h1> <h1 class="text-center text-2xl">Home Page</h1>
<p>I'm not sure what to put here quite yet, maybe I'll think of something eventually. In the meantime I've linked some of my accounts in the sidebar to the right</p> <p>
I'm not sure what to put here quite yet, maybe I'll think of something eventually. In the
meantime I've linked some of my accounts in the sidebar to the right
</p>
</div> </div>
</div> </div>
<div class="flex flex-col gap-y-1 items-center border rounded-md bg-black/55 backdrop-blur-sm py-1"> <div
class="flex flex-col items-center gap-y-1 rounded-md border bg-black/55 py-1 backdrop-blur-sm"
>
<p class="font-bold">Fediverse Accounts</p> <p class="font-bold">Fediverse Accounts</p>
<Separator class="max-w-80" /> <Separator class="max-w-80" />
<a rel="me" href="https://mastodon.neshweb.net/@neshura" target="_blank" class="flex flex-row gap-1 items-center hover:text-secondary"> <a
rel="me"
href="https://mastodon.neshweb.net/@neshura"
target="_blank"
class="flex flex-row items-center gap-1 hover:text-secondary"
>
Mastodon Mastodon
<OpenInNewWindow /> <OpenInNewWindow />
</a> </a>
<a rel="noopener noreferrer" href="https://bookwormstory.social/u/Neshura" target="_blank" class="flex flex-row gap-1 items-center hover:text-secondary"> <a
rel="noopener noreferrer"
href="https://bookwormstory.social/u/Neshura"
target="_blank"
class="flex flex-row items-center gap-1 hover:text-secondary"
>
Lemmy Lemmy
<OpenInNewWindow /> <OpenInNewWindow />
</a> </a>
<a rel="noopener noreferrer" href="https://neshweb.tv/c/neshura_ch/videos" target="_blank" class="flex flex-row gap-1 items-center hover:text-secondary"> <a
rel="noopener noreferrer"
href="https://neshweb.tv/c/neshura_ch/videos"
target="_blank"
class="flex flex-row items-center gap-1 hover:text-secondary"
>
PeerTube PeerTube
<OpenInNewWindow /> <OpenInNewWindow />
</a> </a>
<Separator class="max-w-80" /> <Separator class="max-w-80" />
<p class="font-bold">Mastodon Feed</p> <p class="font-bold">Mastodon Feed</p>
<Separator class="max-w-80" /> <Separator class="max-w-80" />
<Emfed account="https://mastodon.neshweb.net/@neshura" maxToots={4} accountId="109199738141333007"/> <Emfed
account="https://mastodon.neshweb.net/@neshura"
maxToots={4}
accountId="109199738141333007"
/>
</div> </div>
</div> </div>

View file

@ -16,4 +16,3 @@
{version} {version}
</a> </a>
</p> </p>

View file

@ -6,7 +6,7 @@
import type { Heartbeat } from '$lib/types/uptime-kuma-types'; import type { Heartbeat } from '$lib/types/uptime-kuma-types';
import ServerCard from '$lib/components/ServerCard.svelte'; import ServerCard from '$lib/components/ServerCard.svelte';
import { socketStore } from '$lib/stores/socketStore'; import { socketStore } from '$lib/stores/socketStore';
import {uptimeStore} from "$lib/stores/uptimeStore"; import { uptimeStore } from '$lib/stores/uptimeStore';
let { data }: { data: { promise: Promise<string> } } = $props(); let { data }: { data: { promise: Promise<string> } } = $props();
@ -30,12 +30,11 @@
if (token) { if (token) {
if (!socket.connected) { if (!socket.connected) {
socket.connect(); socket.connect();
} } else {
else { console.log('already connected');
console.log("already connected");
} }
socket.on('connect', () => { socket.on('connect', () => {
console.log("logging in") console.log('logging in');
socket.emit('loginByToken', token, () => {}); socket.emit('loginByToken', token, () => {});
}); });

View file

@ -5,9 +5,9 @@
import type { Service } from '$lib/types/data-types'; import type { Service } from '$lib/types/data-types';
import { io } from 'socket.io-client'; import { io } from 'socket.io-client';
import type { Heartbeat } from '$lib/types/uptime-kuma-types'; import type { Heartbeat } from '$lib/types/uptime-kuma-types';
import {socketStore} from "$lib/stores/socketStore"; import { socketStore } from '$lib/stores/socketStore';
import {onDestroy} from "svelte"; import { onDestroy } from 'svelte';
import {uptimeStore} from "$lib/stores/uptimeStore"; import { uptimeStore } from '$lib/stores/uptimeStore';
let { data }: { data: { promise: Promise<string> } } = $props(); let { data }: { data: { promise: Promise<string> } } = $props();
@ -29,12 +29,11 @@
if (token) { if (token) {
if (!socket.connected) { if (!socket.connected) {
socket.connect(); socket.connect();
} } else {
else { console.log('connected');
console.log("connected")
} }
socket.on('connect', () => { socket.on('connect', () => {
console.log("login") console.log('login');
socket.emit('loginByToken', token, () => {}); socket.emit('loginByToken', token, () => {});
}); });