Compare commits

..

70 commits

Author SHA1 Message Date
dc27c9bf63
Fix Syntax Error
All checks were successful
Run Tests on Code / test (push) Successful in 36s
Build and Release Docker Image / build (push) Successful in 2m21s
Build and Release Docker Image / release (push) Successful in 3m11s
Build and Release Docker Image / test (push) Successful in 12m56s
2024-01-03 21:38:09 +01:00
bdc0833e94
Restart Server after first lighthouse run if it crashed or closed
Some checks failed
Run Tests on Code / test (push) Successful in 1m10s
Build and Release Docker Image / test (push) Failing after 3m2s
Build and Release Docker Image / build (push) Has been skipped
Build and Release Docker Image / release (push) Has been skipped
2024-01-03 21:25:14 +01:00
1d2be60c1e
Fix crash on /services page when credentials file not present
Some checks failed
Run Tests on Code / test (push) Successful in 9m44s
Build and Release Docker Image / test (push) Has been cancelled
Build and Release Docker Image / build (push) Has been cancelled
Build and Release Docker Image / release (push) Has been cancelled
2024-01-03 21:09:58 +01:00
769818b4f4
Release Candidate 1.0.0-rc.3
Some checks failed
Run Tests on Code / test (push) Successful in 5m9s
Build and Release Docker Image / release (push) Successful in 1m20s
Build and Release Docker Image / build (push) Has been cancelled
Build and Release Docker Image / test (push) Has been cancelled
2024-01-03 20:41:02 +01:00
cedf89e106
linting changes
Some checks failed
Run Tests on Code / test (push) Has been cancelled
2024-01-03 20:40:52 +01:00
63197220a6
Add socket.io to package.json
Some checks failed
Run Tests on Code / test (push) Has been cancelled
2024-01-03 20:40:05 +01:00
5d8be9d77c
Integrate with Uptime Kuma Socket.io API
Some checks failed
Run Tests on Code / test (push) Has been cancelled
2024-01-03 20:39:53 +01:00
ac6d14b4cf
Add credentials.json to gitignore
All checks were successful
Run Tests on Code / test (push) Successful in 19s
2024-01-03 20:39:18 +01:00
8ae350db27
Split up Unlighthouse Runs + Build Site in release test step + fix pull request actions
All checks were successful
Run Tests on Code / test (push) Successful in 16s
2024-01-02 03:30:14 +01:00
806e4f1277
Fix --no-sandbox export
All checks were successful
Run Tests on Code / test (push) Successful in 15s
Build and Release Docker Image / test (push) Successful in 3m37s
Build and Release Docker Image / build (push) Successful in 2m27s
Build and Release Docker Image / release (push) Successful in 7s
2024-01-02 03:22:45 +01:00
997f80a16d
Verbose export of --no-sandbox flag
All checks were successful
Run Tests on Code / test (push) Successful in 19s
2024-01-02 03:20:33 +01:00
91ca7c489e
Add Chromium --no-sandbox flag
Some checks failed
Run Tests on Code / test (push) Successful in 16s
Build and Release Docker Image / test (push) Failing after 2m7s
Build and Release Docker Image / build (push) Has been skipped
Build and Release Docker Image / release (push) Has been skipped
2024-01-02 03:16:41 +01:00
5be5e206f2
Add urls to unlighthouse config 2024-01-02 03:16:05 +01:00
2e257d3bb2
Fix bash process spawning
Some checks failed
Run Tests on Code / test (push) Successful in 15s
Build and Release Docker Image / test (push) Failing after 1m48s
Build and Release Docker Image / build (push) Has been skipped
Build and Release Docker Image / release (push) Has been skipped
2024-01-02 03:02:56 +01:00
35c78a50e2
Start server for unlighthouse in dev mode
Some checks failed
Run Tests on Code / test (push) Successful in 26s
Build and Release Docker Image / build (push) Has been cancelled
Build and Release Docker Image / release (push) Has been cancelled
Build and Release Docker Image / test (push) Has been cancelled
2024-01-02 02:58:54 +01:00
cad1b814de
Fix indenting for release actions
Some checks failed
Run Tests on Code / test (push) Successful in 19s
Build and Release Docker Image / test (push) Failing after 2m11s
Build and Release Docker Image / build (push) Has been skipped
Build and Release Docker Image / release (push) Has been skipped
2024-01-02 02:52:55 +01:00
d2841ac338
Revert 1263f7b984
Some checks failed
Run Tests on Code / test (push) Successful in 24s
Build and Release Docker Image / test (push) Failing after 2m15s
2024-01-02 02:50:21 +01:00
2c8600c297
Add apt update to dependency install step
Some checks failed
Run Tests on Code / test (push) Successful in 25s
Build and Release Docker Image / test (push) Failing after 33s
2024-01-02 02:47:42 +01:00
1263f7b984
Correct apt package from chromium to chromium-browser
Some checks failed
Run Tests on Code / test (push) Successful in 20s
Build and Release Docker Image / test (push) Failing after 25s
2024-01-02 02:46:33 +01:00
ffd5125d3f
Fix apt install step
Some checks failed
Run Tests on Code / test (push) Successful in 18s
Build and Release Docker Image / test (push) Failing after 15s
2024-01-02 02:42:57 +01:00
90a500c8e8
Add chromium dependency to Unlighthouse install step
Some checks failed
Run Tests on Code / test (push) Successful in 19s
Build and Release Docker Image / test (push) Has been cancelled
2024-01-02 02:41:55 +01:00
1537f8a410
Prettier Changes
Some checks failed
Run Tests on Code / test (push) Successful in 23s
Build and Release Docker Image / test (push) Failing after 43s
2024-01-02 02:39:22 +01:00
e9c805c36b
Release Candidate 1.0.0-rc.2
Some checks failed
Run Tests on Code / test (push) Failing after 44s
Build and Release Docker Image / test (push) Failing after 1m0s
2024-01-02 02:36:24 +01:00
fb8c4c4fd9
Add unlighthouse to Release + Pull Request Actions, Add Unlighthouse config file
Some checks failed
Run Tests on Code / test (push) Has been cancelled
2024-01-02 02:36:13 +01:00
d075b04ac8
Add title and description to placeholder pages
Some checks failed
Run Tests on Code / test (push) Failing after 19s
2024-01-02 02:11:51 +01:00
93954c86ee
Add Skeleton UI component from shadcn 2024-01-02 02:11:36 +01:00
f80d56c057
Apply renaming of Card -> ServiceCard to the services page 2024-01-02 02:11:23 +01:00
1a761d60cc
Rename Card to ServiceCard. Add proper icon handling 2024-01-02 02:10:44 +01:00
52593efb62
Dynamically fetch list of icons and services and pass both to the ServiceCard 2024-01-02 02:10:18 +01:00
994c0bd2a0
Split pages.json to severs.json and services.json, move to /static/data/ 2024-01-02 02:09:50 +01:00
466f637207
API endpoint returning /data/services.json 2024-01-02 02:09:23 +01:00
b4f295bf46
API endpoint listing all icons in icons directory 2024-01-02 02:09:07 +01:00
e4cce6239d
Add IconType enum, make Service fields readonly 2024-01-02 02:08:43 +01:00
62d7fec6d7
Add separate -36 variants for 36px avifs 2024-01-02 02:08:10 +01:00
181a4e9ff9
Add unlighthouse to gitignore 2024-01-02 02:07:37 +01:00
5ad7941c9b
Add .idea directory to gitignore, add pages for About and Servers
Some checks failed
Run Tests on Code / test (push) Failing after 24s
2024-01-01 22:59:52 +01:00
06ddb41900
Remove dummy data on Home page
Some checks failed
Run Tests on Code / test (push) Failing after 25s
2024-01-01 22:55:35 +01:00
bed766f72f
Switch to 2 Wide indents
All checks were successful
Run Tests on Code / test (push) Successful in 17s
2024-01-01 22:53:35 +01:00
6e3bbc176a
Use registry with buildx
All checks were successful
Run Tests on Code / test (push) Successful in 22s
Build and Release Docker Image / test (push) Successful in 22s
Build and Release Docker Image / build (push) Successful in 4m5s
Build and Release Docker Image / release (push) Successful in 20s
2024-01-01 21:33:52 +01:00
0b82f23d3c
USe node:20-bookworm for faster Actions
All checks were successful
Run Tests on Code / test (push) Successful in 20s
2024-01-01 21:30:03 +01:00
698daed1c6
Fix Dockerfile
Some checks failed
Run Tests on Code / test (push) Successful in 24s
Build and Release Docker Image / test (push) Successful in 36s
Build and Release Docker Image / release (push) Has been cancelled
Build and Release Docker Image / build (push) Has been cancelled
2024-01-01 21:21:07 +01:00
7e7e560424
Fix Actions tag reference #2
Some checks failed
Run Tests on Code / test (push) Successful in 22s
Build and Release Docker Image / test (push) Successful in 26s
Build and Release Docker Image / release (push) Has been cancelled
Build and Release Docker Image / build (push) Has been cancelled
2024-01-01 21:09:46 +01:00
251743d4d2
Fix Actions tag reference
Some checks failed
Run Tests on Code / test (push) Successful in 28s
Build and Release Docker Image / test (push) Successful in 19s
Build and Release Docker Image / release (push) Has been cancelled
Build and Release Docker Image / build (push) Has been cancelled
2024-01-01 21:04:32 +01:00
1f15215ce0
Actions Debugging
Some checks failed
Run Tests on Code / test (push) Successful in 20s
Build and Release Docker Image / test (push) Successful in 27s
Build and Release Docker Image / release (push) Has been cancelled
Build and Release Docker Image / build (push) Has been cancelled
2024-01-01 20:51:36 +01:00
04e0bc6ccb
Forgejo Actions Debugging
Some checks failed
Run Tests on Code / test (push) Successful in 21s
Build and Release Docker Image / test (push) Successful in 29s
Build and Release Docker Image / build (push) Failing after 12s
Build and Release Docker Image / release (push) Has been skipped
2024-01-01 20:47:58 +01:00
7248b26278
FIx Actions tag variables
Some checks failed
Run Tests on Code / test (push) Successful in 20s
Build and Release Docker Image / test (push) Successful in 18s
Build and Release Docker Image / build (push) Failing after 21s
Build and Release Docker Image / release (push) Has been skipped
2024-01-01 20:33:29 +01:00
798bf7cba9
Add correct type to Card prop
Some checks failed
Run Tests on Code / test (push) Successful in 3m59s
Build and Release Docker Image / test (push) Successful in 6m28s
Build and Release Docker Image / build (push) Failing after 11s
Build and Release Docker Image / release (push) Has been skipped
2024-01-01 20:18:58 +01:00
4f04bb7b49
Remove Eslint from linting job due to likely incompat with Svelte 5 2024-01-01 20:18:34 +01:00
04b1bd79df
Add service type
Some checks failed
Run Tests on Code / test (push) Failing after 3m34s
2024-01-01 20:10:19 +01:00
7740f011bd
Prettier overwritten changes revert + eslint ignore ui components
Some checks failed
Run Tests on Code / test (push) Failing after 1m53s
2024-01-01 20:02:04 +01:00
9d5c6db7da
Prettier changes
Some checks failed
Run Tests on Code / test (push) Has been cancelled
2024-01-01 20:00:35 +01:00
94a8d2a8e7
only check src directory 2024-01-01 19:59:06 +01:00
3fe773576c
Release Candidate 1.0.0-rc.1
Some checks failed
Run Tests on Code / test (push) Failing after 3m51s
Build and Release Docker Image / test (push) Failing after 4m49s
Build and Release Docker Image / build (push) Has been skipped
Build and Release Docker Image / release (push) Has been skipped
2024-01-01 19:45:06 +01:00
4eeb81fe17
Push Docker image to preview for -rc tags
Some checks failed
Run Tests on Code / test (push) Has been cancelled
2024-01-01 19:44:39 +01:00
009d75bd2a
Add AGPLv3 License
Some checks failed
Run Tests on Code / test (push) Failing after 3m36s
2024-01-01 19:38:45 +01:00
e2cdd0f81a
Add accessibility fields
Some checks failed
Run Tests on Code / test (push) Has been cancelled
2024-01-01 19:36:42 +01:00
387a950b69
Use avif instead of png/jpg 2024-01-01 19:36:27 +01:00
dc04b71304
Add Link Icon to card
Some checks failed
Run Tests on Code / test (push) Failing after 1m27s
2024-01-01 18:40:02 +01:00
a0d16eb8db
Added services page with unfinished service card element
Some checks failed
Run Tests on Code / test (push) Failing after 22s
2024-01-01 07:07:55 +01:00
d8dba19353
Switched port to 8000 2024-01-01 07:07:27 +01:00
04ecead4cf
Added colors to tailwind config 2024-01-01 07:07:18 +01:00
fe1c776f54
Adjusted pending color 2024-01-01 07:07:04 +01:00
ec46d06564
Update gitignore
Some checks failed
Run Tests on Code / test (push) Failing after 20s
2024-01-01 05:56:51 +01:00
ec6625ace3
Delete config templates 2024-01-01 05:56:41 +01:00
668a5ce6e7
Add Navbar using shadcn Button 2024-01-01 05:56:29 +01:00
bdc8203026
Add postcss/tailwind/shadcn 2024-01-01 05:56:10 +01:00
980a44c2ea
Move icons to svelte ordering 2024-01-01 05:55:35 +01:00
ba070f387c
Add Svelte 5/SvelteKit 2 2024-01-01 05:55:11 +01:00
6b58950e78
Remove next.js 2024-01-01 05:53:14 +01:00
b534bebad9
Adopt Actions changes from other repos 2024-01-01 05:51:51 +01:00
30 changed files with 141 additions and 987 deletions

