Compare commits
103 commits
1.0.0-rc.1
...
main
Author | SHA1 | Date | |
---|---|---|---|
35f16b9d09 | |||
8d84391acc | |||
a897e5bb03 | |||
6ac9e68827 | |||
8392c7885d | |||
b0fc76ccdf | |||
ea8e759f6a | |||
23bd323bf8 | |||
b36c2bc082 | |||
9eb15db026 | |||
528055fca0 | |||
9aa8ca05f4 | |||
a4806e13ea | |||
3734b89970 | |||
7ba92af617 | |||
ff8448a561 | |||
678fbb76bd | |||
4ce3e29f57 | |||
2d74a1eb89 | |||
0f50c43782 | |||
c715471a9a | |||
d6dac5a2b8 | |||
5ffb5f95f7 | |||
3525fdfcd1 | |||
abea3f1be9 | |||
99679cc45b | |||
d150c6cdba | |||
d774bb169b | |||
6670dc4430 | |||
c71684b7d9 | |||
7632941962 | |||
f78e7ce6e1 | |||
7ae357cf2f | |||
3b017673b3 | |||
fbe9f89c0f | |||
d9e0bae305 | |||
85a722e160 | |||
9357cd84d5 | |||
1872b42d5d | |||
e6cbae1bd6 | |||
536e7e6588 | |||
84f45fa16a | |||
9b476c6478 | |||
8e4bf3b409 | |||
98e9a21f92 | |||
3c1938af80 | |||
4523de1217 | |||
2f02f7cabb | |||
a819351b26 | |||
98c015856f | |||
1dee471ea5 | |||
af2762028b | |||
45f39399fe | |||
71b981e036 | |||
ed9eadd31d | |||
f5d8ae4a46 | |||
a5381c5ba2 | |||
73ccdf5cac | |||
b510f2c576 | |||
5bd01c3a22 | |||
829e911674 | |||
8cadf96116 | |||
ab0346b95c | |||
b1a2471841 | |||
b685f5e771 | |||
0a22ba5e08 | |||
0eb25708a0 | |||
225b120ea0 | |||
7f25f40fe6 | |||
ee5d6e947a | |||
08282e07f0 | |||
097d2e9e5e | |||
803aa95feb | |||
c451e92745 | |||
f05b68f820 | |||
159c78f9cc | |||
b2afbe35ec | |||
74ab3328d2 | |||
6ae4141b8c | |||
3d31710c3f | |||
8aa858a49e | |||
eeaeca1006 | |||
d99d508bd6 | |||
d9f6f2d0be | |||
256f432c22 | |||
3d87538aea | |||
090b97a3f6 | |||
bfd9dcaa7d | |||
6c2f29afa6 | |||
0d1f4cd766 | |||
7ec403841b | |||
be892d00c1 | |||
bd0b102d02 | |||
60710322b8 | |||
c7317324ab | |||
e4607afd22 | |||
0292f34504 | |||
3cd2a0f5af | |||
04a1cd1580 | |||
0824de8df1 | |||
d2206cbb72 | |||
64632df708 | |||
622c8539fe |
46 changed files with 1811 additions and 519 deletions
|
@ -2,94 +2,133 @@ name: 'Build and Release Docker Image'
|
||||||
author: 'Neshura'
|
author: 'Neshura'
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- '[0-9]+.[0-9]+.[0-9]+'
|
- '[0-9]+.[0-9]+.[0-9]+'
|
||||||
- '[0-9]+.[0-9]+.[0-9]+-rc.[0-9]+'
|
- '[0-9]+.[0-9]+.[0-9]+-rc.[0-9]+'
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
steps:
|
steps:
|
||||||
-
|
- name: Checking Out Repository Code
|
||||||
name: Checking Out Repository Code
|
uses: https://code.forgejo.org/actions/checkout@v3
|
||||||
uses: https://code.forgejo.org/actions/checkout@v3
|
|
||||||
-
|
|
||||||
name: Get Yarn Cache Directory
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
|
|
||||||
-
|
|
||||||
name: Set Up Yarn Cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
-
|
|
||||||
name: Install Dependencies
|
|
||||||
run: yarn install
|
|
||||||
-
|
|
||||||
name: Run Linter
|
|
||||||
run: yarn lint
|
|
||||||
-
|
|
||||||
name: Check if Version in package.json matches Tag
|
|
||||||
run: |
|
|
||||||
VERSION=$(cat package.json | grep "version" | sed 's/.*://' | tr -d , | 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
|
|
||||||
|
|
||||||
build:
|
- name: Get Yarn Cache Directory
|
||||||
needs: test
|
id: yarn-cache-dir-path
|
||||||
if: success()
|
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
|
||||||
runs-on: dind
|
|
||||||
steps:
|
- name: Set Up Yarn Cache
|
||||||
-
|
uses: actions/cache@v3
|
||||||
name: Set up Docker Buildx
|
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||||
uses: docker/setup-buildx-action@v3
|
with:
|
||||||
with:
|
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||||
config-inline: |
|
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||||
[registry."docker.io"]
|
restore-keys: |
|
||||||
mirrors = ["https://docker-cache.neshweb.net"]
|
${{ runner.os }}-yarn-
|
||||||
-
|
|
||||||
name: Login to Docker Hub
|
- name: Install Dependencies
|
||||||
uses: docker/login-action@v3
|
run: yarn install
|
||||||
with:
|
|
||||||
registry: forgejo.neshweb.net
|
- name: Install Chromium for Unlighthouse
|
||||||
username: ${{ secrets.FORGEJO_USERNAME }}
|
run: |
|
||||||
password: ${{ secrets.FORGEJO_TOKEN }}
|
echo "apt update && apt install -y chromium"
|
||||||
-
|
apt update && apt install -y chromium
|
||||||
name: Determine Docker tags
|
echo 'export CHROMIUM_FLAGS="$CHROMIUM_FLAGS --no-sandbox" >> /etc/chromium.d/default-flags'
|
||||||
id: tags
|
echo 'export CHROMIUM_FLAGS="$CHROMIUM_FLAGS --no-sandbox"' >> /etc/chromium.d/default-flags
|
||||||
run: |
|
|
||||||
if echo ${{ github.ref_name }} | grep -qi '\-rc' ; then
|
- name: Add Unlighthouse
|
||||||
echo latest=forgejo.neshweb.net/neshweb-sites/${{ github.event.repository.name }}:preview >> $GITHUB_OUTPUT;
|
run: |
|
||||||
else
|
echo "yarn global add @unlighthouse/cli"
|
||||||
echo latest=forgejo.neshweb.net/neshweb-sites/${{ github.event.repository.name }}:latest >> $GITHUB_OUTPUT;
|
yarn global add @unlighthouse/cli
|
||||||
fi
|
|
||||||
echo version=forgejo.neshweb.net/neshweb-sites/${{ github.event.repository.name }}:${{ github.ref_name }} >> $GITHUB_OUTPUT;
|
- name: Run Linter
|
||||||
-
|
run: yarn lint
|
||||||
name: Push to Package Registry
|
|
||||||
uses: docker/build-push-action@v5
|
- name: Check if Version in package.json matches Tag
|
||||||
with:
|
run: |
|
||||||
push: true
|
VERSION=$(cat package.json | grep "version" | sed 's/.*://' | tr -d , | tr -d \" | tr -d " " )
|
||||||
tags: ${{ steps.tags.outputs.version }}, ${{ steps.tags.outputs.latest }}
|
if test $VERSION != "${{ github.ref_name }}"; then
|
||||||
|
echo "Expected Version is: '${{ github.ref_name }}' actual Version is: '$VERSION'";
|
||||||
release:
|
exit 1
|
||||||
needs: build
|
else
|
||||||
if: success()
|
echo "Version is: '$VERSION'";
|
||||||
runs-on: docker
|
fi
|
||||||
steps:
|
|
||||||
-
|
- name: Build Site
|
||||||
name: Release New Version
|
run: yarn build
|
||||||
uses: actions/forgejo-release@v1
|
|
||||||
with:
|
- name: Start Server
|
||||||
direction: upload
|
run: |
|
||||||
url: https://forgejo.neshweb.net
|
export KUMA_USERNAME=${{ secrets.KUMA_USERNAME }}
|
||||||
release-dir: release
|
export KUMA_PASSWORD=${{ secrets.KUMA_PASSWORD }}
|
||||||
token: ${{ secrets.FORGEJO_TOKEN }}
|
yarn preview &
|
||||||
tag: ${{ github.ref_name }}
|
|
||||||
|
- name: Run Unlighthouse for Desktop
|
||||||
|
run: unlighthouse-ci --build-static --desktop --outputPath reports/desktop
|
||||||
|
|
||||||
|
- name: Refresh Server
|
||||||
|
run: |
|
||||||
|
if ! pgrep -f "node /usr/bin/yarn" ; then
|
||||||
|
export KUMA_USERNAME=${{ secrets.KUMA_USERNAME }}
|
||||||
|
export KUMA_PASSWORD=${{ secrets.KUMA_PASSWORD }}
|
||||||
|
yarn preview &
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Run Unlighthouse for Mobile
|
||||||
|
run: unlighthouse-ci --build-static --mobile --outputPath reports/mobile
|
||||||
|
|
||||||
|
- name: Uploading Lighthouse Reports
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: lighthouse
|
||||||
|
path: reports
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
build:
|
||||||
|
needs: test
|
||||||
|
if: success()
|
||||||
|
runs-on: dind
|
||||||
|
steps:
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
with:
|
||||||
|
config-inline: |
|
||||||
|
[registry."docker.io"]
|
||||||
|
mirrors = ["https://docker-cache.neshweb.net"]
|
||||||
|
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: forgejo.neshweb.net
|
||||||
|
username: ${{ secrets.FORGEJO_USERNAME }}
|
||||||
|
password: ${{ secrets.FORGEJO_TOKEN }}
|
||||||
|
|
||||||
|
- name: Determine Docker tags
|
||||||
|
id: tags
|
||||||
|
run: |
|
||||||
|
if echo ${{ github.ref_name }} | grep -qi '\-rc' ; then
|
||||||
|
echo latest=forgejo.neshweb.net/neshweb-sites/${{ github.event.repository.name }}:preview >> $GITHUB_OUTPUT;
|
||||||
|
else
|
||||||
|
echo latest=forgejo.neshweb.net/neshweb-sites/${{ github.event.repository.name }}:latest >> $GITHUB_OUTPUT;
|
||||||
|
fi
|
||||||
|
echo version=forgejo.neshweb.net/neshweb-sites/${{ github.event.repository.name }}:${{ github.ref_name }} >> $GITHUB_OUTPUT;
|
||||||
|
|
||||||
|
- name: Push to Package Registry
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.tags.outputs.version }}, ${{ steps.tags.outputs.latest }}
|
||||||
|
|
||||||
|
release:
|
||||||
|
needs: build
|
||||||
|
if: success()
|
||||||
|
runs-on: docker
|
||||||
|
steps:
|
||||||
|
- name: Release New Version
|
||||||
|
uses: actions/forgejo-release@v2
|
||||||
|
with:
|
||||||
|
direction: upload
|
||||||
|
url: https://forgejo.neshweb.net
|
||||||
|
release-dir: release
|
||||||
|
token: ${{ secrets.FORGEJO_TOKEN }}
|
||||||
|
tag: ${{ github.ref_name }}
|
|
@ -3,47 +3,73 @@ author: 'Neshura'
|
||||||
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
steps:
|
steps:
|
||||||
-
|
- name: Checking Out Repository Code
|
||||||
name: Checking Out Repository Code
|
uses: https://code.forgejo.org/actions/checkout@v3
|
||||||
uses: https://code.forgejo.org/actions/checkout@v3
|
|
||||||
-
|
|
||||||
name: Get Yarn Cache Directory
|
|
||||||
id: yarn-cache-dir-path
|
|
||||||
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
|
|
||||||
-
|
|
||||||
name: Set Up Yarn Cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
|
||||||
with:
|
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-yarn-
|
|
||||||
-
|
|
||||||
name: Install Dependencies
|
|
||||||
run: yarn install
|
|
||||||
-
|
|
||||||
name: Run Linter
|
|
||||||
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 website
|
|
||||||
run: yarn build
|
|
||||||
|
|
||||||
|
- name: Get Yarn Cache Directory
|
||||||
|
id: yarn-cache-dir-path
|
||||||
|
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Set Up Yarn Cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||||
|
with:
|
||||||
|
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||||
|
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-yarn-
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: yarn install
|
||||||
|
|
||||||
|
- name: Install Chromium for Unlighthouse
|
||||||
|
run: |
|
||||||
|
echo "apt update && apt install -y chromium"
|
||||||
|
apt update && apt install -y chromium
|
||||||
|
echo 'export CHROMIUM_FLAGS="$CHROMIUM_FLAGS --no-sandbox" >> /etc/chromium.d/default-flags'
|
||||||
|
echo 'export CHROMIUM_FLAGS="$CHROMIUM_FLAGS --no-sandbox"' >> /etc/chromium.d/default-flags
|
||||||
|
|
||||||
|
- name: Add Unlighthouse
|
||||||
|
run: |
|
||||||
|
echo "yarn global add @unlighthouse/cli"
|
||||||
|
yarn global add @unlighthouse/cli
|
||||||
|
|
||||||
|
- name: Run Linter
|
||||||
|
run: yarn lint
|
||||||
|
|
||||||
|
- name: Build Site
|
||||||
|
run: yarn build
|
||||||
|
|
||||||
|
- name: Start Server
|
||||||
|
run: |
|
||||||
|
export KUMA_USERNAME=${{ secrets.KUMA_USERNAME }}
|
||||||
|
export KUMA_PASSWORD=${{ secrets.KUMA_PASSWORD }}
|
||||||
|
yarn preview &
|
||||||
|
|
||||||
|
- name: Run Unlighthouse for Desktop
|
||||||
|
run: unlighthouse-ci --build-static --desktop --outputPath reports/desktop
|
||||||
|
|
||||||
|
- name: Refresh Server
|
||||||
|
run: |
|
||||||
|
if ! pgrep -f "node /usr/bin/yarn" ; then
|
||||||
|
export KUMA_USERNAME=${{ secrets.KUMA_USERNAME }}
|
||||||
|
export KUMA_PASSWORD=${{ secrets.KUMA_PASSWORD }}
|
||||||
|
yarn preview &
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Run Unlighthouse for Mobile
|
||||||
|
run: unlighthouse-ci --build-static --mobile --outputPath reports/mobile
|
||||||
|
|
||||||
|
- name: Uploading Lighthouse Reports
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: lighthouse
|
||||||
|
path: reports
|
||||||
|
if-no-files-found: error
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -3,6 +3,9 @@ node_modules
|
||||||
/build
|
/build
|
||||||
/.svelte-kit
|
/.svelte-kit
|
||||||
/package
|
/package
|
||||||
|
/.idea
|
||||||
|
credentials.json
|
||||||
|
.unlighthouse
|
||||||
.env
|
.env
|
||||||
.env.*
|
.env.*
|
||||||
!.env.example
|
!.env.example
|
||||||
|
|
|
@ -14,6 +14,8 @@ 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"]
|
|
@ -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-rc.1",
|
"version": "1.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite dev",
|
"dev": "vite dev",
|
||||||
|
@ -20,6 +20,7 @@
|
||||||
"@sveltejs/kit": "^2.0.0",
|
"@sveltejs/kit": "^2.0.0",
|
||||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||||
"@types/eslint": "8.56.0",
|
"@types/eslint": "8.56.0",
|
||||||
|
"@types/socket.io": "^3.0.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||||
"@typescript-eslint/parser": "^6.0.0",
|
"@typescript-eslint/parser": "^6.0.0",
|
||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.16",
|
||||||
|
@ -40,9 +41,12 @@
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bits-ui": "^0.13.0",
|
"bits-ui": "^0.13.2",
|
||||||
"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-client": "^4.7.2",
|
||||||
"tailwind-merge": "^2.2.0",
|
"tailwind-merge": "^2.2.0",
|
||||||
"tailwind-variants": "^0.1.19"
|
"tailwind-variants": "^0.1.19"
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,9 +69,9 @@
|
||||||
|
|
||||||
.nordlys {
|
.nordlys {
|
||||||
--background: 0 0% 0%; /* #000000 */
|
--background: 0 0% 0%; /* #000000 */
|
||||||
--foreground: 173 80% 40%; /* #14b8a6 */
|
--foreground: 183 100% 96%; /* #14b8a6 */
|
||||||
|
|
||||||
--muted: 183 100% 96%; /* #ecfeff */
|
--muted: 180 10% 66%; /* #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: 173 80% 40%; /* #14b8a6 */
|
--primary: 183 100% 96%; /* #14b8a6 */
|
||||||
--primary-foreground: 221 39% 11%; /* #111827 */
|
--primary-foreground: 221 39% 11%; /* #111827 */
|
||||||
|
|
||||||
--secondary: 183 100% 96%; /* #ecfeff */
|
--secondary: 173 80% 40%; /* #ecfeff */
|
||||||
--secondary-foreground: 173 80% 40%; /* #14b8a6 */
|
--secondary-foreground: 173 80% 40%; /* #14b8a6 */
|
||||||
|
|
||||||
--accent: 183 100% 96%; /* #ecfeff */
|
--accent: 183 100% 96%; /* #ecfeff */
|
||||||
|
|
|
@ -1,101 +0,0 @@
|
||||||
<svelte:options runes={true} />
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { OpenInNewWindow } from 'radix-icons-svelte';
|
|
||||||
import { quintInOut } from 'svelte/easing';
|
|
||||||
import { slide } from 'svelte/transition';
|
|
||||||
import type { Service } from '$lib/types/data-types';
|
|
||||||
|
|
||||||
let { service }: { service: Service } = $props();
|
|
||||||
|
|
||||||
let hover = $state({
|
|
||||||
title: false,
|
|
||||||
link: false,
|
|
||||||
ext: false
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="flex h-48 w-[30rem] flex-col gap-y-2 rounded-xl border-t-4 border-maintenance bg-black/55 p-4"
|
|
||||||
>
|
|
||||||
<div class="flex flex-row justify-between pb-4">
|
|
||||||
<div
|
|
||||||
class="flex flex-row items-center gap-1"
|
|
||||||
on:mouseover={() => (hover.title = true)}
|
|
||||||
on:mouseleave={() => (hover.title = false)}
|
|
||||||
>
|
|
||||||
{#if service.icon}
|
|
||||||
<img
|
|
||||||
width="24px"
|
|
||||||
class="h-6 w-6 cursor-pointer"
|
|
||||||
src={service.icon}
|
|
||||||
alt="{service.name} Logo"
|
|
||||||
/>
|
|
||||||
{:else}{/if}
|
|
||||||
<a
|
|
||||||
href={service.href}
|
|
||||||
class="font-bold text-accent {hover.title ? 'text-primary' : 'text-secondary'}"
|
|
||||||
>{service.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(--primary))' : 'hsl(var(--secondary)'}
|
|
||||||
class="self-center"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="w-16 rounded-md border-b-2 border-maintenance text-center text-sm text-maintenance">
|
|
||||||
Loading
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
<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>
|
|
||||||
<div class="grid {service.extLink ? 'grid-cols-2' : 'grid-cols-1'} mt-auto justify-items-center">
|
|
||||||
<a
|
|
||||||
class="flex flex-row rounded-md border-x-2 px-2 text-sm text-accent hover:border-primary hover:text-primary"
|
|
||||||
href={service.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(--primary))' : 'hsl(var(--secondary)'}
|
|
||||||
class="self-center"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</a>
|
|
||||||
{#if service.extLink}
|
|
||||||
<a
|
|
||||||
class="flex flex-row rounded-md border-x-2 px-2 text-sm text-accent hover:border-primary hover:text-primary"
|
|
||||||
href={service.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(--primary))' : 'hsl(var(--secondary)'}
|
|
||||||
class="self-center"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</a>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
193
src/lib/components/Emfed.svelte
Normal file
193
src/lib/components/Emfed.svelte
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
<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>
|
212
src/lib/components/ServerCard.svelte
Normal file
212
src/lib/components/ServerCard.svelte
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
<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>
|
181
src/lib/components/ServiceCard.svelte
Normal file
181
src/lib/components/ServiceCard.svelte
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
<svelte:options runes={true} />
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { OpenInNewWindow } from 'radix-icons-svelte';
|
||||||
|
import { quintInOut } from 'svelte/easing';
|
||||||
|
import { slide } from 'svelte/transition';
|
||||||
|
import { IconType, type Service } from '$lib/types/data-types';
|
||||||
|
import { Skeleton } from '$lib/components/ui/skeleton';
|
||||||
|
import type { Heartbeat } from '$lib/types/uptime-kuma-types';
|
||||||
|
|
||||||
|
let { service, icons, monitor } = $props<{
|
||||||
|
service: Service;
|
||||||
|
icons: Array<string>;
|
||||||
|
monitor: Heartbeat;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
let status = $state(4);
|
||||||
|
|
||||||
|
let hover = $state({
|
||||||
|
title: false,
|
||||||
|
link: false,
|
||||||
|
ext: false
|
||||||
|
});
|
||||||
|
|
||||||
|
let img_source: string = $state('');
|
||||||
|
|
||||||
|
function checkForImage(service: Service) {
|
||||||
|
const rootSplit = service.icon.split('/');
|
||||||
|
const root = rootSplit[rootSplit.length - 1];
|
||||||
|
|
||||||
|
if (icons.includes(`${root}.${service.iconType}`)) {
|
||||||
|
img_source = `${service.icon}.${service.iconType}`;
|
||||||
|
} else {
|
||||||
|
img_source = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
if (typeof monitor !== 'undefined') {
|
||||||
|
status = monitor.status;
|
||||||
|
}
|
||||||
|
if (icons.length != 0) {
|
||||||
|
const rootSplit = service.icon.split('/');
|
||||||
|
const root = rootSplit[rootSplit.length - 1];
|
||||||
|
|
||||||
|
if (service.iconType === IconType.SVG) {
|
||||||
|
checkForImage(service);
|
||||||
|
} else {
|
||||||
|
if (icons.includes(`${root}-36.${service.iconType}`)) {
|
||||||
|
img_source = `${service.icon}-36.${service.iconType}`;
|
||||||
|
} else {
|
||||||
|
checkForImage(service);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="flex h-48 w-[28rem] flex-col gap-y-3 rounded-xl border-t-4
|
||||||
|
{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 service.icon}
|
||||||
|
{#if img_source != ''}
|
||||||
|
<img
|
||||||
|
width="24px"
|
||||||
|
class="h-6 w-6 cursor-pointer"
|
||||||
|
src={img_source}
|
||||||
|
alt="{service.name} Logo"
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<Skeleton class="h-6 w-6 rounded-full" />
|
||||||
|
{/if}
|
||||||
|
{:else}{/if}
|
||||||
|
<a href={service.href} class="font-bold {!hover.title || 'text-secondary'}">{service.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}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
<p class="text-wrap text-center text-sm">{service.desc}</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">
|
||||||
|
<a
|
||||||
|
class="flex flex-row rounded-md border-x-2 px-2 text-sm hover:border-secondary hover:text-secondary"
|
||||||
|
href={service.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 service.extLink}
|
||||||
|
<a
|
||||||
|
class="flex flex-row rounded-md border-x-2 px-2 text-sm hover:border-secondary hover:text-secondary"
|
||||||
|
href={service.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>
|
|
@ -1,155 +0,0 @@
|
||||||
{
|
|
||||||
"services": [
|
|
||||||
{
|
|
||||||
"name": "Nextcloud",
|
|
||||||
"icon": "/assets/icons/nextcloud-logo.svg",
|
|
||||||
"href": "https://nextcloud.neshweb.net/",
|
|
||||||
"desc": "Self-hosted Cloud Storage Service",
|
|
||||||
"warn": "Note: Registration requires approval",
|
|
||||||
"extLink": "https://nextcloud.com/",
|
|
||||||
"id": 7
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Kavita",
|
|
||||||
"icon": "/assets/icons/kavita-logo.svg",
|
|
||||||
"href": "https://kavita.neshweb.net",
|
|
||||||
"desc": "Self-hosted Manga Library",
|
|
||||||
"warn": "Registration via Admin invite",
|
|
||||||
"id": 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Images",
|
|
||||||
"icon": "/assets/icons/images-logo.svg",
|
|
||||||
"href": "https://imgs.neshweb.net/",
|
|
||||||
"desc": "Self-hosted Chevereto Image Service",
|
|
||||||
"warn": "",
|
|
||||||
"extLink": "https://chevereto.com/",
|
|
||||||
"id": 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Calibre Web",
|
|
||||||
"icon": "/assets/icons/calibre-logo.avif",
|
|
||||||
"href": "https://calibre.neshweb.net/",
|
|
||||||
"desc": "Self-hosted Ebook Library Service",
|
|
||||||
"warn": "Note: Registration only via Admin",
|
|
||||||
"id": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "PeerTube",
|
|
||||||
"icon": "/assets/icons/peertube-logo.svg",
|
|
||||||
"href": "https://tube.neshweb.net/",
|
|
||||||
"desc": "Self-hosted PeerTube Instance",
|
|
||||||
"warn": "Note: Registration only via Admin",
|
|
||||||
"id": 8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Mastodon",
|
|
||||||
"icon": "/assets/icons/mastodon-logo.svg",
|
|
||||||
"href": "https://mastodon.neshweb.net/",
|
|
||||||
"desc": "Self-hosted Mastodon Instance",
|
|
||||||
"warn": "Note: Registration requires approval",
|
|
||||||
"id": 3
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"name": "Vaultwarden",
|
|
||||||
"icon": "/assets/icons/vaultwarden-logo.svg",
|
|
||||||
"href": "https://vault.neshweb.net",
|
|
||||||
"desc": "Self-hosted Password Manager",
|
|
||||||
"warn": "Note: Invite only",
|
|
||||||
"id": 9
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Jellyfin",
|
|
||||||
"icon": "/assets/icons/jellyfin-logo.svg",
|
|
||||||
"href": "https://jellyfin.neshweb.net/",
|
|
||||||
"desc": "Open-Source, Self-Hosted Media Platform",
|
|
||||||
"warn": "Note: Registration only via Admin",
|
|
||||||
"id": 37
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Navidrome",
|
|
||||||
"icon": "/assets/icons/navidrome-logo.avif",
|
|
||||||
"href": "https://navidrome.neshweb.net/",
|
|
||||||
"desc": "Open-Source, Self-Hosted Music Streaming Platform",
|
|
||||||
"warn": "Note: Registration only via Admin",
|
|
||||||
"id": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Gitlab",
|
|
||||||
"icon": "/assets/icons/gitlab-logo.svg",
|
|
||||||
"href": "https://gitlab.neshweb.net/",
|
|
||||||
"desc": "Self-hosted Git Service",
|
|
||||||
"warn": "Note: Registration only via Admin",
|
|
||||||
"id": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Forgejo",
|
|
||||||
"icon": "/assets/icons/forgejo-logo.svg",
|
|
||||||
"href": "https://forgejo.neshweb.net/",
|
|
||||||
"desc": "Self-hosted Git Service",
|
|
||||||
"warn": "Note: Registration only via Admin",
|
|
||||||
"id": 36
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Portainer",
|
|
||||||
"icon": "/assets/icons/portainer-logo.avif",
|
|
||||||
"href": "https://portainer.neshweb.net/",
|
|
||||||
"desc": "Docker Container Manager",
|
|
||||||
"warn": "Note: Admin Only",
|
|
||||||
"id": 34
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Nginx",
|
|
||||||
"icon": "/assets/icons/npm-logo.avif",
|
|
||||||
"href": "https://nginx.neshweb.net/",
|
|
||||||
"desc": "Web-based Nginx Proxy Manager",
|
|
||||||
"warn": "Note: Admin Only",
|
|
||||||
"id": 31
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Proxmox",
|
|
||||||
"icon": "/assets/icons/proxmox-logo.avif",
|
|
||||||
"href": "https://proxmox.neshweb.net/",
|
|
||||||
"desc": "Hypervisor Webinterface",
|
|
||||||
"warn": "Note: Admin Only",
|
|
||||||
"id": 33
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Dockge",
|
|
||||||
"icon": "/assets/icons/dockge-logo.avif",
|
|
||||||
"href": "https://dockge.neshweb.net/",
|
|
||||||
"desc": "Docker Compose WebUI",
|
|
||||||
"warn": "Note: Admin Only",
|
|
||||||
"id": 35
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"games": {
|
|
||||||
"minecraft": {
|
|
||||||
"name": "Minecraft",
|
|
||||||
"icon": "/assets/icons/minecraft-logo.avif",
|
|
||||||
"href": "https://minecraft.neshweb.net/",
|
|
||||||
"desc": "View all currently available Minecraft Servers and their mods"
|
|
||||||
},
|
|
||||||
"ready_or_not": {
|
|
||||||
"name": "Ready or Not",
|
|
||||||
"icon": "/assets/icons/ron-logo.avif",
|
|
||||||
"href": "https://readyornot.neshweb.net/",
|
|
||||||
"desc": "Collection of Floor Plans for the Game 'Ready or Not'"
|
|
||||||
},
|
|
||||||
"zomboid": {
|
|
||||||
"name": "Zomboid",
|
|
||||||
"icon": "/assets/icons/zomboid-logo.avif",
|
|
||||||
"ip": "91.13.248.30",
|
|
||||||
"status": "Online"
|
|
||||||
},
|
|
||||||
"factorio": {
|
|
||||||
"name": "Factorio",
|
|
||||||
"status": "Online"
|
|
||||||
},
|
|
||||||
"space_engineers": {
|
|
||||||
"name": "Space Engineers",
|
|
||||||
"status": "Online"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
7
src/lib/components/ui/separator/index.ts
Normal file
7
src/lib/components/ui/separator/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import Root from './separator.svelte';
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
//
|
||||||
|
Root as Separator
|
||||||
|
};
|
22
src/lib/components/ui/separator/separator.svelte
Normal file
22
src/lib/components/ui/separator/separator.svelte
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<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}
|
||||||
|
/>
|
7
src/lib/components/ui/skeleton/index.ts
Normal file
7
src/lib/components/ui/skeleton/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import Root from './skeleton.svelte';
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
//
|
||||||
|
Root as Skeleton
|
||||||
|
};
|
11
src/lib/components/ui/skeleton/skeleton.svelte
Normal file
11
src/lib/components/ui/skeleton/skeleton.svelte
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from '$lib/utils';
|
||||||
|
import type { HTMLAttributes } from 'svelte/elements';
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLDivElement>;
|
||||||
|
|
||||||
|
let className: $$Props['class'] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class={cn('animate-pulse rounded-md bg-primary/10', className)} {...$$restProps} />
|
4
src/lib/stores/socketStore.ts
Normal file
4
src/lib/stores/socketStore.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
import { io } from 'socket.io-client';
|
||||||
|
|
||||||
|
export let socketStore = writable(io('https://status.neshweb.net/'));
|
4
src/lib/stores/uptimeStore.ts
Normal file
4
src/lib/stores/uptimeStore.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
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());
|
|
@ -1,9 +1,29 @@
|
||||||
export type Service = {
|
export type Service = {
|
||||||
name: string;
|
readonly name: string;
|
||||||
icon: string;
|
readonly icon?: string;
|
||||||
href: string;
|
readonly iconType?: IconType;
|
||||||
desc: string;
|
readonly href: string;
|
||||||
warn: string;
|
readonly desc: string;
|
||||||
extLink?: string;
|
readonly warn: string;
|
||||||
id: number;
|
readonly extLink?: string;
|
||||||
|
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 {
|
||||||
|
SVG = 'svg',
|
||||||
|
AVIF = 'avif',
|
||||||
|
PNG = 'png',
|
||||||
|
WEBP = 'webp',
|
||||||
|
JPG = 'jpg'
|
||||||
|
}
|
||||||
|
|
9
src/lib/types/uptime-kuma-types.ts
Normal file
9
src/lib/types/uptime-kuma-types.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
export type Heartbeat = {
|
||||||
|
readonly monitorID: number;
|
||||||
|
readonly status: number;
|
||||||
|
readonly time: string;
|
||||||
|
readonly msg: string;
|
||||||
|
readonly ping: number;
|
||||||
|
readonly important: boolean;
|
||||||
|
readonly duration: number;
|
||||||
|
};
|
|
@ -1,7 +1,29 @@
|
||||||
|
<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 />
|
||||||
<slot />
|
|
||||||
|
<div class="h-full pb-8 pt-16">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Footer />
|
||||||
|
|
|
@ -1,86 +1,65 @@
|
||||||
<div class="h-full overflow-auto">
|
<script lang="ts">
|
||||||
<h1>Welcome to SvelteKit</h1>
|
import { Separator } from '$lib/components/ui/separator';
|
||||||
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p>
|
import { OpenInNewWindow } from 'radix-icons-svelte';
|
||||||
<p>gap</p>
|
import Emfed from '$lib/components/Emfed.svelte';
|
||||||
<p>gap</p>
|
</script>
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
<svelte:head>
|
||||||
<p>gap</p>
|
<title>Home</title>
|
||||||
<p>gap</p>
|
<meta name="description" content="Landing Page for neshweb.net" />
|
||||||
<p>gap</p>
|
</svelte:head>
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
<div
|
||||||
<p>gap</p>
|
class="flex max-h-full flex-row flex-wrap justify-center justify-around gap-4 overflow-auto p-8"
|
||||||
<p>gap</p>
|
>
|
||||||
<p>gap</p>
|
<div class="flex w-[22rem] flex-1 flex-col items-center">
|
||||||
<p>gap</p>
|
<div class="flex flex-col gap-y-2 rounded-xl border bg-black/55 p-4 backdrop-blur-sm">
|
||||||
<p>gap</p>
|
<h1 class="text-center text-2xl">Home Page</h1>
|
||||||
<p>gap</p>
|
<p>
|
||||||
<p>gap</p>
|
I'm not sure what to put here quite yet, maybe I'll think of something eventually. In the
|
||||||
<p>gap</p>
|
meantime I've linked some of my accounts in the sidebar to the right
|
||||||
<p>gap</p>
|
</p>
|
||||||
<p>gap</p>
|
</div>
|
||||||
<p>gap</p>
|
</div>
|
||||||
<p>gap</p>
|
<div
|
||||||
<p>gap</p>
|
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>gap</p>
|
>
|
||||||
<p>gap</p>
|
<p class="font-bold">Fediverse Accounts</p>
|
||||||
<p>gap</p>
|
<Separator class="max-w-80" />
|
||||||
<p>gap</p>
|
<a
|
||||||
<p>gap</p>
|
rel="me"
|
||||||
<p>gap</p>
|
href="https://mastodon.neshweb.net/@neshura"
|
||||||
<p>gap</p>
|
target="_blank"
|
||||||
<p>gap</p>
|
class="flex flex-row items-center gap-1 hover:text-secondary"
|
||||||
<p>gap</p>
|
>
|
||||||
<p>gap</p>
|
Mastodon
|
||||||
<p>gap</p>
|
<OpenInNewWindow />
|
||||||
<p>gap</p>
|
</a>
|
||||||
<p>gap</p>
|
<a
|
||||||
<p>gap</p>
|
rel="noopener noreferrer"
|
||||||
<p>gap</p>
|
href="https://bookwormstory.social/u/Neshura"
|
||||||
<p>gap</p>
|
target="_blank"
|
||||||
<p>gap</p>
|
class="flex flex-row items-center gap-1 hover:text-secondary"
|
||||||
<p>gap</p>
|
>
|
||||||
<p>gap</p>
|
Lemmy
|
||||||
<p>gap</p>
|
<OpenInNewWindow />
|
||||||
<p>gap</p>
|
</a>
|
||||||
<p>gap</p>
|
<a
|
||||||
<p>gap</p>
|
rel="noopener noreferrer"
|
||||||
<p>gap</p>
|
href="https://neshweb.tv/c/neshura_ch/videos"
|
||||||
<p>gap</p>
|
target="_blank"
|
||||||
<p>gap</p>
|
class="flex flex-row items-center gap-1 hover:text-secondary"
|
||||||
<p>gap</p>
|
>
|
||||||
<p>gap</p>
|
PeerTube
|
||||||
<p>gap</p>
|
<OpenInNewWindow />
|
||||||
<p>gap</p>
|
</a>
|
||||||
<p>gap</p>
|
<Separator class="max-w-80" />
|
||||||
<p>gap</p>
|
<p class="font-bold">Mastodon Feed</p>
|
||||||
<p>gap</p>
|
<Separator class="max-w-80" />
|
||||||
<p>gap</p>
|
<Emfed
|
||||||
<p>gap</p>
|
account="https://mastodon.neshweb.net/@neshura"
|
||||||
<p>gap</p>
|
maxToots={4}
|
||||||
<p>gap</p>
|
accountId="109199738141333007"
|
||||||
<p>gap</p>
|
/>
|
||||||
<p>gap</p>
|
</div>
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
<p>gap</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
17
src/routes/Footer.svelte
Normal file
17
src/routes/Footer.svelte
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<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>
|
|
@ -2,19 +2,17 @@
|
||||||
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-primary w-28';
|
const button = 'border-t-2 bg-black/55 hover:bg-black/70 hover:border-secondary w-28';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ul
|
<ul
|
||||||
class="sticky flex h-16 w-full flex-row items-center justify-center gap-3 border-b bg-black/40 backdrop-blur-sm"
|
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"
|
||||||
>
|
>
|
||||||
<li>
|
<li class="ml-auto">
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
href="/"
|
href="/"
|
||||||
class="{button} + {$page.url.pathname === '/'
|
class="{button} + {!($page.url.pathname === '/') || 'border-secondary text-secondary'}"
|
||||||
? 'border-primary text-primary'
|
|
||||||
: 'text-accent'}"
|
|
||||||
>
|
>
|
||||||
Home
|
Home
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -23,9 +21,8 @@
|
||||||
<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-primary text-primary'
|
'border-secondary text-secondary'}"
|
||||||
: 'text-accent'}"
|
|
||||||
>
|
>
|
||||||
Servers
|
Servers
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -34,20 +31,18 @@
|
||||||
<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-primary text-primary'
|
'border-secondary text-secondary'}"
|
||||||
: 'text-accent'}"
|
|
||||||
>
|
>
|
||||||
Services
|
Services
|
||||||
</Button>
|
</Button>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li class="mr-auto">
|
||||||
<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-primary text-primary'
|
'border-secondary text-secondary'}"
|
||||||
: 'text-accent'}"
|
|
||||||
>
|
>
|
||||||
About
|
About
|
||||||
</Button>
|
</Button>
|
||||||
|
|
11
src/routes/about/+page.svelte
Normal file
11
src/routes/about/+page.svelte
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<svelte:head>
|
||||||
|
<title>About</title>
|
||||||
|
<meta name="description" content="Information about this Website" />
|
||||||
|
</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>
|
10
src/routes/assets/icons/+server.ts
Normal file
10
src/routes/assets/icons/+server.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import { json } from '@sveltejs/kit';
|
||||||
|
|
||||||
|
export function GET() {
|
||||||
|
let content = fs.readdirSync('static/assets/icons');
|
||||||
|
|
||||||
|
content = content.filter((entry) => entry != '.directory');
|
||||||
|
|
||||||
|
return json(content);
|
||||||
|
}
|
29
src/routes/css/+page.svelte
Normal file
29
src/routes/css/+page.svelte
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<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>
|
10
src/routes/data/servers/+server.ts
Normal file
10
src/routes/data/servers/+server.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
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);
|
||||||
|
}
|
10
src/routes/data/services/+server.ts
Normal file
10
src/routes/data/services/+server.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import { json } from '@sveltejs/kit';
|
||||||
|
|
||||||
|
export function GET() {
|
||||||
|
const content = fs.readFileSync('static/data/services.json').toString();
|
||||||
|
|
||||||
|
const data = JSON.parse(content);
|
||||||
|
|
||||||
|
return json(data);
|
||||||
|
}
|
62
src/routes/servers/+page.server.ts
Normal file
62
src/routes/servers/+page.server.ts
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
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;
|
||||||
|
}
|
97
src/routes/servers/+page.svelte
Normal file
97
src/routes/servers/+page.svelte
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
<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>
|
||||||
|
<title>Servers</title>
|
||||||
|
<meta name="description" content="Overview of Game Servers running on neshweb.net" />
|
||||||
|
</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>
|
62
src/routes/services/+page.server.ts
Normal file
62
src/routes/services/+page.server.ts
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
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;
|
||||||
|
}
|
|
@ -1,11 +1,85 @@
|
||||||
<svelte:options runes={true} />
|
<svelte:options runes={true} />
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import pages from '$lib/components/pages.json';
|
import ServiceCard from '$lib/components/ServiceCard.svelte';
|
||||||
import Card from '$lib/components/Card.svelte';
|
|
||||||
import type { Service } from '$lib/types/data-types';
|
import type { Service } from '$lib/types/data-types';
|
||||||
|
import { io } from 'socket.io-client';
|
||||||
|
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';
|
||||||
|
|
||||||
const services: Array<Service> = $state(pages.services);
|
let { data }: { data: { promise: Promise<string> } } = $props();
|
||||||
|
|
||||||
|
let token = $state();
|
||||||
|
|
||||||
|
data.promise.then((jwt) => {
|
||||||
|
token = jwt;
|
||||||
|
});
|
||||||
|
|
||||||
|
let services: readonly Service[] = $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/services').then((data: Service[]) => {
|
||||||
|
services = data;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
get('/assets/icons').then((data: string[]) => {
|
||||||
|
icons = data;
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
|
@ -13,8 +87,8 @@
|
||||||
<meta name="description" content="Overview of Services running on neshweb.net" />
|
<meta name="description" content="Overview of Services running on neshweb.net" />
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<div class="flex h-full flex-row flex-wrap justify-center gap-10 overflow-auto p-8">
|
<div class="flex max-h-full flex-row flex-wrap justify-center gap-10 overflow-auto p-8">
|
||||||
{#each services as service}
|
{#each services as service}
|
||||||
<Card {service} />
|
<ServiceCard {service} {icons} monitor={monitorList.get(service.id)} />
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
BIN
static/assets/icons/calibre-logo-36.avif
Normal file
BIN
static/assets/icons/calibre-logo-36.avif
Normal file
Binary file not shown.
Binary file not shown.
BIN
static/assets/icons/navidrome-logo-36.avif
Normal file
BIN
static/assets/icons/navidrome-logo-36.avif
Normal file
Binary file not shown.
Binary file not shown.
BIN
static/assets/icons/npm-logo-36.avif
Normal file
BIN
static/assets/icons/npm-logo-36.avif
Normal file
Binary file not shown.
Binary file not shown.
BIN
static/assets/icons/portainer-logo-36.avif
Normal file
BIN
static/assets/icons/portainer-logo-36.avif
Normal file
Binary file not shown.
Binary file not shown.
25
static/data/servers.json
Normal file
25
static/data/servers.json
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Minecraft",
|
||||||
|
"icon": "/assets/icons/minecraft-logo",
|
||||||
|
"iconType": "avif",
|
||||||
|
"connection": "minecraft.neshweb.net",
|
||||||
|
"href": "https://minecraft.neshweb.net/",
|
||||||
|
"desc": "View all currently available Minecraft Servers and their mods",
|
||||||
|
"id": 38
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ready or Not",
|
||||||
|
"icon": "/assets/icons/ron-logo",
|
||||||
|
"iconType": "avif",
|
||||||
|
"href": "https://readyornot.neshweb.net/",
|
||||||
|
"desc": "Collection of Floor Plans for the Game 'Ready or Not'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Factorio"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Space Engineers",
|
||||||
|
"id": 13
|
||||||
|
}
|
||||||
|
]
|
138
static/data/services.json
Normal file
138
static/data/services.json
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Nextcloud",
|
||||||
|
"icon": "/assets/icons/nextcloud-logo",
|
||||||
|
"iconType": "svg",
|
||||||
|
"href": "https://nextcloud.neshweb.net/",
|
||||||
|
"desc": "Self-hosted Cloud Storage Service",
|
||||||
|
"warn": "Note: Registration requires approval",
|
||||||
|
"extLink": "https://nextcloud.com/",
|
||||||
|
"id": 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Kavita",
|
||||||
|
"icon": "/assets/icons/kavita-logo",
|
||||||
|
"iconType": "svg",
|
||||||
|
"href": "https://kavita.neshweb.net/",
|
||||||
|
"desc": "Self-hosted Manga Library",
|
||||||
|
"warn": "Registration via Admin invite",
|
||||||
|
"id": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Images",
|
||||||
|
"icon": "/assets/icons/images-logo",
|
||||||
|
"iconType": "svg",
|
||||||
|
"href": "https://imgs.neshweb.net/",
|
||||||
|
"desc": "Self-hosted Chevereto Image Service",
|
||||||
|
"warn": "",
|
||||||
|
"extLink": "https://chevereto.com/",
|
||||||
|
"id": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Calibre Web",
|
||||||
|
"icon": "/assets/icons/calibre-logo",
|
||||||
|
"iconType": "avif",
|
||||||
|
"href": "https://calibre.neshweb.net/",
|
||||||
|
"desc": "Self-hosted Ebook Library Service",
|
||||||
|
"warn": "Note: Registration only via Admin",
|
||||||
|
"id": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PeerTube",
|
||||||
|
"icon": "/assets/icons/peertube-logo",
|
||||||
|
"iconType": "svg",
|
||||||
|
"href": "https://neshweb.tv/",
|
||||||
|
"desc": "Self-hosted PeerTube Instance",
|
||||||
|
"warn": "Note: Registration only via Admin",
|
||||||
|
"id": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mastodon",
|
||||||
|
"icon": "/assets/icons/mastodon-logo",
|
||||||
|
"iconType": "svg",
|
||||||
|
"href": "https://mastodon.neshweb.net/",
|
||||||
|
"desc": "Self-hosted Mastodon Instance",
|
||||||
|
"warn": "Note: Registration requires approval",
|
||||||
|
"id": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Vaultwarden",
|
||||||
|
"icon": "/assets/icons/vaultwarden-logo",
|
||||||
|
"iconType": "svg",
|
||||||
|
"href": "https://vault.neshweb.net/",
|
||||||
|
"desc": "Self-hosted Password Manager",
|
||||||
|
"warn": "Note: Invite only",
|
||||||
|
"id": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jellyfin",
|
||||||
|
"icon": "/assets/icons/jellyfin-logo",
|
||||||
|
"iconType": "svg",
|
||||||
|
"href": "https://mov.neshweb.tv/",
|
||||||
|
"desc": "Open-Source, Self-Hosted Media Platform",
|
||||||
|
"warn": "Note: Registration only via Admin",
|
||||||
|
"id": 37
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Navidrome",
|
||||||
|
"icon": "/assets/icons/navidrome-logo",
|
||||||
|
"iconType": "avif",
|
||||||
|
"href": "https://navidrome.neshweb.net/",
|
||||||
|
"desc": "Open-Source, Self-Hosted Music Streaming Platform",
|
||||||
|
"warn": "Note: Registration only via Admin",
|
||||||
|
"id": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Forgejo",
|
||||||
|
"icon": "/assets/icons/forgejo-logo",
|
||||||
|
"iconType": "svg",
|
||||||
|
"href": "https://forgejo.neshweb.net/",
|
||||||
|
"desc": "Self-hosted Git Service",
|
||||||
|
"warn": "Note: Registration only via Admin",
|
||||||
|
"id": 36
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Portainer",
|
||||||
|
"icon": "/assets/icons/portainer-logo",
|
||||||
|
"iconType": "avif",
|
||||||
|
"href": "https://portainer.neshweb.net/",
|
||||||
|
"desc": "Docker Container Manager",
|
||||||
|
"warn": "Note: Admin Only",
|
||||||
|
"id": 34
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nginx",
|
||||||
|
"icon": "/assets/icons/npm-logo",
|
||||||
|
"iconType": "avif",
|
||||||
|
"href": "https://nginx.neshweb.net/",
|
||||||
|
"desc": "Web-based Nginx Proxy Manager",
|
||||||
|
"warn": "Note: Admin Only",
|
||||||
|
"id": 31
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Proxmox",
|
||||||
|
"icon": "/assets/icons/proxmox-logo",
|
||||||
|
"iconType": "avif",
|
||||||
|
"href": "https://proxmox.neshweb.net/",
|
||||||
|
"desc": "Hypervisor Webinterface",
|
||||||
|
"warn": "Note: Admin Only",
|
||||||
|
"id": 33
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Dockge",
|
||||||
|
"icon": "/assets/icons/dockge-logo",
|
||||||
|
"iconType": "avif",
|
||||||
|
"href": "https://dockge.neshweb.net/",
|
||||||
|
"desc": "Docker Compose WebUI",
|
||||||
|
"warn": "Note: Admin Only",
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
]
|
|
@ -1,6 +1,10 @@
|
||||||
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 path from "path";
|
import { readFileSync } from 'node:fs';
|
||||||
|
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 = {
|
||||||
|
@ -13,6 +17,9 @@ 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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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"],
|
safelist: ["dark", "nordlys"],
|
||||||
theme: {
|
theme: {
|
||||||
container: {
|
container: {
|
||||||
center: true,
|
center: true,
|
||||||
|
@ -68,6 +68,9 @@ const config = {
|
||||||
},
|
},
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
sans: [...fontFamily.sans]
|
sans: [...fontFamily.sans]
|
||||||
|
},
|
||||||
|
aspectRatio: {
|
||||||
|
'16/9': '16 / 9',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
13
unlighthouse.config.ts
Normal file
13
unlighthouse.config.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
export default {
|
||||||
|
site: 'http://localhost:8000',
|
||||||
|
ci: {
|
||||||
|
budget: {
|
||||||
|
performance: 90,
|
||||||
|
accessibility: 100,
|
||||||
|
'best-practices': 90,
|
||||||
|
seo: 90
|
||||||
|
},
|
||||||
|
buildStatic: true
|
||||||
|
},
|
||||||
|
urls: ['/', '/servers', '/services', '/about']
|
||||||
|
};
|
260
yarn.lock
260
yarn.lock
|
@ -372,6 +372,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.2.tgz#830f3a3fba67f6216a5884368431918029045afe"
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.2.tgz#830f3a3fba67f6216a5884368431918029045afe"
|
||||||
integrity sha512-SYRedJi+mweatroB+6TTnJYLts0L0bosg531xnQWtklOI6dezEagx4Q0qDyvRdK+qgdA3YZpjjGuPFtxBmddBA==
|
integrity sha512-SYRedJi+mweatroB+6TTnJYLts0L0bosg531xnQWtklOI6dezEagx4Q0qDyvRdK+qgdA3YZpjjGuPFtxBmddBA==
|
||||||
|
|
||||||
|
"@socket.io/component-emitter@~3.1.0":
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553"
|
||||||
|
integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==
|
||||||
|
|
||||||
"@sveltejs/adapter-auto@^3.0.0":
|
"@sveltejs/adapter-auto@^3.0.0":
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-auto/-/adapter-auto-3.0.1.tgz#540df9a7ce94f6dea4f1a8fd3be8b711a882efce"
|
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-auto/-/adapter-auto-3.0.1.tgz#540df9a7ce94f6dea4f1a8fd3be8b711a882efce"
|
||||||
|
@ -423,11 +428,23 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib "^2.4.0"
|
tslib "^2.4.0"
|
||||||
|
|
||||||
|
"@types/cookie@^0.4.1":
|
||||||
|
version "0.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d"
|
||||||
|
integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==
|
||||||
|
|
||||||
"@types/cookie@^0.6.0":
|
"@types/cookie@^0.6.0":
|
||||||
version "0.6.0"
|
version "0.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.6.0.tgz#eac397f28bf1d6ae0ae081363eca2f425bedf0d5"
|
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.6.0.tgz#eac397f28bf1d6ae0ae081363eca2f425bedf0d5"
|
||||||
integrity sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==
|
integrity sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==
|
||||||
|
|
||||||
|
"@types/cors@^2.8.12":
|
||||||
|
version "2.8.17"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.17.tgz#5d718a5e494a8166f569d986794e49c48b216b2b"
|
||||||
|
integrity sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
"@types/eslint@8.56.0":
|
"@types/eslint@8.56.0":
|
||||||
version "8.56.0"
|
version "8.56.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.56.0.tgz#e28d045b8e530a33c9cbcfbf02332df0d1380a2c"
|
resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.56.0.tgz#e28d045b8e530a33c9cbcfbf02332df0d1380a2c"
|
||||||
|
@ -446,6 +463,13 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
|
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
|
||||||
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
|
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
|
||||||
|
|
||||||
|
"@types/node@*", "@types/node@>=10.0.0":
|
||||||
|
version "20.10.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.6.tgz#a3ec84c22965802bf763da55b2394424f22bfbb5"
|
||||||
|
integrity sha512-Vac8H+NlRNNlAmDfGUP7b5h/KA+AtWIzuXy0E6OyP8f1tCLYAtPvKRRDJjAPqhpCb0t6U2j7/xqAuLEebW2kiw==
|
||||||
|
dependencies:
|
||||||
|
undici-types "~5.26.4"
|
||||||
|
|
||||||
"@types/pug@^2.0.6":
|
"@types/pug@^2.0.6":
|
||||||
version "2.0.10"
|
version "2.0.10"
|
||||||
resolved "https://registry.yarnpkg.com/@types/pug/-/pug-2.0.10.tgz#52f8dbd6113517aef901db20b4f3fca543b88c1f"
|
resolved "https://registry.yarnpkg.com/@types/pug/-/pug-2.0.10.tgz#52f8dbd6113517aef901db20b4f3fca543b88c1f"
|
||||||
|
@ -456,6 +480,13 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.6.tgz#c65b2bfce1bec346582c07724e3f8c1017a20339"
|
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.6.tgz#c65b2bfce1bec346582c07724e3f8c1017a20339"
|
||||||
integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==
|
integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==
|
||||||
|
|
||||||
|
"@types/socket.io@^3.0.2":
|
||||||
|
version "3.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/socket.io/-/socket.io-3.0.2.tgz#606c9639e3f93bb8454cba8f5f0a283d47917759"
|
||||||
|
integrity sha512-pu0sN9m5VjCxBZVK8hW37ZcMe8rjn4HHggBN5CbaRTvFwv5jOmuIRZEuddsBPa9Th0ts0SIo3Niukq+95cMBbQ==
|
||||||
|
dependencies:
|
||||||
|
socket.io "*"
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin@^6.0.0":
|
"@typescript-eslint/eslint-plugin@^6.0.0":
|
||||||
version "6.16.0"
|
version "6.16.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.16.0.tgz#cc29fbd208ea976de3db7feb07755bba0ce8d8bc"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.16.0.tgz#cc29fbd208ea976de3db7feb07755bba0ce8d8bc"
|
||||||
|
@ -547,6 +578,14 @@
|
||||||
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
|
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
|
||||||
integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
|
integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
|
||||||
|
|
||||||
|
accepts@~1.3.4:
|
||||||
|
version "1.3.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
|
||||||
|
integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
|
||||||
|
dependencies:
|
||||||
|
mime-types "~2.1.34"
|
||||||
|
negotiator "0.6.3"
|
||||||
|
|
||||||
acorn-jsx@^5.3.2:
|
acorn-jsx@^5.3.2:
|
||||||
version "5.3.2"
|
version "5.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
|
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
|
||||||
|
@ -653,15 +692,20 @@ balanced-match@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||||
|
|
||||||
|
base64id@2.0.0, base64id@~2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
|
||||||
|
integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==
|
||||||
|
|
||||||
binary-extensions@^2.0.0:
|
binary-extensions@^2.0.0:
|
||||||
version "2.2.0"
|
version "2.2.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.0:
|
bits-ui@^0.13.2:
|
||||||
version "0.13.0"
|
version "0.13.2"
|
||||||
resolved "https://registry.yarnpkg.com/bits-ui/-/bits-ui-0.13.0.tgz#dff61c8b4a95b1f589105444da74396bdc6702e7"
|
resolved "https://registry.yarnpkg.com/bits-ui/-/bits-ui-0.13.2.tgz#caf47bfed774c7f28600b1d41ac69db0509ec347"
|
||||||
integrity sha512-XMvGKhJQMvSWqaan0eaIx1uAVcFBpImgO6xf+XTb7UhqdzbH0//6be4DeR1nRUpIU70XoU1B7i3lMPrTWg37ng==
|
integrity sha512-hSxj/BDazR49j2QkgsAnWjHsWdG6OvprCF0IagQm4mDf1pwiunXXJMnSciNxocvaZ/HAkKQRf8R6orwDPO/HYg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@internationalized/date" "^3.5.1"
|
"@internationalized/date" "^3.5.1"
|
||||||
"@melt-ui/svelte" "0.67.0"
|
"@melt-ui/svelte" "0.67.0"
|
||||||
|
@ -774,6 +818,19 @@ cookie@^0.6.0:
|
||||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
|
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
|
||||||
integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
|
integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
|
||||||
|
|
||||||
|
cookie@~0.4.1:
|
||||||
|
version "0.4.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
|
||||||
|
integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
|
||||||
|
|
||||||
|
cors@~2.8.5:
|
||||||
|
version "2.8.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
|
||||||
|
integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
|
||||||
|
dependencies:
|
||||||
|
object-assign "^4"
|
||||||
|
vary "^1"
|
||||||
|
|
||||||
cross-spawn@^7.0.0, cross-spawn@^7.0.2:
|
cross-spawn@^7.0.0, cross-spawn@^7.0.2:
|
||||||
version "7.0.3"
|
version "7.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
||||||
|
@ -788,7 +845,7 @@ cssesc@^3.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
|
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
|
||||||
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
|
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
|
||||||
|
|
||||||
debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
|
debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2:
|
||||||
version "4.3.4"
|
version "4.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
||||||
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
||||||
|
@ -800,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.3.1:
|
deepmerge@^4.2.2, 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==
|
||||||
|
@ -844,6 +901,36 @@ 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"
|
||||||
|
@ -864,6 +951,43 @@ emoji-regex@^9.2.2:
|
||||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
|
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
|
||||||
integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
|
integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
|
||||||
|
|
||||||
|
engine.io-client@~6.5.2:
|
||||||
|
version "6.5.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.5.3.tgz#4cf6fa24845029b238f83c628916d9149c399bc5"
|
||||||
|
integrity sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==
|
||||||
|
dependencies:
|
||||||
|
"@socket.io/component-emitter" "~3.1.0"
|
||||||
|
debug "~4.3.1"
|
||||||
|
engine.io-parser "~5.2.1"
|
||||||
|
ws "~8.11.0"
|
||||||
|
xmlhttprequest-ssl "~2.0.0"
|
||||||
|
|
||||||
|
engine.io-parser@~5.2.1:
|
||||||
|
version "5.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.1.tgz#9f213c77512ff1a6cc0c7a86108a7ffceb16fcfb"
|
||||||
|
integrity sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==
|
||||||
|
|
||||||
|
engine.io@~6.5.2:
|
||||||
|
version "6.5.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.5.4.tgz#6822debf324e781add2254e912f8568508850cdc"
|
||||||
|
integrity sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==
|
||||||
|
dependencies:
|
||||||
|
"@types/cookie" "^0.4.1"
|
||||||
|
"@types/cors" "^2.8.12"
|
||||||
|
"@types/node" ">=10.0.0"
|
||||||
|
accepts "~1.3.4"
|
||||||
|
base64id "2.0.0"
|
||||||
|
cookie "~0.4.1"
|
||||||
|
cors "~2.8.5"
|
||||||
|
debug "~4.3.1"
|
||||||
|
engine.io-parser "~5.2.1"
|
||||||
|
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"
|
||||||
|
@ -1231,6 +1355,16 @@ 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"
|
||||||
|
@ -1308,6 +1442,11 @@ 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"
|
||||||
|
@ -1445,6 +1584,18 @@ micromatch@^4.0.4, micromatch@^4.0.5:
|
||||||
braces "^3.0.2"
|
braces "^3.0.2"
|
||||||
picomatch "^2.3.1"
|
picomatch "^2.3.1"
|
||||||
|
|
||||||
|
mime-db@1.52.0:
|
||||||
|
version "1.52.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
|
||||||
|
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
|
||||||
|
|
||||||
|
mime-types@~2.1.34:
|
||||||
|
version "2.1.35"
|
||||||
|
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
|
||||||
|
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
|
||||||
|
dependencies:
|
||||||
|
mime-db "1.52.0"
|
||||||
|
|
||||||
min-indent@^1.0.0:
|
min-indent@^1.0.0:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
|
resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
|
||||||
|
@ -1525,6 +1676,11 @@ natural-compare@^1.4.0:
|
||||||
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||||
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
|
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
|
||||||
|
|
||||||
|
negotiator@0.6.3:
|
||||||
|
version "0.6.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
|
||||||
|
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
|
||||||
|
|
||||||
node-releases@^2.0.14:
|
node-releases@^2.0.14:
|
||||||
version "2.0.14"
|
version "2.0.14"
|
||||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b"
|
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b"
|
||||||
|
@ -1540,7 +1696,7 @@ normalize-range@^0.1.2:
|
||||||
resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
|
resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
|
||||||
integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==
|
integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==
|
||||||
|
|
||||||
object-assign@^4.0.1:
|
object-assign@^4, object-assign@^4.0.1:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||||
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
|
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
|
||||||
|
@ -1590,6 +1746,11 @@ 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"
|
||||||
|
@ -1713,6 +1874,15 @@ 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"
|
||||||
|
@ -1853,6 +2023,18 @@ 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"
|
||||||
|
@ -1896,6 +2078,44 @@ slash@^3.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
|
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
|
||||||
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
||||||
|
|
||||||
|
socket.io-adapter@~2.5.2:
|
||||||
|
version "2.5.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz#5de9477c9182fdc171cd8c8364b9a8894ec75d12"
|
||||||
|
integrity sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==
|
||||||
|
dependencies:
|
||||||
|
ws "~8.11.0"
|
||||||
|
|
||||||
|
socket.io-client@^4.7.2:
|
||||||
|
version "4.7.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.7.2.tgz#f2f13f68058bd4e40f94f2a1541f275157ff2c08"
|
||||||
|
integrity sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==
|
||||||
|
dependencies:
|
||||||
|
"@socket.io/component-emitter" "~3.1.0"
|
||||||
|
debug "~4.3.2"
|
||||||
|
engine.io-client "~6.5.2"
|
||||||
|
socket.io-parser "~4.2.4"
|
||||||
|
|
||||||
|
socket.io-parser@~4.2.4:
|
||||||
|
version "4.2.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz#c806966cf7270601e47469ddeec30fbdfda44c83"
|
||||||
|
integrity sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==
|
||||||
|
dependencies:
|
||||||
|
"@socket.io/component-emitter" "~3.1.0"
|
||||||
|
debug "~4.3.1"
|
||||||
|
|
||||||
|
socket.io@*, socket.io@^4.7.2:
|
||||||
|
version "4.7.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.7.2.tgz#22557d76c3f3ca48f82e73d68b7add36a22df002"
|
||||||
|
integrity sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw==
|
||||||
|
dependencies:
|
||||||
|
accepts "~1.3.4"
|
||||||
|
base64id "~2.0.0"
|
||||||
|
cors "~2.8.5"
|
||||||
|
debug "~4.3.2"
|
||||||
|
engine.io "~6.5.2"
|
||||||
|
socket.io-adapter "~2.5.2"
|
||||||
|
socket.io-parser "~4.2.4"
|
||||||
|
|
||||||
sorcery@^0.11.0:
|
sorcery@^0.11.0:
|
||||||
version "0.11.0"
|
version "0.11.0"
|
||||||
resolved "https://registry.yarnpkg.com/sorcery/-/sorcery-0.11.0.tgz#310c80ee993433854bb55bb9aa4003acd147fca8"
|
resolved "https://registry.yarnpkg.com/sorcery/-/sorcery-0.11.0.tgz#310c80ee993433854bb55bb9aa4003acd147fca8"
|
||||||
|
@ -2023,9 +2243,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.27"
|
version "5.0.0-next.28"
|
||||||
resolved "https://registry.yarnpkg.com/svelte/-/svelte-5.0.0-next.27.tgz#e7e48490032d64234780b453271406af87edef52"
|
resolved "https://registry.yarnpkg.com/svelte/-/svelte-5.0.0-next.28.tgz#6ebcf3da041f9ec60ffffa38dfbc6b262813d2ba"
|
||||||
integrity sha512-5I4JrmEWVPu4ALEskqU/xdz6PsJYnRaWiIN/s7BCvtuwHjy2mbclSfC+VzgCxEN0AEJxdsPXsxYkIfwXch3AyQ==
|
integrity sha512-a9Nqq8eczeJMrOlDL24LMI1MKXMZhDhH33tL8lkPilUJyTjk4W97zYC/hKlZOeAFKdSOBZPIeLFH+NHR2iNSRQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@ampproject/remapping" "^2.2.1"
|
"@ampproject/remapping" "^2.2.1"
|
||||||
"@jridgewell/sourcemap-codec" "^1.4.15"
|
"@jridgewell/sourcemap-codec" "^1.4.15"
|
||||||
|
@ -2163,6 +2383,11 @@ typescript@^5.0.0, typescript@^5.0.3:
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37"
|
||||||
integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==
|
integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==
|
||||||
|
|
||||||
|
undici-types@~5.26.4:
|
||||||
|
version "5.26.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
|
||||||
|
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
|
||||||
|
|
||||||
update-browserslist-db@^1.0.13:
|
update-browserslist-db@^1.0.13:
|
||||||
version "1.0.13"
|
version "1.0.13"
|
||||||
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4"
|
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4"
|
||||||
|
@ -2183,6 +2408,11 @@ util-deprecate@^1.0.2:
|
||||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||||
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
|
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
|
||||||
|
|
||||||
|
vary@^1:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||||
|
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
|
||||||
|
|
||||||
vite@^5.0.3:
|
vite@^5.0.3:
|
||||||
version "5.0.10"
|
version "5.0.10"
|
||||||
resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.10.tgz#1e13ef5c3cf5aa4eed81f5df6d107b3c3f1f6356"
|
resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.10.tgz#1e13ef5c3cf5aa4eed81f5df6d107b3c3f1f6356"
|
||||||
|
@ -2229,6 +2459,16 @@ wrappy@1:
|
||||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||||
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
|
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
|
||||||
|
|
||||||
|
ws@~8.11.0:
|
||||||
|
version "8.11.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143"
|
||||||
|
integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==
|
||||||
|
|
||||||
|
xmlhttprequest-ssl@~2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67"
|
||||||
|
integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==
|
||||||
|
|
||||||
yallist@^4.0.0:
|
yallist@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
|
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
|
||||||
|
|
Loading…
Reference in a new issue