View file

@ -58,10 +58,7 @@ jobs:
run: yarn build run: yarn build
- name: Start Server - name: Start Server
run: | run: yarn preview &
export KUMA_USERNAME=${{ secrets.KUMA_USERNAME }}
export KUMA_PASSWORD=${{ secrets.KUMA_PASSWORD }}
yarn preview &
- name: Run Unlighthouse for Desktop - name: Run Unlighthouse for Desktop
run: unlighthouse-ci --build-static --desktop --outputPath reports/desktop run: unlighthouse-ci --build-static --desktop --outputPath reports/desktop
@ -69,8 +66,6 @@ jobs:
- name: Refresh Server - name: Refresh Server
run: | run: |
if ! pgrep -f "node /usr/bin/yarn" ; then if ! pgrep -f "node /usr/bin/yarn" ; then
export KUMA_USERNAME=${{ secrets.KUMA_USERNAME }}
export KUMA_PASSWORD=${{ secrets.KUMA_PASSWORD }}
yarn preview & yarn preview &
fi fi
@ -125,7 +120,7 @@ jobs:
runs-on: docker runs-on: docker
steps: steps:
- name: Release New Version - name: Release New Version
uses: actions/forgejo-release@v2 uses: actions/forgejo-release@v1
with: with:
direction: upload direction: upload
url: https://forgejo.neshweb.net url: https://forgejo.neshweb.net

View file

@ -44,14 +44,22 @@ jobs:
- name: Run Linter - name: Run Linter
run: yarn lint run: yarn lint
- name: Check if Version in package.json matches Tag
run: |
echo "Test"
VERSION=$(cat package.json | grep "version" | sed 's/.*://' | tr -d , | tr -d \" )
if test $VERSION != "${{ github.ref_name }}"; then
echo "Expected Version is: '${{ github.ref_name }}' actual Version is: '$VERSION'";
exit 1
else
echo "Version is: '$VERSION'";
fi
- name: Build Site - name: Build Site
run: yarn build run: yarn build
- name: Start Server - name: Start Server
run: | run: yarn preview &
export KUMA_USERNAME=${{ secrets.KUMA_USERNAME }}
export KUMA_PASSWORD=${{ secrets.KUMA_PASSWORD }}
yarn preview &
- name: Run Unlighthouse for Desktop - name: Run Unlighthouse for Desktop
run: unlighthouse-ci --build-static --desktop --outputPath reports/desktop run: unlighthouse-ci --build-static --desktop --outputPath reports/desktop
@ -59,8 +67,6 @@ jobs:
- name: Refresh Server - name: Refresh Server
run: | run: |
if ! pgrep -f "node /usr/bin/yarn" ; then if ! pgrep -f "node /usr/bin/yarn" ; then
export KUMA_USERNAME=${{ secrets.KUMA_USERNAME }}
export KUMA_PASSWORD=${{ secrets.KUMA_PASSWORD }}
yarn preview & yarn preview &
fi fi

View file

@ -14,8 +14,6 @@ WORKDIR /app
COPY --from=build /app . COPY --from=build /app .
ENV NODE_ENV production ENV NODE_ENV production
ENV KUMA_USERNAME ''
ENV KUMA_PASSWORD ''
EXPOSE 8000 EXPOSE 8000
CMD ["yarn", "preview"] CMD ["yarn", "preview"]

View file

@ -2,7 +2,7 @@
"name": "main-site", "name": "main-site",
"author": "Neshura", "author": "Neshura",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"version": "1.0.0", "version": "1.0.0-rc.3",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",
@ -41,10 +41,9 @@
}, },
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"bits-ui": "^0.13.2", "bits-ui": "^0.13.0",
"clsx": "^2.1.0", "clsx": "^2.1.0",
"radix-icons-svelte": "^1.2.1", "radix-icons-svelte": "^1.2.1",
"sanitize-html": "^2.11.0",
"socket.io": "^4.7.2", "socket.io": "^4.7.2",
"socket.io-client": "^4.7.2", "socket.io-client": "^4.7.2",
"tailwind-merge": "^2.2.0", "tailwind-merge": "^2.2.0",

View file

@ -69,9 +69,9 @@
.nordlys { .nordlys {
--background: 0 0% 0%; /* #000000 */ --background: 0 0% 0%; /* #000000 */
--foreground: 183 100% 96%; /* #14b8a6 */ --foreground: 173 80% 40%; /* #14b8a6 */
--muted: 180 10% 66%; /* #ecfeff */ --muted: 183 100% 96%; /* #ecfeff */
--muted-foreground: 176 61% 19%; /* #134e4a */ --muted-foreground: 176 61% 19%; /* #134e4a */
--popover: 0 0% 0%; /* #000000 */ --popover: 0 0% 0%; /* #000000 */
@ -83,10 +83,10 @@
--border: 183 100% 96%; /* #ecfeff */ --border: 183 100% 96%; /* #ecfeff */
--input: 183 100% 96%; /* #ecfeff */ --input: 183 100% 96%; /* #ecfeff */
--primary: 183 100% 96%; /* #14b8a6 */ --primary: 173 80% 40%; /* #14b8a6 */
--primary-foreground: 221 39% 11%; /* #111827 */ --primary-foreground: 221 39% 11%; /* #111827 */
--secondary: 173 80% 40%; /* #ecfeff */ --secondary: 183 100% 96%; /* #ecfeff */
--secondary-foreground: 173 80% 40%; /* #14b8a6 */ --secondary-foreground: 173 80% 40%; /* #14b8a6 */
--accent: 183 100% 96%; /* #ecfeff */ --accent: 183 100% 96%; /* #ecfeff */

View file

@ -1,193 +0,0 @@
<svelte:options runes={true} />
<script lang="ts">
import { onMount } from 'svelte';
import sanitizeHtml from 'sanitize-html';
import { Skeleton } from '$lib/components/ui/skeleton/index.js';
import { DoubleArrowUp } from 'radix-icons-svelte';
let {
account,
maxToots,
accountId,
excludeReplies
}: { account: string; maxToots?: number; accountId?: string; excludeReplies: boolean } = $props();
let toots: Toot[] = $state([]);
let loading = $state(false);
onMount(() => {
loading = true;
loadToots(account, accountId, maxToots, excludeReplies);
});
interface Toot {
created_at: string;
in_reply_to_id: string | null;
content: string;
url: string;
account: {
username: string;
display_name: string;
avatar: string;
url: string;
};
reblog?: Toot;
media_attachments: {
type: 'unknown' | 'image' | 'gifv' | 'video' | 'audio';
url: string;
preview_url: string;
description: string;
blurhash: string;
}[];
}
export async function getToots(
userURL: string,
limit: number,
excludeReplies: boolean,
accountId?: string
): Promise<Toot[]> {
const url = new URL(userURL);
// Either use the account id specified or look it up based on the username
// in the link.
const userId: string =
accountId ??
(await (async () => {
// Extract username from URL.
const parts = /@(\w+)$/.exec(url.pathname);
if (!parts) {
throw 'not a Mastodon user URL';
}
const username = parts[1];
// Look up user ID from username.
const lookupURL = Object.assign(new URL(url), {
pathname: '/api/v1/accounts/lookup',
search: `?acct=${username}`
});
return (await (await fetch(lookupURL)).json())['id'];
})());
// Fetch toots.
const tootURL = Object.assign(new URL(url), {
pathname: `/api/v1/accounts/${userId}/statuses`,
search: `?limit=${limit ?? 5}&exclude_replies=${!!excludeReplies}`
});
return await (await fetch(tootURL)).json();
}
function loadToots() {
getToots(account, maxToots ?? 5, excludeReplies === true, accountId).then((data) => {
toots = data;
loading = false;
});
}
</script>
{#snippet avatar(toot)}
<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"
/>
<div class="flex flex-col items-start">
<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>
</div>
</a>
{/snippet}
{#snippet body(toot)}
<div>
<div class="[&>p>span>a]:hover:underline">
{@html sanitizeHtml(toot.content)}
</div>
{#each toot.media_attachments.filter((att) => att.type === 'image') as image}
<a
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>
{/each}
</div>
{/snippet}
<ol class="h-[40rem] w-full overflow-y-auto">
{#if loading}
{#each Array(maxToots ?? 5) as placeholder}
<li class="flex flex-col gap-3 px-4 py-3">
<div class="flex flex-row justify-between">
<div class="flex flex-row gap-2">
<Skeleton class="h-12 w-12 rounded-md" />
<div class="flex flex-col items-start gap-1">
<Skeleton class="h-6 w-24"></Skeleton>
<Skeleton class="h-4 w-20"></Skeleton>
</div>
</div>
<Skeleton class="h-10 w-16" />
</div>
<Skeleton class="h-36 w-full"></Skeleton>
</li>
{/each}
{:else}
{#each toots as toot}
<li class="flex flex-col gap-3 px-4 py-3">
{#if toot.reblog}
<div class="flex flex-row justify-between">
<div class="flex flex-col gap-1">
<a class="flex flex-row items-center gap-1" href={toot.account.url}>
<DoubleArrowUp />
<img
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>
{@render avatar(toot.reblog)}
</div>
<a
class="flex flex-col items-center text-sm text-muted hover:underline"
href={toot.url}
>
<time datetime={toot.created_at}>
{new Date(toot.created_at).toLocaleDateString()}
</time>
<time datetime={toot.created_at}>
{new Date(toot.created_at).toLocaleTimeString()}
</time>
</a>
</div>
{@render body(toot.reblog)}
{:else}
<div class="flex flex-row justify-between">
{@render avatar(toot)}
<a
class="flex flex-col items-center text-sm text-muted hover:underline"
href={toot.url}
>
<time datetime={toot.created_at}>
{new Date(toot.created_at).toLocaleDateString()}
</time>
<time datetime={toot.created_at}>
{new Date(toot.created_at).toLocaleTimeString()}
</time>
</a>
</div>
{@render body(toot)}
{/if}
</li>
{/each}
{/if}
</ol>

View file

@ -1,212 +0,0 @@
<svelte:options runes={true} />
<script lang="ts">
import { Clipboard, Copy, OpenInNewWindow } from 'radix-icons-svelte';
import { quintInOut } from 'svelte/easing';
import { slide } from 'svelte/transition';
import { IconType, type Server } from '$lib/types/data-types';
import { Skeleton } from '$lib/components/ui/skeleton';
import type { Heartbeat } from '$lib/types/uptime-kuma-types';
import { Button } from '$lib/components/ui/button';
let { server, icons, monitor } = $props<{
server: Server;
icons: Array<string>;
monitor?: Heartbeat;
}>();
let status = $state(4);
let hover = $state({
title: false,
link: false,
ext: false
});
let img_source: string = $state('');
function copyToClipboard(value: string) {
navigator.clipboard.writeText(value);
}
function checkForImage(server: Server) {
const rootSplit = server.icon.split('/');
const root = rootSplit[rootSplit.length - 1];
if (icons.includes(`${root}.${server.iconType}`)) {
img_source = `${server.icon}.${server.iconType}`;
} else {
img_source = '';
}
}
$effect(() => {
if (typeof server.id === 'undefined') {
status = 99;
}
if (typeof monitor !== 'undefined') {
status = monitor.status;
}
if (icons.length != 0 && typeof server.icon !== 'undefined') {
const rootSplit = server.icon.split('/');
const root = rootSplit[rootSplit.length - 1];
if (server.iconType === IconType.SVG) {
checkForImage(server);
} else {
if (icons.includes(`${root}-36.${server.iconType}`)) {
img_source = `${server.icon}-36.${server.iconType}`;
} else {
checkForImage(server);
}
}
}
});
</script>
<div
class="flex h-48 w-[28rem] flex-col gap-y-3 rounded-xl border-t-4
{status == 99
? 'border-primary'
: status == 0
? 'border-offline'
: status == 1
? 'border-online'
: status == 2
? 'border-pending'
: status == 3
? 'border-maintenance'
: 'border-maintenance'}
z-0 bg-black/55 p-4 backdrop-blur-sm"
>
<div class="flex flex-row justify-between">
<div
class="flex flex-row items-center gap-1"
on:mouseover={() => (hover.title = true)}
on:mouseleave={() => (hover.title = false)}
>
{#if typeof server.icon !== 'undefined'}
{#if img_source != ''}
<img
width="24px"
class="h-6 w-6 cursor-pointer"
src={img_source}
alt="{server.name} Logo"
/>
{:else}
<Skeleton class="h-6 w-6 rounded-full" />
{/if}
{:else}{/if}
{#if typeof server.href !== 'undefined'}
<a href={server.href} class="font-bold {!hover.title || 'text-secondary'}">{server.name}</a>
{#if hover.title}
<div
transition:slide={{ delay: 100, duration: 200, easing: quintInOut, axis: 'x' }}
class="grid items-center"
>
<OpenInNewWindow
color={hover.title ? 'hsl(var(--secondary))' : 'hsl(var(--primary)'}
class="self-center"
/>
</div>
{/if}
{:else}
<h2 class="font-bold">{server.name}</h2>
{/if}
</div>
{#if typeof server.id !== 'undefined'}
<h1
class="w-16 rounded-md border-b-2
{status == 0
? 'border-offline'
: status == 1
? 'border-online'
: status == 2
? 'border-pending'
: status == 3
? 'border-maintenance'
: 'border-maintenance'}
text-center text-sm
{status == 0
? 'text-offline'
: status == 1
? 'text-online'
: status == 2
? 'text-pending'
: status == 3
? 'text-maintenance'
: 'text-maintenance'}"
>
{status == 0
? 'Offline'
: status == 1
? 'Online'
: status == 2
? 'Pending'
: status == 3
? 'Maint.'
: 'Loading'}
</h1>
{/if}
</div>
<p class="text-wrap text-center text-sm">{server.desc}</p>
{#if typeof server.connection !== 'undefined'}
<div class="flex w-full flex-col items-center">
<Button
variant="ghost"
class=" flex w-fit flex-row items-center gap-1 rounded-sm border px-2 py-1 text-center font-mono text-sm font-bold
hover:border-primary hover:bg-transparent hover:text-primary/60
active:border-secondary active:bg-black/70 active:text-secondary"
on:click={() => copyToClipboard(server.connection)}
>
{server.connection}
<Copy />
</Button>
</div>
{/if}
<div class="grid {server.extLink ? 'grid-cols-2' : 'grid-cols-1'} mt-auto justify-items-center">
{#if typeof server.href !== 'undefined'}
<a
class="flex flex-row rounded-md border-x-2 px-2 text-sm hover:border-secondary hover:text-secondary"
href={server.href}
on:mouseover={() => (hover.link = true)}
on:mouseleave={() => (hover.link = false)}
>
Open
{#if hover.link}
<div
transition:slide={{ delay: 100, duration: 200, easing: quintInOut, axis: 'x' }}
class="grid items-center pl-1 pr-0"
>
<OpenInNewWindow
color={hover.link ? 'hsl(var(--secondary))' : 'hsl(var(--primary)'}
class="self-center"
/>
</div>
{/if}
</a>
{/if}
{#if server.extLink}
<a
class="flex flex-row rounded-md border-x-2 px-2 text-sm hover:border-secondary hover:text-secondary"
href={server.extLink}
on:mouseover={() => (hover.ext = true)}
on:mouseleave={() => (hover.ext = false)}
>
Official Site
{#if hover.ext}
<div
transition:slide={{ delay: 100, duration: 200, easing: quintInOut, axis: 'x' }}
class="grid items-center pl-1 pr-0"
>
<OpenInNewWindow
color={hover.ext ? 'hsl(var(--secondary))' : 'hsl(var(--primary)'}
class="self-center"
/>
</div>
{/if}
</a>
{/if}
</div>
</div>

View file

@ -37,6 +37,9 @@
$effect(() => { $effect(() => {
if (typeof monitor !== 'undefined') { if (typeof monitor !== 'undefined') {
if (monitor.monitorID == 9) {
console.log('Vaultwarden: ', monitor.status);
}
status = monitor.status; status = monitor.status;
} }
if (icons.length != 0) { if (icons.length != 0) {
@ -57,7 +60,7 @@
</script> </script>
<div <div
class="flex h-48 w-[28rem] flex-col gap-y-3 rounded-xl border-t-4 class="flex h-48 w-[28rem] flex-col gap-y-2 rounded-xl border-t-4
{status == 0 {status == 0
? 'border-offline' ? 'border-offline'
: status == 1 : status == 1
@ -67,9 +70,9 @@
: status == 3 : status == 3
? 'border-maintenance' ? 'border-maintenance'
: 'border-maintenance'} : 'border-maintenance'}
z-0 bg-black/55 p-4 backdrop-blur-sm" bg-black/55 p-4"
> >
<div class="flex flex-row justify-between"> <div class="flex flex-row justify-between pb-4">
<div <div
class="flex flex-row items-center gap-1" class="flex flex-row items-center gap-1"
on:mouseover={() => (hover.title = true)} on:mouseover={() => (hover.title = true)}
@ -87,14 +90,18 @@
<Skeleton class="h-6 w-6 rounded-full" /> <Skeleton class="h-6 w-6 rounded-full" />
{/if} {/if}
{:else}{/if} {:else}{/if}
<a href={service.href} class="font-bold {!hover.title || 'text-secondary'}">{service.name}</a> <a
href={service.href}
class="font-bold text-accent {hover.title ? 'text-primary' : 'text-secondary'}"
>{service.name}</a
>
{#if hover.title} {#if hover.title}
<div <div
transition:slide={{ delay: 100, duration: 200, easing: quintInOut, axis: 'x' }} transition:slide={{ delay: 100, duration: 200, easing: quintInOut, axis: 'x' }}
class="grid items-center" class="grid items-center"
> >
<OpenInNewWindow <OpenInNewWindow
color={hover.title ? 'hsl(var(--secondary))' : 'hsl(var(--primary)'} color={hover.title ? 'hsl(var(--primary))' : 'hsl(var(--secondary)'}
class="self-center" class="self-center"
/> />
</div> </div>
@ -134,11 +141,11 @@
: 'Loading'} : 'Loading'}
</h1> </h1>
</div> </div>
<p class="text-wrap text-center text-sm">{service.desc}</p> <p class="text-wrap text-center text-sm text-accent">{service.desc}</p>
<p class="text-center text-sm font-bold text-destructive">{service.warn}</p> <p class="text-center text-sm font-bold text-destructive">{service.warn}</p>
<div class="grid {service.extLink ? 'grid-cols-2' : 'grid-cols-1'} mt-auto justify-items-center"> <div class="grid {service.extLink ? 'grid-cols-2' : 'grid-cols-1'} mt-auto justify-items-center">
<a <a
class="flex flex-row rounded-md border-x-2 px-2 text-sm hover:border-secondary hover:text-secondary" class="flex flex-row rounded-md border-x-2 px-2 text-sm text-accent hover:border-primary hover:text-primary"
href={service.href} href={service.href}
on:mouseover={() => (hover.link = true)} on:mouseover={() => (hover.link = true)}
on:mouseleave={() => (hover.link = false)} on:mouseleave={() => (hover.link = false)}
@ -150,7 +157,7 @@
class="grid items-center pl-1 pr-0" class="grid items-center pl-1 pr-0"
> >
<OpenInNewWindow <OpenInNewWindow
color={hover.link ? 'hsl(var(--secondary))' : 'hsl(var(--primary)'} color={hover.link ? 'hsl(var(--primary))' : 'hsl(var(--secondary)'}
class="self-center" class="self-center"
/> />
</div> </div>
@ -158,7 +165,7 @@
</a> </a>
{#if service.extLink} {#if service.extLink}
<a <a
class="flex flex-row rounded-md border-x-2 px-2 text-sm hover:border-secondary hover:text-secondary" class="flex flex-row rounded-md border-x-2 px-2 text-sm text-accent hover:border-primary hover:text-primary"
href={service.extLink} href={service.extLink}
on:mouseover={() => (hover.ext = true)} on:mouseover={() => (hover.ext = true)}
on:mouseleave={() => (hover.ext = false)} on:mouseleave={() => (hover.ext = false)}
@ -170,7 +177,7 @@
class="grid items-center pl-1 pr-0" class="grid items-center pl-1 pr-0"
> >
<OpenInNewWindow <OpenInNewWindow
color={hover.ext ? 'hsl(var(--secondary))' : 'hsl(var(--primary)'} color={hover.ext ? 'hsl(var(--primary))' : 'hsl(var(--secondary)'}
class="self-center" class="self-center"
/> />
</div> </div>

View file

@ -1,7 +0,0 @@
import Root from './separator.svelte';
export {
Root,
//
Root as Separator
};

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
export type Service = { export type Service = {
readonly name: string; readonly name: string;
readonly icon?: string; readonly icon: string;
readonly iconType?: IconType; readonly iconType: IconType;
readonly href: string; readonly href: string;
readonly desc: string; readonly desc: string;
readonly warn: string; readonly warn: string;
@ -9,17 +9,6 @@ export type Service = {
readonly id: number; readonly id: number;
}; };
export type Server = {
readonly name: string;
readonly icon?: string;
readonly iconType?: IconType;
readonly connection?: string;
readonly href?: string;
readonly desc?: string;
readonly extLink?: string;
readonly id?: number;
};
export enum IconType { export enum IconType {
SVG = 'svg', SVG = 'svg',
AVIF = 'avif', AVIF = 'avif',

View file

@ -1,29 +1,7 @@
<svelte:options runes={true} />
<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 { beforeNavigate } from '$app/navigation';
import Footer from './Footer.svelte';
$effect(() => {
beforeNavigate((navigation) => {
const servers =
navigation.to.url.pathname === '/servers' || navigation.from.url.pathname === '/servers';
const services =
navigation.to.url.pathname === '/services' || navigation.from.url.pathname === '/services';
if (!(servers && services)) {
$socketStore.close();
}
});
});
</script> </script>
<Header /> <Header />
<div class="h-full pb-8 pt-16">
<slot /> <slot />
</div>
<Footer />

View file

@ -1,65 +1,8 @@
<script lang="ts">
import { Separator } from '$lib/components/ui/separator';
import { OpenInNewWindow } from 'radix-icons-svelte';
import Emfed from '$lib/components/Emfed.svelte';
</script>
<svelte:head> <svelte:head>
<title>Home</title> <title>Home</title>
<meta name="description" content="Landing Page for neshweb.net" /> <meta name="description" content="Landing Page for neshweb.net" />
</svelte:head> </svelte:head>
<div <div class="h-full overflow-auto">
class="flex max-h-full flex-row flex-wrap justify-center justify-around gap-4 overflow-auto p-8" <h1>Home Page</h1>
>
<div class="flex w-[22rem] flex-1 flex-col items-center">
<div class="flex flex-col gap-y-2 rounded-xl border bg-black/55 p-4 backdrop-blur-sm">
<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>
</div>
</div>
<div
class="flex w-[22rem] flex-col items-center gap-y-1 overflow-auto rounded-xl border bg-black/55 py-1 backdrop-blur-sm"
>
<p class="font-bold">Fediverse Accounts</p>
<Separator class="max-w-80" />
<a
rel="me"
href="https://mastodon.neshweb.net/@neshura"
target="_blank"
class="flex flex-row items-center gap-1 hover:text-secondary"
>
Mastodon
<OpenInNewWindow />
</a>
<a
rel="noopener noreferrer"
href="https://bookwormstory.social/u/Neshura"
target="_blank"
class="flex flex-row items-center gap-1 hover:text-secondary"
>
Lemmy
<OpenInNewWindow />
</a>
<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
<OpenInNewWindow />
</a>
<Separator class="max-w-80" />
<p class="font-bold">Mastodon Feed</p>
<Separator class="max-w-80" />
<Emfed
account="https://mastodon.neshweb.net/@neshura"
maxToots={4}
accountId="109199738141333007"
/>
</div>
</div> </div>

View file

@ -1,17 +0,0 @@
<script lang="ts">
import { version } from '$app/environment';
</script>
<div
class="absolute bottom-0 z-50 flex h-8 w-full flex-row items-center gap-3 border-t bg-black/40 backdrop-blur-sm"
>
<p class="px-4">
Version:
<a
href="https://forgejo.neshweb.net/Neshweb-Sites/main-site/releases/tag/{version}"
class="text-secondary hover:underline"
>
{version}
</a>
</p>
</div>

View file

@ -2,17 +2,19 @@
import { page } from '$app/stores'; import { page } from '$app/stores';
import { Button } from '$lib/components/ui/button'; import { Button } from '$lib/components/ui/button';
const button = 'border-t-2 bg-black/55 hover:bg-black/70 hover:border-secondary w-28'; const button = 'border-t-2 bg-black/55 hover:bg-black/70 hover:border-primary w-28';
</script> </script>
<ul <ul
class="absolute z-50 flex h-16 w-full flex-row items-center gap-3 overflow-x-auto border-b bg-black/40 backdrop-blur-sm" class="sticky flex h-16 w-full flex-row items-center justify-center gap-3 border-b bg-black/40 backdrop-blur-sm"
> >
<li class="ml-auto"> <li>
<Button <Button
variant="ghost" variant="ghost"
href="/" href="/"
class="{button} + {!($page.url.pathname === '/') || 'border-secondary text-secondary'}" class="{button} + {$page.url.pathname === '/'
? 'border-primary text-primary'
: 'text-accent'}"
> >
Home Home
</Button> </Button>
@ -21,8 +23,9 @@
<Button <Button
variant="ghost" variant="ghost"
href="/servers" href="/servers"
class="{button} + {!$page.url.pathname.startsWith('/servers') || class="{button} + {$page.url.pathname.startsWith('/servers')
'border-secondary text-secondary'}" ? 'border-primary text-primary'
: 'text-accent'}"
> >
Servers Servers
</Button> </Button>
@ -31,18 +34,20 @@
<Button <Button
variant="ghost" variant="ghost"
href="/services" href="/services"
class="{button} + {!$page.url.pathname.startsWith('/services') || class="{button} + {$page.url.pathname.startsWith('/services')
'border-secondary text-secondary'}" ? 'border-primary text-primary'
: 'text-accent'}"
> >
Services Services
</Button> </Button>
</li> </li>
<li class="mr-auto"> <li>
<Button <Button
variant="ghost" variant="ghost"
href="/about" href="/about"
class="{button} + {!$page.url.pathname.startsWith('/about') || class="{button} + {$page.url.pathname.startsWith('/about')
'border-secondary text-secondary'}" ? 'border-primary text-primary'
: 'text-accent'}"
> >
About About
</Button> </Button>

View file

@ -2,10 +2,3 @@
<title>About</title> <title>About</title>
<meta name="description" content="Information about this Website" /> <meta name="description" content="Information about this Website" />
</svelte:head> </svelte:head>
<div class="flex max-h-full flex-row flex-wrap justify-center gap-10 overflow-auto p-8">
<p>
This is just a small Website I built to organize all of the Services I am self-hosting. Maybe
I'll eventually add something actually useful to the site but until then this is all you'll get.
</p>
</div>

View file

@ -1,29 +0,0 @@
<svelte:head>
<title>CSS Test</title>
<meta name="description" content="CSS playground" />
</svelte:head>
<p class="text-background">Background</p>
<p class="text-foreground">Foreground</p>
<p class="text-muted">Muted</p>
<p class="text-muted-foreground">Muted Foreground</p>
<p class="text-popover">Popover</p>
<p class="text-popover-foreground">Popover Foreground</p>
<p class="text-card">card</p>
<p class="text-card-foreground">card-foreground</p>
<p class="text-border">border</p>
<p class="text-input">input</p>
<p class="text-primary">Primary</p>
<p class="text-primary-foreground">primary-foreground</p>
<p class="text-secondary">secondary</p>
<p class="text-secondary-foreground">secondary-foreground</p>
<p class="text-accent">accent</p>
<p class="text-secondary-foreground">secondary-foreground</p>
<p class="text-accent">accent</p>
<p class="text-accent-foreground">accent-foreground</p>
<p class="text-destructive">destructive</p>
<p class="text-destructive-foreground">destructive-foreground</p>
<p class="text-offline">offline</p>
<p class="text-online">online</p>
<p class="text-pending">pending</p>
<p class="text-maintenance">maintenance</p>

View file

@ -1,10 +0,0 @@
import * as fs from 'fs';
import { json } from '@sveltejs/kit';
export function GET() {
const content = fs.readFileSync('static/data/servers.json').toString();
const data = JSON.parse(content);
return json(data);
}

View file

@ -4,7 +4,7 @@ import { json } from '@sveltejs/kit';
export function GET() { export function GET() {
const content = fs.readFileSync('static/data/services.json').toString(); const content = fs.readFileSync('static/data/services.json').toString();
const data = JSON.parse(content); let data = JSON.parse(content);
return json(data); return json(data);
} }

View file

@ -1,62 +0,0 @@
import { io, Socket } from 'socket.io-client';
import * as fs from 'fs';
export async function load() {
const promise = getJwt();
return {
promise
};
}
async function getJwt(): Promise<string> {
const socket = io('https://status.neshweb.net/');
const credFile = './credentials.json';
let token = '';
let valid = false;
if (fs.existsSync(credFile)) {
const content = fs.readFileSync(credFile);
token = content.toString();
}
socket.on('connect', async () => {
if (token == '') {
token = await login(socket);
valid = true;
} else {
socket.emit('loginByToken', token, async (res) => {
if (!res.ok) {
token = await login(socket);
}
valid = true;
});
}
});
while (!valid) {
await new Promise((resolve) => setTimeout(resolve, 10));
}
fs.writeFileSync(credFile, token);
return token;
}
async function login(socket: Socket): Promise<string> {
let token = '';
socket.emit(
'login',
{ username: process.env.KUMA_USERNAME, password: process.env.KUMA_PASSWORD, token: '' },
(res: { token: string }) => {
token = res.token;
socket.close();
}
);
while (token == '') {
await new Promise((resolve) => setTimeout(resolve, 10));
}
return token;
}

View file

@ -1,97 +1,4 @@
<svelte:options runes={true} />
<script lang="ts">
import type { Server } from '$lib/types/data-types';
import { io } from 'socket.io-client';
import type { Heartbeat } from '$lib/types/uptime-kuma-types';
import ServerCard from '$lib/components/ServerCard.svelte';
import { socketStore } from '$lib/stores/socketStore';
import { uptimeStore } from '$lib/stores/uptimeStore';
let { data }: { data: { promise: Promise<string> } } = $props();
let token = $state();
data.promise.then((jwt) => {
token = jwt;
});
let servers: readonly Server[] = $state.frozen([]);
let icons: readonly string[] = $state.frozen([]);
let monitorList = $state($uptimeStore);
let socket = $socketStore;
$effect(() => {
if (token) {
if (!socket.connected) {
socket.connect();
}
socket.on('connect', () => {
socket.emit('loginByToken', token, () => {});
});
socket.on('heartbeatList', (_, data) => {
let recent = data[data.length - 1];
let monitor: Heartbeat = {
monitorID: recent.monitor_id,
status: recent.status,
time: recent.time,
msg: recent.msg,
ping: recent.ping,
important: recent.important,
duration: recent.duration
};
monitorList.set(monitor.monitorID, monitor);
monitorList = new Map(monitorList.entries());
$uptimeStore = monitorList;
});
socket.on('heartbeat', (data) => {
monitorList.set(data.monitorID, data);
monitorList = new Map(monitorList.entries());
$uptimeStore = monitorList;
});
}
});
async function get(url: string): Promise<any> {
let res = await fetch(url);
if (res.ok) {
let data = await res.json();
return data;
} else {
return Promise.reject();
}
}
$effect(() => {
get('/data/servers').then((data: Server[]) => {
servers = data;
});
});
$effect(() => {
get('/assets/icons').then((data: string[]) => {
icons = data;
});
});
</script>
<svelte:head> <svelte:head>
<title>Servers</title> <title>Servers</title>
<meta name="description" content="Overview of Game Servers running on neshweb.net" /> <meta name="description" content="Overview of Game Servers running on neshweb.net" />
</svelte:head> </svelte:head>
<div class="flex max-h-full flex-row flex-wrap justify-center gap-10 overflow-auto p-8">
{#each servers as server}
{#if typeof server.id === 'undefined'}
<ServerCard {server} {icons} />
{:else}
<ServerCard {server} {icons} monitor={monitorList.get(server.id)} />
{/if}
{/each}
</div>

View file

@ -1,62 +1,41 @@
import { io, Socket } from 'socket.io-client'; import { io } from 'socket.io-client';
import * as fs from 'fs'; import * as fs from 'fs';
export async function load() { export async function load() {
const promise = getJwt();
return {
promise
};
}
async function getJwt(): Promise<string> {
const socket = io('https://status.neshweb.net/');
const credFile = './credentials.json'; const credFile = './credentials.json';
let token = ''; const socket = io('https://status.neshweb.net/');
let valid = false;
let credentials = {
username: '',
password: ''
};
if (fs.existsSync(credFile)) { if (fs.existsSync(credFile)) {
const content = fs.readFileSync(credFile); const buf = fs.readFileSync(credFile);
token = content.toString(); credentials = JSON.parse(buf.toString());
}
socket.on('connect', async () => {
if (token == '') {
token = await login(socket);
valid = true;
} else { } else {
socket.emit('loginByToken', token, async (res) => { console.error('Credentials File does not exist, Socket.io connection will not work.');
if (!res.ok) {
token = await login(socket);
}
valid = true;
});
}
});
while (!valid) {
await new Promise((resolve) => setTimeout(resolve, 10));
} }
fs.writeFileSync(credFile, token); console.log(credentials);
return token;
}
async function login(socket: Socket): Promise<string> {
let token = ''; let token = '';
socket.on('connect', () => {
socket.emit( socket.emit(
'login', 'login',
{ username: process.env.KUMA_USERNAME, password: process.env.KUMA_PASSWORD, token: '' }, { username: credentials.username, password: credentials.password, token: '' },
(res: { token: string }) => { (res) => {
token = res.token; token = res.token;
socket.close(); console.log('Token is:', token);
} }
); );
});
while (token == '') { while (token == '') {
await new Promise((resolve) => setTimeout(resolve, 10)); await new Promise((resolve) => setTimeout(resolve, 10));
} }
return token; return {
token
};
} }

View file

@ -5,37 +5,33 @@
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 { onDestroy } from 'svelte';
import { uptimeStore } from '$lib/stores/uptimeStore';
let { data }: { data: { promise: Promise<string> } } = $props(); let { data }: { data: { token: string } } = $props();
let token = $state(); $effect(() => {
console.log('Data:', data.token);
data.promise.then((jwt) => {
token = jwt;
}); });
let services: readonly Service[] = $state.frozen([]); let services: readonly Service[] = $state.frozen([]);
let icons: readonly string[] = $state.frozen([]); let icons: readonly string[] = $state.frozen([]);
let monitorList = $state($uptimeStore); let monitorList: Map<number, Heartbeat> = $state(new Map());
let socket = $socketStore; //let token = $props();
$effect(() => { $effect(() => {
if (token) { if (data.token) {
if (!socket.connected) { const socket = io('https://status.neshweb.net/');
socket.connect();
}
socket.on('connect', () => { socket.on('connect', () => {
socket.emit('loginByToken', token, () => {}); socket.emit('loginByToken', data.token, (res) => {
console.log(data.token);
console.log(res);
});
}); });
socket.on('heartbeatList', (_, data) => { socket.on('heartbeatList', (idString: string, data) => {
let recent = data[data.length - 1]; let recent = data[data.length - 1];
let monitor: Heartbeat = { let monitor: Heartbeat = {
monitorID: recent.monitor_id, monitorID: recent.monitor_id,
@ -48,13 +44,11 @@
}; };
monitorList.set(monitor.monitorID, monitor); monitorList.set(monitor.monitorID, monitor);
monitorList = new Map(monitorList.entries()); monitorList = new Map(monitorList.entries());
$uptimeStore = monitorList;
}); });
socket.on('heartbeat', (data) => { socket.on('heartbeat', (data) => {
monitorList.set(data.monitorID, data); monitorList.set(data.monitorID, data);
monitorList = new Map(monitorList.entries()); monitorList = new Map(monitorList.entries());
$uptimeStore = monitorList;
}); });
} }
}); });

View file

@ -3,10 +3,8 @@
"name": "Minecraft", "name": "Minecraft",
"icon": "/assets/icons/minecraft-logo", "icon": "/assets/icons/minecraft-logo",
"iconType": "avif", "iconType": "avif",
"connection": "minecraft.neshweb.net",
"href": "https://minecraft.neshweb.net/", "href": "https://minecraft.neshweb.net/",
"desc": "View all currently available Minecraft Servers and their mods", "desc": "View all currently available Minecraft Servers and their mods"
"id": 38
}, },
{ {
"name": "Ready or Not", "name": "Ready or Not",
@ -16,10 +14,18 @@
"desc": "Collection of Floor Plans for the Game 'Ready or Not'" "desc": "Collection of Floor Plans for the Game 'Ready or Not'"
}, },
{ {
"name": "Factorio" "name": "Zomboid",
"icon": "/assets/icons/zomboid-logo",
"iconType": "avif",
"ip": "91.13.248.30",
"status": "Online"
},
{
"name": "Factorio",
"status": "Online"
}, },
{ {
"name": "Space Engineers", "name": "Space Engineers",
"id": 13 "status": "Online"
} }
] ]

View file

@ -13,7 +13,7 @@
"name": "Kavita", "name": "Kavita",
"icon": "/assets/icons/kavita-logo", "icon": "/assets/icons/kavita-logo",
"iconType": "svg", "iconType": "svg",
"href": "https://kavita.neshweb.net/", "href": "https://kavita.neshweb.net",
"desc": "Self-hosted Manga Library", "desc": "Self-hosted Manga Library",
"warn": "Registration via Admin invite", "warn": "Registration via Admin invite",
"id": 5 "id": 5
@ -41,7 +41,7 @@
"name": "PeerTube", "name": "PeerTube",
"icon": "/assets/icons/peertube-logo", "icon": "/assets/icons/peertube-logo",
"iconType": "svg", "iconType": "svg",
"href": "https://neshweb.tv/", "href": "https://tube.neshweb.net/",
"desc": "Self-hosted PeerTube Instance", "desc": "Self-hosted PeerTube Instance",
"warn": "Note: Registration only via Admin", "warn": "Note: Registration only via Admin",
"id": 8 "id": 8
@ -59,7 +59,7 @@
"name": "Vaultwarden", "name": "Vaultwarden",
"icon": "/assets/icons/vaultwarden-logo", "icon": "/assets/icons/vaultwarden-logo",
"iconType": "svg", "iconType": "svg",
"href": "https://vault.neshweb.net/", "href": "https://vault.neshweb.net",
"desc": "Self-hosted Password Manager", "desc": "Self-hosted Password Manager",
"warn": "Note: Invite only", "warn": "Note: Invite only",
"id": 9 "id": 9
@ -68,7 +68,7 @@
"name": "Jellyfin", "name": "Jellyfin",
"icon": "/assets/icons/jellyfin-logo", "icon": "/assets/icons/jellyfin-logo",
"iconType": "svg", "iconType": "svg",
"href": "https://mov.neshweb.tv/", "href": "https://jellyfin.neshweb.net/",
"desc": "Open-Source, Self-Hosted Media Platform", "desc": "Open-Source, Self-Hosted Media Platform",
"warn": "Note: Registration only via Admin", "warn": "Note: Registration only via Admin",
"id": 37 "id": 37
@ -82,6 +82,15 @@
"warn": "Note: Registration only via Admin", "warn": "Note: Registration only via Admin",
"id": 10 "id": 10
}, },
{
"name": "Gitlab",
"icon": "/assets/icons/gitlab-logo",
"iconType": "svg",
"href": "https://gitlab.neshweb.net/",
"desc": "Self-hosted Git Service",
"warn": "Note: Registration only via Admin",
"id": 2
},
{ {
"name": "Forgejo", "name": "Forgejo",
"icon": "/assets/icons/forgejo-logo", "icon": "/assets/icons/forgejo-logo",
@ -126,13 +135,5 @@
"desc": "Docker Compose WebUI", "desc": "Docker Compose WebUI",
"warn": "Note: Admin Only", "warn": "Note: Admin Only",
"id": 35 "id": 35
},
{
"name": "bookwormstory.social",
"icon": "/assets/icons/bookworm-logo",
"iconType": "avif",
"href": "https://bookwormstory.social/",
"desc": "Lemmy Instance hosted for the community around Ascendance of a Bookworm",
"id": 19
} }
] ]

View file

@ -1,10 +1,6 @@
import adapter from '@sveltejs/adapter-auto'; import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
import { readFileSync } from 'node:fs'; import path from "path";
import { fileURLToPath } from 'node:url';
const path = fileURLToPath(new URL('package.json', import.meta.url));
const pkg = JSON.parse(readFileSync(path, 'utf8'));
/** @type {import('@sveltejs/kit').Config} */ /** @type {import('@sveltejs/kit').Config} */
const config = { const config = {
@ -17,9 +13,6 @@ const config = {
// If your environment is not supported or you settled on a specific environment, switch out the adapter. // If your environment is not supported or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters. // See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter(), adapter: adapter(),
version: {
name: pkg.version
}
} }
}; };

View file

@ -4,7 +4,7 @@ import { fontFamily } from "tailwindcss/defaultTheme";
const config = { const config = {
darkMode: ["class"], darkMode: ["class"],
content: ["./src/**/*.{html,js,svelte,ts}"], content: ["./src/**/*.{html,js,svelte,ts}"],
safelist: ["dark", "nordlys"], safelist: ["dark"],
theme: { theme: {
container: { container: {
center: true, center: true,
@ -68,9 +68,6 @@ const config = {
}, },
fontFamily: { fontFamily: {
sans: [...fontFamily.sans] sans: [...fontFamily.sans]
},
aspectRatio: {
'16/9': '16 / 9',
} }
} }
}, },

View file

@ -702,10 +702,10 @@ binary-extensions@^2.0.0:
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
bits-ui@^0.13.2: bits-ui@^0.13.0:
version "0.13.2" version "0.13.0"
resolved "https://registry.yarnpkg.com/bits-ui/-/bits-ui-0.13.2.tgz#caf47bfed774c7f28600b1d41ac69db0509ec347" resolved "https://registry.yarnpkg.com/bits-ui/-/bits-ui-0.13.0.tgz#dff61c8b4a95b1f589105444da74396bdc6702e7"
integrity sha512-hSxj/BDazR49j2QkgsAnWjHsWdG6OvprCF0IagQm4mDf1pwiunXXJMnSciNxocvaZ/HAkKQRf8R6orwDPO/HYg== integrity sha512-XMvGKhJQMvSWqaan0eaIx1uAVcFBpImgO6xf+XTb7UhqdzbH0//6be4DeR1nRUpIU70XoU1B7i3lMPrTWg37ng==
dependencies: dependencies:
"@internationalized/date" "^3.5.1" "@internationalized/date" "^3.5.1"
"@melt-ui/svelte" "0.67.0" "@melt-ui/svelte" "0.67.0"
@ -857,7 +857,7 @@ deep-is@^0.1.3:
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
deepmerge@^4.2.2, deepmerge@^4.3.1: deepmerge@^4.3.1:
version "4.3.1" version "4.3.1"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
@ -901,36 +901,6 @@ doctrine@^3.0.0:
dependencies: dependencies:
esutils "^2.0.2" esutils "^2.0.2"
dom-serializer@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53"
integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==
dependencies:
domelementtype "^2.3.0"
domhandler "^5.0.2"
entities "^4.2.0"
domelementtype@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
domhandler@^5.0.2, domhandler@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31"
integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==
dependencies:
domelementtype "^2.3.0"
domutils@^3.0.1:
version "3.1.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e"
integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==
dependencies:
dom-serializer "^2.0.0"
domelementtype "^2.3.0"
domhandler "^5.0.3"
eastasianwidth@^0.2.0: eastasianwidth@^0.2.0:
version "0.2.0" version "0.2.0"
resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
@ -983,11 +953,6 @@ engine.io@~6.5.2:
engine.io-parser "~5.2.1" engine.io-parser "~5.2.1"
ws "~8.11.0" ws "~8.11.0"
entities@^4.2.0, entities@^4.4.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
es6-promise@^3.1.2: es6-promise@^3.1.2:
version "3.3.1" version "3.3.1"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613"
@ -1355,16 +1320,6 @@ hasown@^2.0.0:
dependencies: dependencies:
function-bind "^1.1.2" function-bind "^1.1.2"
htmlparser2@^8.0.0:
version "8.0.2"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.2.tgz#f002151705b383e62433b5cf466f5b716edaec21"
integrity sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==
dependencies:
domelementtype "^2.3.0"
domhandler "^5.0.3"
domutils "^3.0.1"
entities "^4.4.0"
ignore@^5.2.0, ignore@^5.2.4: ignore@^5.2.0, ignore@^5.2.4:
version "5.3.0" version "5.3.0"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78"
@ -1442,11 +1397,6 @@ is-path-inside@^3.0.3:
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
is-plain-object@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
is-reference@^3.0.1: is-reference@^3.0.1:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-3.0.2.tgz#154747a01f45cd962404ee89d43837af2cba247c" resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-3.0.2.tgz#154747a01f45cd962404ee89d43837af2cba247c"
@ -1746,11 +1696,6 @@ parent-module@^1.0.0:
dependencies: dependencies:
callsites "^3.0.0" callsites "^3.0.0"
parse-srcset@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1"
integrity sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==
path-exists@^4.0.0: path-exists@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
@ -1874,15 +1819,6 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0:
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
postcss@^8.3.11:
version "8.4.33"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.33.tgz#1378e859c9f69bf6f638b990a0212f43e2aaa742"
integrity sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==
dependencies:
nanoid "^3.3.7"
picocolors "^1.0.0"
source-map-js "^1.0.2"
postcss@^8.4.23, postcss@^8.4.29, postcss@^8.4.32, postcss@^8.4.5: postcss@^8.4.23, postcss@^8.4.29, postcss@^8.4.32, postcss@^8.4.5:
version "8.4.32" version "8.4.32"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.32.tgz#1dac6ac51ab19adb21b8b34fd2d93a86440ef6c9" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.32.tgz#1dac6ac51ab19adb21b8b34fd2d93a86440ef6c9"
@ -2023,18 +1959,6 @@ sander@^0.5.0:
mkdirp "^0.5.1" mkdirp "^0.5.1"
rimraf "^2.5.2" rimraf "^2.5.2"
sanitize-html@^2.11.0:
version "2.11.0"
resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.11.0.tgz#9a6434ee8fcaeddc740d8ae7cd5dd71d3981f8f6"
integrity sha512-BG68EDHRaGKqlsNjJ2xUB7gpInPA8gVx/mvjO743hZaeMCZ2DwzW7xvsqZ+KNU4QKwj86HJ3uu2liISf2qBBUA==
dependencies:
deepmerge "^4.2.2"
escape-string-regexp "^4.0.0"
htmlparser2 "^8.0.0"
is-plain-object "^5.0.0"
parse-srcset "^1.0.2"
postcss "^8.3.11"
semver@^7.5.3, semver@^7.5.4: semver@^7.5.3, semver@^7.5.4:
version "7.5.4" version "7.5.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
@ -2243,9 +2167,9 @@ svelte-preprocess@^5.1.0:
strip-indent "^3.0.0" strip-indent "^3.0.0"
svelte@^5.0.0-next.1: svelte@^5.0.0-next.1:
version "5.0.0-next.28" version "5.0.0-next.27"
resolved "https://registry.yarnpkg.com/svelte/-/svelte-5.0.0-next.28.tgz#6ebcf3da041f9ec60ffffa38dfbc6b262813d2ba" resolved "https://registry.yarnpkg.com/svelte/-/svelte-5.0.0-next.27.tgz#e7e48490032d64234780b453271406af87edef52"
integrity sha512-a9Nqq8eczeJMrOlDL24LMI1MKXMZhDhH33tL8lkPilUJyTjk4W97zYC/hKlZOeAFKdSOBZPIeLFH+NHR2iNSRQ== integrity sha512-5I4JrmEWVPu4ALEskqU/xdz6PsJYnRaWiIN/s7BCvtuwHjy2mbclSfC+VzgCxEN0AEJxdsPXsxYkIfwXch3AyQ==
dependencies: dependencies:
"@ampproject/remapping" "^2.2.1" "@ampproject/remapping" "^2.2.1"
"@jridgewell/sourcemap-codec" "^1.4.15" "@jridgewell/sourcemap-codec" "^1.4.15"