refactor: massively simplify to svelte with web/ directory, prepare for backend

This commit is contained in:
2026-01-04 15:10:35 -06:00
parent af81d8e048
commit 07ea1c093e
89 changed files with 1180 additions and 9659 deletions
-88
View File
@@ -1,88 +0,0 @@
# Source control
.git
.github
.gitignore
# Environment files - STRICT - no .env files at all
.env*
!.env.example
**/.env*
# Dependencies (installed in container)
node_modules
**/node_modules
# Build outputs (built in container)
.next
.svelte-kit
build
dist
**/dist
**/.next
**/.svelte-kit
**/build
# Cache & temp
.turbo
**/.turbo
.cache
**/.cache
*.tsbuildinfo
# Logs
*.log
npm-debug.log*
yarn-debug.log*
pnpm-debug.log*
lerna-debug.log*
# OS files
.DS_Store
Thumbs.db
# IDE
.vscode
.idea
*.swp
*.swo
*~
# Testing - exclude all test files
coverage
.nyc_output
tests
**/tests
test
**/test
*.test.*
*.spec.*
**/*.test.*
**/*.spec.*
playwright.config.*
playwright-report
test-results
vitest.config.*
vitest.setup.*
# Development configs
.editorconfig
.prettierrc*
.prettierignore
.eslintrc*
eslint.config.*
# Development specific
*.local
tmp
temp
*.tmp
# Documentation and project files
*.md
CHANGELOG*
LICENSE*
docs
**/docs
# Build artifacts
docker-build.log
-16
View File
@@ -1,16 +0,0 @@
# Database
DATABASE_URL=postgresql://user:password@localhost:5432/xevion
# Payload CMS
PAYLOAD_SECRET=development-secret-change-in-production
# R2 Storage (optional for local dev)
R2_ENDPOINT=https://YOUR_ACCOUNT_ID.r2.cloudflarestorage.com
R2_BUCKET_NAME=xevion-media
R2_ACCESS_KEY_ID=your_access_key
R2_SECRET_ACCESS_KEY=your_secret_key
# Application
NODE_ENV=development
PORT=3000
ORIGIN=http://localhost:3000
Vendored
+4 -45
View File
@@ -1,46 +1,5 @@
# Dependencies web/node_modules/
node_modules/ target/
# Build outputs
.next/
.svelte-kit/
build/
dist/
.turbo/
*.tsbuildinfo
# Environment - only in root
/.env
/.env*.local
# Logs
*.log
npm-debug.log*
yarn-debug.log*
pnpm-debug.log*
# OS
.DS_Store
Thumbs.db
# IDE
.vscode/ .vscode/
.idea/ web/build/
*.swp web/.svelte-kit/
*.swo
*~
# Testing
coverage/
# Temporary
tmp/
temp/
*.tmp
# Playwright
playwright-report/
test-results/
# Docker
docker-build.log
-2
View File
@@ -2,7 +2,6 @@
"cSpell.words": [ "cSpell.words": [
"azabani", "azabani",
"CLIENTVAR", "CLIENTVAR",
"directus",
"hanken", "hanken",
"headlessui", "headlessui",
"Hoverable", "Hoverable",
@@ -12,7 +11,6 @@
"plaiceholder", "plaiceholder",
"runnerspace", "runnerspace",
"SERVERVAR", "SERVERVAR",
"turbopack",
"usehooks" "usehooks"
], ],
"spellright.language": ["en"], "spellright.language": ["en"],
-88
View File
@@ -1,88 +0,0 @@
{
admin off
auto_https off
persist_config off
log {
format json
output stdout
level INFO
}
servers {
protocols h1 h2 h2c
timeouts {
read_body 10s
read_header 10s
write 30s
idle 120s
}
}
}
# Listen on Railway's PORT or default to 3000
:{$PORT:3000} {
# Security headers
header {
# HSTS (only in production with HTTPS)
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
# Prevent clickjacking
X-Frame-Options "SAMEORIGIN"
# XSS Protection
X-Content-Type-Options "nosniff"
X-XSS-Protection "1; mode=block"
# Referrer policy
Referrer-Policy "strict-origin-when-cross-origin"
# Content Security Policy (adjust as needed)
Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:;"
# Permissions policy
Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=()"
# Remove server identification
-Server
-X-Powered-By
}
handle /admin* {
reverse_proxy localhost:5001 {
header_up Host {host}
header_up X-Real-IP {remote_host}
transport http {
read_timeout 60s
write_timeout 60s
}
}
}
handle {
reverse_proxy localhost:5000 {
header_up Host {host}
header_up X-Real-IP {remote_host}
transport http {
read_timeout 30s
write_timeout 30s
}
}
}
# Error handling
handle_errors {
@5xx expression `{http.error.status_code} >= 500`
handle @5xx {
respond "Service temporarily unavailable" 503 {
close
}
}
respond "{http.error.status_code} {http.error.status_text}" {
close
}
}
}
-61
View File
@@ -1,61 +0,0 @@
FROM oven/bun:1-alpine AS base
WORKDIR /app
RUN apk add --no-cache libc6-compat
# Install dependencies
FROM base AS deps
COPY package.json bun.lock ./
COPY packages/db/package.json ./packages/db/
COPY packages/types/package.json ./packages/types/
COPY packages/typescript-config/package.json ./packages/typescript-config/
COPY apps/payload/package.json ./apps/payload/
COPY apps/web/package.json ./apps/web/
RUN bun install --frozen-lockfile
# Build everything
FROM base AS builder
COPY --from=deps /app ./
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN bun run build
# Compile SvelteKit to standalone executable
RUN bun build --compile --target=bun --minify --outfile=apps/web/web-server ./apps/web/build/index.js
# Production image
FROM oven/bun:1-alpine AS runner
WORKDIR /app
RUN apk add --no-cache caddy && \
addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
ENV NODE_ENV=production
ENV PORT=3000
ENV NEXT_TELEMETRY_DISABLED=1
# Copy built artifacts
COPY --from=builder --chown=nextjs:nodejs /app/packages/db/dist ./packages/db/dist
COPY --from=builder --chown=nextjs:nodejs /app/packages/db/package.json ./packages/db/
COPY --from=builder --chown=nextjs:nodejs /app/packages/types/dist ./packages/types/dist
COPY --from=builder --chown=nextjs:nodejs /app/packages/types/package.json ./packages/types/
# Payload standalone build
COPY --from=builder --chown=nextjs:nodejs /app/apps/payload/.next/standalone ./apps/payload/.next/standalone
COPY --from=builder --chown=nextjs:nodejs /app/apps/payload/.next/static ./apps/payload/.next/standalone/apps/payload/.next/static
COPY --from=builder --chown=nextjs:nodejs /app/apps/payload/public ./apps/payload/.next/standalone/apps/payload/public
COPY --from=builder --chown=nextjs:nodejs /app/apps/payload/src/migrations ./apps/payload/.next/standalone/apps/payload/src/migrations
# Web standalone executable (no node_modules needed)
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/web-server ./apps/web/
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/build/client ./apps/web/build/client
# Entrypoint
COPY --chown=nextjs:nodejs Caddyfile docker-entrypoint.ts ./
RUN chmod +x docker-entrypoint.ts && \
caddy fmt --overwrite Caddyfile
USER nextjs
EXPOSE ${PORT}
ENTRYPOINT ["bun", "run", "docker-entrypoint.ts"]
+10 -145
View File
@@ -1,148 +1,13 @@
# Default environment variables dev:
default_database_url := "postgresql://xevion:xevion@xevion-db:5432/xevion" bun run --cwd web dev
default_payload_secret := "development-secret-change-in-production"
network_name := "xevion-net"
# Build the Docker image setup:
docker-build: bun install --cwd web
docker build -t xevion.dev .
# Run the Docker container (uses .env if available, otherwise defaults) build:
docker-run: bun run --cwd web build
#!/bin/sh
docker network create {{network_name}} 2>/dev/null || true
if [ -f .env ]; then
echo "Loading environment from .env file..."
docker run -p 3000:3000 \
--network {{network_name}} \
-e DATABASE_URL="{{default_database_url}}" \
--env-file .env \
xevion.dev | hl -P
else
echo "No .env file found, using defaults..."
docker run -p 3000:3000 \
--network {{network_name}} \
-e DATABASE_URL="{{default_database_url}}" \
-e PAYLOAD_SECRET="{{default_payload_secret}}" \
xevion.dev | hl -P
fi
# Start the PostgreSQL database container check:
docker-db: bun run --cwd web format
#!/bin/sh bun run --cwd web lint
docker network create {{network_name}} 2>/dev/null || true bun run --cwd web check
docker run --name xevion-db \
--network {{network_name}} \
-p 5432:5432 \
-e POSTGRES_USER=xevion \
-e POSTGRES_PASSWORD=xevion \
-e POSTGRES_DB=xevion \
-d postgres
# Stop and remove the database container
docker-db-stop:
docker stop xevion-db && docker rm xevion-db
# Test Docker image with health checks
[script("bun")]
docker-test:
const $ = async (cmd: string[]) => Bun.spawn(cmd).exited;
const $out = (cmd: string[]) => Bun.spawnSync(cmd).stdout.toString();
// Ensure network exists (suppress error if already exists)
Bun.spawnSync(["docker", "network", "create", "{{network_name}}"], { stderr: "ignore" });
// Find available port
const used = new Set(
$out(["ss", "-tuln"]).split("\n").slice(1)
.map(l => l.match(/:(\d+)/)?.[1]).filter(Boolean)
);
const ranges = [[49152, 65535], [10000, 32767], [5000, 9999]];
const available = ranges
.flatMap(([s, e]) => Array.from({ length: e - s + 1 }, (_, i) => s + i))
.filter(p => !used.has(String(p)));
const port = available[~~(Math.random() * available.length)];
console.log(`Using port ${port}`);
// Start container
const container = `xevion-test-${port}`;
const dbUrl = "{{default_database_url}}";
const secret = "{{default_payload_secret}}";
await $([
"docker", "run", "-d", "--name", container,
"--network", "{{network_name}}",
"-p", `${port}:3000`,
"-e", `DATABASE_URL=${dbUrl}`,
"-e", `PAYLOAD_SECRET=${secret}`,
"xevion.dev"
]);
const cleanup = async () => {
console.log("\nCleaning up...");
await $(["docker", "rm", "-f", container]);
};
process.on("SIGINT", async () => { await cleanup(); process.exit(1); });
process.on("SIGTERM", async () => { await cleanup(); process.exit(1); });
const base = `http://localhost:${port}`;
// Poll until success or timeout
const poll = async (
fn: () => Promise<boolean>,
{ timeout = 5000, interval = 1000 } = {}
): Promise<boolean> => {
const start = Date.now();
while (Date.now() - start < timeout) {
if (await fn()) return true;
await Bun.sleep(interval);
}
return false;
};
// Test a route with retries
const test = async (path: string, expect: { status?: number; contains?: string } = {}) => {
const { status = 200, contains } = expect;
let last = { status: 0, reason: "no response" };
const check = async () => {
try {
const res = await fetch(`${base}${path}`);
const text = await res.text();
if (res.status === status && (!contains || text.includes(contains))) return true;
last = { status: res.status, reason: contains && !text.includes(contains)
? `missing "${contains}"` : `status ${res.status}` };
return false;
} catch (e: any) { last = { status: 0, reason: e.code || e.message }; return false; }
};
const ok = await poll(check);
console.log(ok ? `${path}` : `${path} (${last.reason})`);
return ok;
};
// Wait for index
console.log("Waiting for server...");
const ready = await poll(async () => {
try { return (await fetch(base)).ok; } catch { return false; }
}, { timeout: 3000, interval: 100 });
if (!ready) {
console.error("Server failed to start");
await cleanup();
process.exit(1);
}
console.log("Server ready\n");
// Run tests sequentially
const tests = [
() => test("/projects"),
() => test("/blog"),
() => test("/admin", { contains: "Payload" }),
() => test("/admin/api/stats"),
];
const results: boolean[] = [];
for (const t of tests) results.push(await t());
await cleanup();
process.exit(results.every(Boolean) ? 0 : 1);
File diff suppressed because it is too large Load Diff
-38
View File
@@ -1,38 +0,0 @@
import { dirname } from 'path'
import { fileURLToPath } from 'url'
import { FlatCompat } from '@eslint/eslintrc'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
const compat = new FlatCompat({
baseDirectory: __dirname,
})
const eslintConfig = [
...compat.extends('next/core-web-vitals', 'next/typescript'),
{
rules: {
'@typescript-eslint/ban-ts-comment': 'warn',
'@typescript-eslint/no-empty-object-type': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unused-vars': [
'warn',
{
vars: 'all',
args: 'after-used',
ignoreRestSiblings: false,
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
destructuredArrayIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^(_|ignore)',
},
],
},
},
{
ignores: ['.next/'],
},
]
export default eslintConfig
-5
View File
@@ -1,5 +0,0 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
-31
View File
@@ -1,31 +0,0 @@
import { withPayload } from "@payloadcms/next/withPayload";
/** @type {import("next").NextConfig} */
const config = {
output: "standalone",
basePath: "/admin",
reactStrictMode: true,
images: {
remotePatterns: [
{
protocol: "https",
hostname: "img.walters.to",
},
{
protocol: "https",
hostname: "img.xevion.dev",
},
],
},
webpack: (webpackConfig) => {
webpackConfig.resolve.extensionAlias = {
".cjs": [".cts", ".cjs"],
".js": [".ts", ".tsx", ".js", ".jsx"],
".mjs": [".mts", ".mjs"],
};
return webpackConfig;
},
};
export default withPayload(config, { devBundleServerPackages: false });
-63
View File
@@ -1,63 +0,0 @@
{
"name": "@xevion/payload",
"version": "0.0.0",
"private": true,
"description": "PayloadCMS admin for xevion.dev",
"license": "MIT",
"type": "module",
"scripts": {
"build": "cross-env NODE_OPTIONS=\"--no-deprecation --max-old-space-size=8000\" next build",
"deploy": "echo 'Use Docker deployment'",
"dev": "cross-env NODE_OPTIONS=--no-deprecation next dev --port 5001",
"devsafe": "rm -rf .next && cross-env NODE_OPTIONS=--no-deprecation next dev",
"generate:importmap": "cross-env NODE_OPTIONS=--no-deprecation payload generate:importmap",
"generate:types": "cross-env NODE_OPTIONS=--no-deprecation payload generate:types",
"generate:schema": "pnpm run generate:schema:payload && pnpm run generate:schema:sync",
"generate:schema:payload": "cross-env NODE_OPTIONS=--no-deprecation payload generate:db-schema",
"generate:schema:sync": "cp src/payload-generated-schema.ts ../../packages/db/src/schema.ts && pnpm --filter @xevion/db build",
"ii": "pnpm install --ignore-workspace",
"lint": "cross-env NODE_OPTIONS=--no-deprecation next lint",
"payload": "cross-env NODE_OPTIONS=--no-deprecation payload",
"preview": "cross-env NODE_OPTIONS=--no-deprecation next start --port 5001",
"start": "cross-env NODE_OPTIONS=--no-deprecation next start --port 5001",
"test": "pnpm run test:int && pnpm run test:e2e",
"test:e2e": "cross-env NODE_OPTIONS=\"--no-deprecation --no-experimental-strip-types\" pnpm exec playwright test",
"test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts",
"clean": "rm -rf .next .turbo node_modules"
},
"dependencies": {
"@payloadcms/db-postgres": "3.69.0",
"@payloadcms/next": "3.69.0",
"@payloadcms/richtext-lexical": "3.69.0",
"@payloadcms/storage-s3": "3.69.0",
"@payloadcms/ui": "3.69.0",
"cross-env": "^7.0.3",
"dotenv": "16.4.7",
"graphql": "^16.8.1",
"next": "15.4.10",
"payload": "3.69.0",
"pino": "^9.6.0",
"pino-pretty": "^13.0.0",
"react": "19.2.1",
"react-dom": "19.2.1"
},
"devDependencies": {
"@playwright/test": "1.56.1",
"@testing-library/react": "16.3.0",
"@types/node": "^22.5.4",
"@types/react": "19.2.1",
"@types/react-dom": "19.2.1",
"@vitejs/plugin-react": "4.5.2",
"eslint": "^9.16.0",
"eslint-config-next": "15.4.7",
"jsdom": "26.1.0",
"playwright": "1.56.1",
"playwright-core": "1.56.1",
"vite-tsconfig-paths": "5.1.4",
"vitest": "3.2.3"
},
"engines": {
"node": "^18.20.2 || >=20.9.0",
"pnpm": "^9 || ^10"
}
}
-41
View File
@@ -1,41 +0,0 @@
import { defineConfig, devices } from '@playwright/test'
/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
import 'dotenv/config'
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: './tests/e2e',
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
// baseURL: 'http://localhost:3000',
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'], channel: 'chromium' },
},
],
webServer: {
command: 'pnpm dev',
reuseExistingServer: true,
url: 'http://localhost:3000',
},
})
@@ -1,19 +0,0 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import config from '@payload-config'
import '@payloadcms/next/css'
import {
REST_DELETE,
REST_GET,
REST_OPTIONS,
REST_PATCH,
REST_POST,
REST_PUT,
} from '@payloadcms/next/routes'
export const GET = REST_GET(config)
export const POST = REST_POST(config)
export const DELETE = REST_DELETE(config)
export const PATCH = REST_PATCH(config)
export const PUT = REST_PUT(config)
export const OPTIONS = REST_OPTIONS(config)
@@ -1,8 +0,0 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import config from '@payload-config'
import { GRAPHQL_POST, REST_OPTIONS } from '@payloadcms/next/routes'
export const POST = GRAPHQL_POST(config)
export const OPTIONS = REST_OPTIONS(config)
@@ -1,47 +0,0 @@
import configPromise from "@payload-config";
import { getPayload } from "payload";
import { NextRequest, NextResponse } from "next/server";
// Force this route to be dynamic
export const dynamic = "force-dynamic";
export async function GET(_request: NextRequest) {
try {
const payload = await getPayload({ config: configPromise });
// Fetch statistics about the content
const [projectsResult, technologiesResult, linksResult] = await Promise.all(
[
payload.count({ collection: "projects" }),
payload.count({ collection: "technologies" }),
payload.count({ collection: "links" }),
],
);
// Get featured projects count
const featuredProjects = await payload.count({
collection: "projects",
where: { featured: { equals: true } },
});
return NextResponse.json({
stats: {
projects: {
total: projectsResult.totalDocs,
featured: featuredProjects.totalDocs,
},
technologies: technologiesResult.totalDocs,
links: linksResult.totalDocs,
},
timestamp: new Date().toISOString(),
});
} catch (error) {
return NextResponse.json(
{
error: "Failed to fetch stats",
details: error instanceof Error ? error.message : "Unknown error",
},
{ status: 500 },
);
}
}
@@ -1,5 +0,0 @@
import { CollectionCards as CollectionCards_ab83ff7e88da8d3530831f296ec4756a } from '@payloadcms/ui/rsc'
export const importMap = {
'@payloadcms/ui/rsc#CollectionCards': CollectionCards_ab83ff7e88da8d3530831f296ec4756a,
}
-35
View File
@@ -1,35 +0,0 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import config from "@payload-config";
import "@payloadcms/next/css";
import type { ServerFunctionClient } from "payload";
import { handleServerFunctions, RootLayout } from "@payloadcms/next/layouts";
import React from "react";
import { importMap } from "./importMap.js";
import "./custom.scss";
type Args = {
children: React.ReactNode;
};
const serverFunction: ServerFunctionClient = async function (args) {
"use server";
return handleServerFunctions({
...args,
config,
importMap,
});
};
const Layout = ({ children }: Args) => (
<RootLayout
config={config}
importMap={importMap}
serverFunction={serverFunction}
>
{children}
</RootLayout>
);
export default Layout;
@@ -1,27 +0,0 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import type { Metadata } from "next";
import config from "@payload-config";
import { NotFoundPage, generatePageMetadata } from "@payloadcms/next/views";
import { importMap } from "./importMap";
type Args = {
params: Promise<{
segments: string[];
}>;
searchParams: Promise<{
[key: string]: string | string[];
}>;
};
export const generateMetadata = ({
params,
searchParams,
}: Args): Promise<Metadata> =>
generatePageMetadata({ config, params, searchParams });
const NotFound = ({ params, searchParams }: Args) =>
NotFoundPage({ config, params, searchParams, importMap });
export default NotFound;
-27
View File
@@ -1,27 +0,0 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import type { Metadata } from "next";
import config from "@payload-config";
import { RootPage, generatePageMetadata } from "@payloadcms/next/views";
import { importMap } from "./importMap";
type Args = {
params: Promise<{
segments: string[];
}>;
searchParams: Promise<{
[key: string]: string | string[];
}>;
};
export const generateMetadata = ({
params,
searchParams,
}: Args): Promise<Metadata> =>
generatePageMetadata({ config, params, searchParams });
const Page = ({ params, searchParams }: Args) =>
RootPage({ config, params, searchParams, importMap });
export default Page;
-31
View File
@@ -1,31 +0,0 @@
import type { CollectionConfig } from "payload";
export const Links: CollectionConfig = {
slug: "links",
admin: {
useAsTitle: "url",
},
fields: [
{
name: "url",
type: "text",
required: true,
label: "URL",
},
{
name: "icon",
type: "text",
label: "Icon (FontAwesome class)",
},
{
name: "description",
type: "text",
},
{
name: "project",
type: "relationship",
relationTo: "projects",
required: true,
},
],
};
-16
View File
@@ -1,16 +0,0 @@
import type { CollectionConfig } from "payload";
export const Media: CollectionConfig = {
slug: "media",
access: {
read: () => true,
},
fields: [
{
name: "alt",
type: "text",
required: true,
},
],
upload: true,
};
-92
View File
@@ -1,92 +0,0 @@
import type { CollectionConfig } from "payload";
export const Projects: CollectionConfig = {
slug: "projects",
admin: {
useAsTitle: "name",
defaultColumns: ["name", "featured", "status", "updatedAt"],
},
fields: [
{
name: "name",
type: "text",
required: true,
},
{
name: "description",
type: "textarea",
required: true,
},
{
name: "shortDescription",
type: "text",
label: "Short Description",
required: true,
},
{
name: "icon",
type: "text",
label: "Icon (FontAwesome class)",
},
{
name: "status",
type: "select",
options: [
{ label: "Draft", value: "draft" },
{ label: "Published", value: "published" },
{ label: "Archived", value: "archived" },
],
defaultValue: "draft",
required: true,
},
{
name: "featured",
type: "checkbox",
label: "Featured Project",
defaultValue: false,
},
{
name: "autocheckUpdated",
type: "checkbox",
label: "Auto-check for GitHub updates",
defaultValue: false,
admin: {
description:
"Automatically check GitHub for latest commits and update lastUpdated field",
},
},
{
name: "lastUpdated",
type: "date",
label: "Last Updated",
admin: {
description:
"Automatically updated by cron job based on GitHub commits",
date: {
displayFormat: "yyyy-MM-dd HH:mm:ss",
},
},
},
{
name: "wakatimeOffset",
type: "number",
label: "WakaTime Offset",
admin: {
description: "Offset for WakaTime fetched data (optional)",
},
},
{
name: "bannerImage",
type: "upload",
relationTo: "media",
label: "Banner Image",
},
{
name: "technologies",
type: "relationship",
relationTo: "technologies",
hasMany: true,
label: "Technologies Used",
},
],
};
@@ -1,20 +0,0 @@
import type { CollectionConfig } from "payload";
export const Technologies: CollectionConfig = {
slug: "technologies",
admin: {
useAsTitle: "name",
},
fields: [
{
name: "name",
type: "text",
required: true,
},
{
name: "url",
type: "text",
label: "URL",
},
],
};
-13
View File
@@ -1,13 +0,0 @@
import type { CollectionConfig } from "payload";
export const Users: CollectionConfig = {
slug: "users",
admin: {
useAsTitle: "email",
},
auth: true,
fields: [
// Email added by default
// Add more fields as needed
],
};
-32
View File
@@ -1,32 +0,0 @@
import type { GlobalConfig } from "payload";
export const Metadata: GlobalConfig = {
slug: "metadata",
access: {
read: () => true,
},
fields: [
{
name: "tagline",
type: "textarea",
required: true,
label: "Site Tagline",
},
{
name: "resume",
type: "upload",
relationTo: "media",
required: true,
label: "Resume File",
},
{
name: "resumeFilename",
type: "text",
label: "Resume Filename Override",
admin: {
description:
'Optional: Override the filename for the resume (e.g., "resume.pdf")',
},
},
],
};
File diff suppressed because it is too large Load Diff
@@ -1,218 +0,0 @@
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
await db.execute(sql`
CREATE TYPE "public"."enum_projects_status" AS ENUM('draft', 'published', 'archived');
CREATE TABLE "users_sessions" (
"_order" integer NOT NULL,
"_parent_id" integer NOT NULL,
"id" varchar PRIMARY KEY NOT NULL,
"created_at" timestamp(3) with time zone,
"expires_at" timestamp(3) with time zone NOT NULL
);
CREATE TABLE "users" (
"id" serial PRIMARY KEY NOT NULL,
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
"email" varchar NOT NULL,
"reset_password_token" varchar,
"reset_password_expiration" timestamp(3) with time zone,
"salt" varchar,
"hash" varchar,
"login_attempts" numeric DEFAULT 0,
"lock_until" timestamp(3) with time zone
);
CREATE TABLE "media" (
"id" serial PRIMARY KEY NOT NULL,
"alt" varchar NOT NULL,
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
"url" varchar,
"thumbnail_u_r_l" varchar,
"filename" varchar,
"mime_type" varchar,
"filesize" numeric,
"width" numeric,
"height" numeric,
"focal_x" numeric,
"focal_y" numeric
);
CREATE TABLE "projects" (
"id" serial PRIMARY KEY NOT NULL,
"name" varchar NOT NULL,
"description" varchar NOT NULL,
"short_description" varchar NOT NULL,
"icon" varchar,
"status" "enum_projects_status" DEFAULT 'draft' NOT NULL,
"featured" boolean DEFAULT false,
"autocheck_updated" boolean DEFAULT false,
"last_updated" timestamp(3) with time zone,
"wakatime_offset" numeric,
"banner_image_id" integer,
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
);
CREATE TABLE "projects_rels" (
"id" serial PRIMARY KEY NOT NULL,
"order" integer,
"parent_id" integer NOT NULL,
"path" varchar NOT NULL,
"technologies_id" integer
);
CREATE TABLE "technologies" (
"id" serial PRIMARY KEY NOT NULL,
"name" varchar NOT NULL,
"url" varchar,
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
);
CREATE TABLE "links" (
"id" serial PRIMARY KEY NOT NULL,
"url" varchar NOT NULL,
"icon" varchar,
"description" varchar,
"project_id" integer NOT NULL,
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
);
CREATE TABLE "payload_kv" (
"id" serial PRIMARY KEY NOT NULL,
"key" varchar NOT NULL,
"data" jsonb NOT NULL
);
CREATE TABLE "payload_locked_documents" (
"id" serial PRIMARY KEY NOT NULL,
"global_slug" varchar,
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
);
CREATE TABLE "payload_locked_documents_rels" (
"id" serial PRIMARY KEY NOT NULL,
"order" integer,
"parent_id" integer NOT NULL,
"path" varchar NOT NULL,
"users_id" integer,
"media_id" integer,
"projects_id" integer,
"technologies_id" integer,
"links_id" integer
);
CREATE TABLE "payload_preferences" (
"id" serial PRIMARY KEY NOT NULL,
"key" varchar,
"value" jsonb,
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
);
CREATE TABLE "payload_preferences_rels" (
"id" serial PRIMARY KEY NOT NULL,
"order" integer,
"parent_id" integer NOT NULL,
"path" varchar NOT NULL,
"users_id" integer
);
CREATE TABLE "payload_migrations" (
"id" serial PRIMARY KEY NOT NULL,
"name" varchar,
"batch" numeric,
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
);
CREATE TABLE "metadata" (
"id" serial PRIMARY KEY NOT NULL,
"tagline" varchar NOT NULL,
"resume_id" integer NOT NULL,
"resume_filename" varchar,
"updated_at" timestamp(3) with time zone,
"created_at" timestamp(3) with time zone
);
ALTER TABLE "users_sessions" ADD CONSTRAINT "users_sessions_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "projects" ADD CONSTRAINT "projects_banner_image_id_media_id_fk" FOREIGN KEY ("banner_image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "projects_rels" ADD CONSTRAINT "projects_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."projects"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "projects_rels" ADD CONSTRAINT "projects_rels_technologies_fk" FOREIGN KEY ("technologies_id") REFERENCES "public"."technologies"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "links" ADD CONSTRAINT "links_project_id_projects_id_fk" FOREIGN KEY ("project_id") REFERENCES "public"."projects"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."payload_locked_documents"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_users_fk" FOREIGN KEY ("users_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_media_fk" FOREIGN KEY ("media_id") REFERENCES "public"."media"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_projects_fk" FOREIGN KEY ("projects_id") REFERENCES "public"."projects"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_technologies_fk" FOREIGN KEY ("technologies_id") REFERENCES "public"."technologies"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_links_fk" FOREIGN KEY ("links_id") REFERENCES "public"."links"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."payload_preferences"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_users_fk" FOREIGN KEY ("users_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "metadata" ADD CONSTRAINT "metadata_resume_id_media_id_fk" FOREIGN KEY ("resume_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
CREATE INDEX "users_sessions_order_idx" ON "users_sessions" USING btree ("_order");
CREATE INDEX "users_sessions_parent_id_idx" ON "users_sessions" USING btree ("_parent_id");
CREATE INDEX "users_updated_at_idx" ON "users" USING btree ("updated_at");
CREATE INDEX "users_created_at_idx" ON "users" USING btree ("created_at");
CREATE UNIQUE INDEX "users_email_idx" ON "users" USING btree ("email");
CREATE INDEX "media_updated_at_idx" ON "media" USING btree ("updated_at");
CREATE INDEX "media_created_at_idx" ON "media" USING btree ("created_at");
CREATE UNIQUE INDEX "media_filename_idx" ON "media" USING btree ("filename");
CREATE INDEX "projects_banner_image_idx" ON "projects" USING btree ("banner_image_id");
CREATE INDEX "projects_updated_at_idx" ON "projects" USING btree ("updated_at");
CREATE INDEX "projects_created_at_idx" ON "projects" USING btree ("created_at");
CREATE INDEX "projects_rels_order_idx" ON "projects_rels" USING btree ("order");
CREATE INDEX "projects_rels_parent_idx" ON "projects_rels" USING btree ("parent_id");
CREATE INDEX "projects_rels_path_idx" ON "projects_rels" USING btree ("path");
CREATE INDEX "projects_rels_technologies_id_idx" ON "projects_rels" USING btree ("technologies_id");
CREATE INDEX "technologies_updated_at_idx" ON "technologies" USING btree ("updated_at");
CREATE INDEX "technologies_created_at_idx" ON "technologies" USING btree ("created_at");
CREATE INDEX "links_project_idx" ON "links" USING btree ("project_id");
CREATE INDEX "links_updated_at_idx" ON "links" USING btree ("updated_at");
CREATE INDEX "links_created_at_idx" ON "links" USING btree ("created_at");
CREATE UNIQUE INDEX "payload_kv_key_idx" ON "payload_kv" USING btree ("key");
CREATE INDEX "payload_locked_documents_global_slug_idx" ON "payload_locked_documents" USING btree ("global_slug");
CREATE INDEX "payload_locked_documents_updated_at_idx" ON "payload_locked_documents" USING btree ("updated_at");
CREATE INDEX "payload_locked_documents_created_at_idx" ON "payload_locked_documents" USING btree ("created_at");
CREATE INDEX "payload_locked_documents_rels_order_idx" ON "payload_locked_documents_rels" USING btree ("order");
CREATE INDEX "payload_locked_documents_rels_parent_idx" ON "payload_locked_documents_rels" USING btree ("parent_id");
CREATE INDEX "payload_locked_documents_rels_path_idx" ON "payload_locked_documents_rels" USING btree ("path");
CREATE INDEX "payload_locked_documents_rels_users_id_idx" ON "payload_locked_documents_rels" USING btree ("users_id");
CREATE INDEX "payload_locked_documents_rels_media_id_idx" ON "payload_locked_documents_rels" USING btree ("media_id");
CREATE INDEX "payload_locked_documents_rels_projects_id_idx" ON "payload_locked_documents_rels" USING btree ("projects_id");
CREATE INDEX "payload_locked_documents_rels_technologies_id_idx" ON "payload_locked_documents_rels" USING btree ("technologies_id");
CREATE INDEX "payload_locked_documents_rels_links_id_idx" ON "payload_locked_documents_rels" USING btree ("links_id");
CREATE INDEX "payload_preferences_key_idx" ON "payload_preferences" USING btree ("key");
CREATE INDEX "payload_preferences_updated_at_idx" ON "payload_preferences" USING btree ("updated_at");
CREATE INDEX "payload_preferences_created_at_idx" ON "payload_preferences" USING btree ("created_at");
CREATE INDEX "payload_preferences_rels_order_idx" ON "payload_preferences_rels" USING btree ("order");
CREATE INDEX "payload_preferences_rels_parent_idx" ON "payload_preferences_rels" USING btree ("parent_id");
CREATE INDEX "payload_preferences_rels_path_idx" ON "payload_preferences_rels" USING btree ("path");
CREATE INDEX "payload_preferences_rels_users_id_idx" ON "payload_preferences_rels" USING btree ("users_id");
CREATE INDEX "payload_migrations_updated_at_idx" ON "payload_migrations" USING btree ("updated_at");
CREATE INDEX "payload_migrations_created_at_idx" ON "payload_migrations" USING btree ("created_at");
CREATE INDEX "metadata_resume_idx" ON "metadata" USING btree ("resume_id");`)
}
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
await db.execute(sql`
DROP TABLE "users_sessions" CASCADE;
DROP TABLE "users" CASCADE;
DROP TABLE "media" CASCADE;
DROP TABLE "projects" CASCADE;
DROP TABLE "projects_rels" CASCADE;
DROP TABLE "technologies" CASCADE;
DROP TABLE "links" CASCADE;
DROP TABLE "payload_kv" CASCADE;
DROP TABLE "payload_locked_documents" CASCADE;
DROP TABLE "payload_locked_documents_rels" CASCADE;
DROP TABLE "payload_preferences" CASCADE;
DROP TABLE "payload_preferences_rels" CASCADE;
DROP TABLE "payload_migrations" CASCADE;
DROP TABLE "metadata" CASCADE;
DROP TYPE "public"."enum_projects_status";`)
}
-9
View File
@@ -1,9 +0,0 @@
import * as migration_20260104_100459 from './20260104_100459';
export const migrations = [
{
up: migration_20260104_100459.up,
down: migration_20260104_100459.down,
name: '20260104_100459'
},
];
@@ -1,630 +0,0 @@
/* tslint:disable */
/* eslint-disable */
/**
* This file was automatically generated by Payload.
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
* and re-run `payload generate:db-schema` to regenerate this file.
*/
import type {} from "@payloadcms/db-postgres";
import {
pgTable,
index,
uniqueIndex,
foreignKey,
integer,
varchar,
timestamp,
serial,
numeric,
boolean,
jsonb,
pgEnum,
} from "@payloadcms/db-postgres/drizzle/pg-core";
import { sql, relations } from "@payloadcms/db-postgres/drizzle";
export const enum_projects_status = pgEnum("enum_projects_status", [
"draft",
"published",
"archived",
]);
export const users_sessions = pgTable(
"users_sessions",
{
_order: integer("_order").notNull(),
_parentID: integer("_parent_id").notNull(),
id: varchar("id").primaryKey(),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
}),
expiresAt: timestamp("expires_at", {
mode: "string",
withTimezone: true,
precision: 3,
}).notNull(),
},
(columns) => [
index("users_sessions_order_idx").on(columns._order),
index("users_sessions_parent_id_idx").on(columns._parentID),
foreignKey({
columns: [columns["_parentID"]],
foreignColumns: [users.id],
name: "users_sessions_parent_id_fk",
}).onDelete("cascade"),
],
);
export const users = pgTable(
"users",
{
id: serial("id").primaryKey(),
updatedAt: timestamp("updated_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
email: varchar("email").notNull(),
resetPasswordToken: varchar("reset_password_token"),
resetPasswordExpiration: timestamp("reset_password_expiration", {
mode: "string",
withTimezone: true,
precision: 3,
}),
salt: varchar("salt"),
hash: varchar("hash"),
loginAttempts: numeric("login_attempts", { mode: "number" }).default(0),
lockUntil: timestamp("lock_until", {
mode: "string",
withTimezone: true,
precision: 3,
}),
},
(columns) => [
index("users_updated_at_idx").on(columns.updatedAt),
index("users_created_at_idx").on(columns.createdAt),
uniqueIndex("users_email_idx").on(columns.email),
],
);
export const media = pgTable(
"media",
{
id: serial("id").primaryKey(),
alt: varchar("alt").notNull(),
updatedAt: timestamp("updated_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
url: varchar("url"),
thumbnailURL: varchar("thumbnail_u_r_l"),
filename: varchar("filename"),
mimeType: varchar("mime_type"),
filesize: numeric("filesize", { mode: "number" }),
width: numeric("width", { mode: "number" }),
height: numeric("height", { mode: "number" }),
focalX: numeric("focal_x", { mode: "number" }),
focalY: numeric("focal_y", { mode: "number" }),
},
(columns) => [
index("media_updated_at_idx").on(columns.updatedAt),
index("media_created_at_idx").on(columns.createdAt),
uniqueIndex("media_filename_idx").on(columns.filename),
],
);
export const projects = pgTable(
"projects",
{
id: serial("id").primaryKey(),
name: varchar("name").notNull(),
description: varchar("description").notNull(),
shortDescription: varchar("short_description").notNull(),
icon: varchar("icon"),
status: enum_projects_status("status").notNull().default("draft"),
featured: boolean("featured").default(false),
autocheckUpdated: boolean("autocheck_updated").default(false),
lastUpdated: timestamp("last_updated", {
mode: "string",
withTimezone: true,
precision: 3,
}),
wakatimeOffset: numeric("wakatime_offset", { mode: "number" }),
bannerImage: integer("banner_image_id").references(() => media.id, {
onDelete: "set null",
}),
updatedAt: timestamp("updated_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
},
(columns) => [
index("projects_banner_image_idx").on(columns.bannerImage),
index("projects_updated_at_idx").on(columns.updatedAt),
index("projects_created_at_idx").on(columns.createdAt),
],
);
export const projects_rels = pgTable(
"projects_rels",
{
id: serial("id").primaryKey(),
order: integer("order"),
parent: integer("parent_id").notNull(),
path: varchar("path").notNull(),
technologiesID: integer("technologies_id"),
},
(columns) => [
index("projects_rels_order_idx").on(columns.order),
index("projects_rels_parent_idx").on(columns.parent),
index("projects_rels_path_idx").on(columns.path),
index("projects_rels_technologies_id_idx").on(columns.technologiesID),
foreignKey({
columns: [columns["parent"]],
foreignColumns: [projects.id],
name: "projects_rels_parent_fk",
}).onDelete("cascade"),
foreignKey({
columns: [columns["technologiesID"]],
foreignColumns: [technologies.id],
name: "projects_rels_technologies_fk",
}).onDelete("cascade"),
],
);
export const technologies = pgTable(
"technologies",
{
id: serial("id").primaryKey(),
name: varchar("name").notNull(),
url: varchar("url"),
updatedAt: timestamp("updated_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
},
(columns) => [
index("technologies_updated_at_idx").on(columns.updatedAt),
index("technologies_created_at_idx").on(columns.createdAt),
],
);
export const links = pgTable(
"links",
{
id: serial("id").primaryKey(),
url: varchar("url").notNull(),
icon: varchar("icon"),
description: varchar("description"),
project: integer("project_id")
.notNull()
.references(() => projects.id, {
onDelete: "set null",
}),
updatedAt: timestamp("updated_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
},
(columns) => [
index("links_project_idx").on(columns.project),
index("links_updated_at_idx").on(columns.updatedAt),
index("links_created_at_idx").on(columns.createdAt),
],
);
export const payload_kv = pgTable(
"payload_kv",
{
id: serial("id").primaryKey(),
key: varchar("key").notNull(),
data: jsonb("data").notNull(),
},
(columns) => [uniqueIndex("payload_kv_key_idx").on(columns.key)],
);
export const payload_locked_documents = pgTable(
"payload_locked_documents",
{
id: serial("id").primaryKey(),
globalSlug: varchar("global_slug"),
updatedAt: timestamp("updated_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
},
(columns) => [
index("payload_locked_documents_global_slug_idx").on(columns.globalSlug),
index("payload_locked_documents_updated_at_idx").on(columns.updatedAt),
index("payload_locked_documents_created_at_idx").on(columns.createdAt),
],
);
export const payload_locked_documents_rels = pgTable(
"payload_locked_documents_rels",
{
id: serial("id").primaryKey(),
order: integer("order"),
parent: integer("parent_id").notNull(),
path: varchar("path").notNull(),
usersID: integer("users_id"),
mediaID: integer("media_id"),
projectsID: integer("projects_id"),
technologiesID: integer("technologies_id"),
linksID: integer("links_id"),
},
(columns) => [
index("payload_locked_documents_rels_order_idx").on(columns.order),
index("payload_locked_documents_rels_parent_idx").on(columns.parent),
index("payload_locked_documents_rels_path_idx").on(columns.path),
index("payload_locked_documents_rels_users_id_idx").on(columns.usersID),
index("payload_locked_documents_rels_media_id_idx").on(columns.mediaID),
index("payload_locked_documents_rels_projects_id_idx").on(
columns.projectsID,
),
index("payload_locked_documents_rels_technologies_id_idx").on(
columns.technologiesID,
),
index("payload_locked_documents_rels_links_id_idx").on(columns.linksID),
foreignKey({
columns: [columns["parent"]],
foreignColumns: [payload_locked_documents.id],
name: "payload_locked_documents_rels_parent_fk",
}).onDelete("cascade"),
foreignKey({
columns: [columns["usersID"]],
foreignColumns: [users.id],
name: "payload_locked_documents_rels_users_fk",
}).onDelete("cascade"),
foreignKey({
columns: [columns["mediaID"]],
foreignColumns: [media.id],
name: "payload_locked_documents_rels_media_fk",
}).onDelete("cascade"),
foreignKey({
columns: [columns["projectsID"]],
foreignColumns: [projects.id],
name: "payload_locked_documents_rels_projects_fk",
}).onDelete("cascade"),
foreignKey({
columns: [columns["technologiesID"]],
foreignColumns: [technologies.id],
name: "payload_locked_documents_rels_technologies_fk",
}).onDelete("cascade"),
foreignKey({
columns: [columns["linksID"]],
foreignColumns: [links.id],
name: "payload_locked_documents_rels_links_fk",
}).onDelete("cascade"),
],
);
export const payload_preferences = pgTable(
"payload_preferences",
{
id: serial("id").primaryKey(),
key: varchar("key"),
value: jsonb("value"),
updatedAt: timestamp("updated_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
},
(columns) => [
index("payload_preferences_key_idx").on(columns.key),
index("payload_preferences_updated_at_idx").on(columns.updatedAt),
index("payload_preferences_created_at_idx").on(columns.createdAt),
],
);
export const payload_preferences_rels = pgTable(
"payload_preferences_rels",
{
id: serial("id").primaryKey(),
order: integer("order"),
parent: integer("parent_id").notNull(),
path: varchar("path").notNull(),
usersID: integer("users_id"),
},
(columns) => [
index("payload_preferences_rels_order_idx").on(columns.order),
index("payload_preferences_rels_parent_idx").on(columns.parent),
index("payload_preferences_rels_path_idx").on(columns.path),
index("payload_preferences_rels_users_id_idx").on(columns.usersID),
foreignKey({
columns: [columns["parent"]],
foreignColumns: [payload_preferences.id],
name: "payload_preferences_rels_parent_fk",
}).onDelete("cascade"),
foreignKey({
columns: [columns["usersID"]],
foreignColumns: [users.id],
name: "payload_preferences_rels_users_fk",
}).onDelete("cascade"),
],
);
export const payload_migrations = pgTable(
"payload_migrations",
{
id: serial("id").primaryKey(),
name: varchar("name"),
batch: numeric("batch", { mode: "number" }),
updatedAt: timestamp("updated_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
},
(columns) => [
index("payload_migrations_updated_at_idx").on(columns.updatedAt),
index("payload_migrations_created_at_idx").on(columns.createdAt),
],
);
export const metadata = pgTable(
"metadata",
{
id: serial("id").primaryKey(),
tagline: varchar("tagline").notNull(),
resume: integer("resume_id")
.notNull()
.references(() => media.id, {
onDelete: "set null",
}),
resumeFilename: varchar("resume_filename"),
updatedAt: timestamp("updated_at", {
mode: "string",
withTimezone: true,
precision: 3,
}),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
}),
},
(columns) => [index("metadata_resume_idx").on(columns.resume)],
);
export const relations_users_sessions = relations(
users_sessions,
({ one }) => ({
_parentID: one(users, {
fields: [users_sessions._parentID],
references: [users.id],
relationName: "sessions",
}),
}),
);
export const relations_users = relations(users, ({ many }) => ({
sessions: many(users_sessions, {
relationName: "sessions",
}),
}));
export const relations_media = relations(media, () => ({}));
export const relations_projects_rels = relations(projects_rels, ({ one }) => ({
parent: one(projects, {
fields: [projects_rels.parent],
references: [projects.id],
relationName: "_rels",
}),
technologiesID: one(technologies, {
fields: [projects_rels.technologiesID],
references: [technologies.id],
relationName: "technologies",
}),
}));
export const relations_projects = relations(projects, ({ one, many }) => ({
bannerImage: one(media, {
fields: [projects.bannerImage],
references: [media.id],
relationName: "bannerImage",
}),
_rels: many(projects_rels, {
relationName: "_rels",
}),
}));
export const relations_technologies = relations(technologies, () => ({}));
export const relations_links = relations(links, ({ one }) => ({
project: one(projects, {
fields: [links.project],
references: [projects.id],
relationName: "project",
}),
}));
export const relations_payload_kv = relations(payload_kv, () => ({}));
export const relations_payload_locked_documents_rels = relations(
payload_locked_documents_rels,
({ one }) => ({
parent: one(payload_locked_documents, {
fields: [payload_locked_documents_rels.parent],
references: [payload_locked_documents.id],
relationName: "_rels",
}),
usersID: one(users, {
fields: [payload_locked_documents_rels.usersID],
references: [users.id],
relationName: "users",
}),
mediaID: one(media, {
fields: [payload_locked_documents_rels.mediaID],
references: [media.id],
relationName: "media",
}),
projectsID: one(projects, {
fields: [payload_locked_documents_rels.projectsID],
references: [projects.id],
relationName: "projects",
}),
technologiesID: one(technologies, {
fields: [payload_locked_documents_rels.technologiesID],
references: [technologies.id],
relationName: "technologies",
}),
linksID: one(links, {
fields: [payload_locked_documents_rels.linksID],
references: [links.id],
relationName: "links",
}),
}),
);
export const relations_payload_locked_documents = relations(
payload_locked_documents,
({ many }) => ({
_rels: many(payload_locked_documents_rels, {
relationName: "_rels",
}),
}),
);
export const relations_payload_preferences_rels = relations(
payload_preferences_rels,
({ one }) => ({
parent: one(payload_preferences, {
fields: [payload_preferences_rels.parent],
references: [payload_preferences.id],
relationName: "_rels",
}),
usersID: one(users, {
fields: [payload_preferences_rels.usersID],
references: [users.id],
relationName: "users",
}),
}),
);
export const relations_payload_preferences = relations(
payload_preferences,
({ many }) => ({
_rels: many(payload_preferences_rels, {
relationName: "_rels",
}),
}),
);
export const relations_payload_migrations = relations(
payload_migrations,
() => ({}),
);
export const relations_metadata = relations(metadata, ({ one }) => ({
resume: one(media, {
fields: [metadata.resume],
references: [media.id],
relationName: "resume",
}),
}));
type DatabaseSchema = {
enum_projects_status: typeof enum_projects_status;
users_sessions: typeof users_sessions;
users: typeof users;
media: typeof media;
projects: typeof projects;
projects_rels: typeof projects_rels;
technologies: typeof technologies;
links: typeof links;
payload_kv: typeof payload_kv;
payload_locked_documents: typeof payload_locked_documents;
payload_locked_documents_rels: typeof payload_locked_documents_rels;
payload_preferences: typeof payload_preferences;
payload_preferences_rels: typeof payload_preferences_rels;
payload_migrations: typeof payload_migrations;
metadata: typeof metadata;
relations_users_sessions: typeof relations_users_sessions;
relations_users: typeof relations_users;
relations_media: typeof relations_media;
relations_projects_rels: typeof relations_projects_rels;
relations_projects: typeof relations_projects;
relations_technologies: typeof relations_technologies;
relations_links: typeof relations_links;
relations_payload_kv: typeof relations_payload_kv;
relations_payload_locked_documents_rels: typeof relations_payload_locked_documents_rels;
relations_payload_locked_documents: typeof relations_payload_locked_documents;
relations_payload_preferences_rels: typeof relations_payload_preferences_rels;
relations_payload_preferences: typeof relations_payload_preferences;
relations_payload_migrations: typeof relations_payload_migrations;
relations_metadata: typeof relations_metadata;
};
declare module "@payloadcms/db-postgres" {
export interface GeneratedDatabaseSchema {
schema: DatabaseSchema;
}
}
-470
View File
@@ -1,470 +0,0 @@
/* tslint:disable */
/* eslint-disable */
/**
* This file was automatically generated by Payload.
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
* and re-run `payload generate:types` to regenerate this file.
*/
/**
* Supported timezones in IANA format.
*
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "supportedTimezones".
*/
export type SupportedTimezones =
| 'Pacific/Midway'
| 'Pacific/Niue'
| 'Pacific/Honolulu'
| 'Pacific/Rarotonga'
| 'America/Anchorage'
| 'Pacific/Gambier'
| 'America/Los_Angeles'
| 'America/Tijuana'
| 'America/Denver'
| 'America/Phoenix'
| 'America/Chicago'
| 'America/Guatemala'
| 'America/New_York'
| 'America/Bogota'
| 'America/Caracas'
| 'America/Santiago'
| 'America/Buenos_Aires'
| 'America/Sao_Paulo'
| 'Atlantic/South_Georgia'
| 'Atlantic/Azores'
| 'Atlantic/Cape_Verde'
| 'Europe/London'
| 'Europe/Berlin'
| 'Africa/Lagos'
| 'Europe/Athens'
| 'Africa/Cairo'
| 'Europe/Moscow'
| 'Asia/Riyadh'
| 'Asia/Dubai'
| 'Asia/Baku'
| 'Asia/Karachi'
| 'Asia/Tashkent'
| 'Asia/Calcutta'
| 'Asia/Dhaka'
| 'Asia/Almaty'
| 'Asia/Jakarta'
| 'Asia/Bangkok'
| 'Asia/Shanghai'
| 'Asia/Singapore'
| 'Asia/Tokyo'
| 'Asia/Seoul'
| 'Australia/Brisbane'
| 'Australia/Sydney'
| 'Pacific/Guam'
| 'Pacific/Noumea'
| 'Pacific/Auckland'
| 'Pacific/Fiji';
export interface Config {
auth: {
users: UserAuthOperations;
};
blocks: {};
collections: {
users: User;
media: Media;
projects: Project;
technologies: Technology;
links: Link;
'payload-kv': PayloadKv;
'payload-locked-documents': PayloadLockedDocument;
'payload-preferences': PayloadPreference;
'payload-migrations': PayloadMigration;
};
collectionsJoins: {};
collectionsSelect: {
users: UsersSelect<false> | UsersSelect<true>;
media: MediaSelect<false> | MediaSelect<true>;
projects: ProjectsSelect<false> | ProjectsSelect<true>;
technologies: TechnologiesSelect<false> | TechnologiesSelect<true>;
links: LinksSelect<false> | LinksSelect<true>;
'payload-kv': PayloadKvSelect<false> | PayloadKvSelect<true>;
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
};
db: {
defaultIDType: number;
};
fallbackLocale: null;
globals: {
metadata: Metadatum;
};
globalsSelect: {
metadata: MetadataSelect<false> | MetadataSelect<true>;
};
locale: null;
user: User & {
collection: 'users';
};
jobs: {
tasks: unknown;
workflows: unknown;
};
}
export interface UserAuthOperations {
forgotPassword: {
email: string;
password: string;
};
login: {
email: string;
password: string;
};
registerFirstUser: {
email: string;
password: string;
};
unlock: {
email: string;
password: string;
};
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users".
*/
export interface User {
id: number;
updatedAt: string;
createdAt: string;
email: string;
resetPasswordToken?: string | null;
resetPasswordExpiration?: string | null;
salt?: string | null;
hash?: string | null;
loginAttempts?: number | null;
lockUntil?: string | null;
sessions?:
| {
id: string;
createdAt?: string | null;
expiresAt: string;
}[]
| null;
password?: string | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "media".
*/
export interface Media {
id: number;
alt: string;
updatedAt: string;
createdAt: string;
url?: string | null;
thumbnailURL?: string | null;
filename?: string | null;
mimeType?: string | null;
filesize?: number | null;
width?: number | null;
height?: number | null;
focalX?: number | null;
focalY?: number | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "projects".
*/
export interface Project {
id: number;
name: string;
description: string;
shortDescription: string;
icon?: string | null;
status: 'draft' | 'published' | 'archived';
featured?: boolean | null;
/**
* Automatically check GitHub for latest commits and update lastUpdated field
*/
autocheckUpdated?: boolean | null;
/**
* Automatically updated by cron job based on GitHub commits
*/
lastUpdated?: string | null;
/**
* Offset for WakaTime fetched data (optional)
*/
wakatimeOffset?: number | null;
bannerImage?: (number | null) | Media;
technologies?: (number | Technology)[] | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "technologies".
*/
export interface Technology {
id: number;
name: string;
url?: string | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "links".
*/
export interface Link {
id: number;
url: string;
icon?: string | null;
description?: string | null;
project: number | Project;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-kv".
*/
export interface PayloadKv {
id: number;
key: string;
data:
| {
[k: string]: unknown;
}
| unknown[]
| string
| number
| boolean
| null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents".
*/
export interface PayloadLockedDocument {
id: number;
document?:
| ({
relationTo: 'users';
value: number | User;
} | null)
| ({
relationTo: 'media';
value: number | Media;
} | null)
| ({
relationTo: 'projects';
value: number | Project;
} | null)
| ({
relationTo: 'technologies';
value: number | Technology;
} | null)
| ({
relationTo: 'links';
value: number | Link;
} | null);
globalSlug?: string | null;
user: {
relationTo: 'users';
value: number | User;
};
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-preferences".
*/
export interface PayloadPreference {
id: number;
user: {
relationTo: 'users';
value: number | User;
};
key?: string | null;
value?:
| {
[k: string]: unknown;
}
| unknown[]
| string
| number
| boolean
| null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-migrations".
*/
export interface PayloadMigration {
id: number;
name?: string | null;
batch?: number | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users_select".
*/
export interface UsersSelect<T extends boolean = true> {
updatedAt?: T;
createdAt?: T;
email?: T;
resetPasswordToken?: T;
resetPasswordExpiration?: T;
salt?: T;
hash?: T;
loginAttempts?: T;
lockUntil?: T;
sessions?:
| T
| {
id?: T;
createdAt?: T;
expiresAt?: T;
};
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "media_select".
*/
export interface MediaSelect<T extends boolean = true> {
alt?: T;
updatedAt?: T;
createdAt?: T;
url?: T;
thumbnailURL?: T;
filename?: T;
mimeType?: T;
filesize?: T;
width?: T;
height?: T;
focalX?: T;
focalY?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "projects_select".
*/
export interface ProjectsSelect<T extends boolean = true> {
name?: T;
description?: T;
shortDescription?: T;
icon?: T;
status?: T;
featured?: T;
autocheckUpdated?: T;
lastUpdated?: T;
wakatimeOffset?: T;
bannerImage?: T;
technologies?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "technologies_select".
*/
export interface TechnologiesSelect<T extends boolean = true> {
name?: T;
url?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "links_select".
*/
export interface LinksSelect<T extends boolean = true> {
url?: T;
icon?: T;
description?: T;
project?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-kv_select".
*/
export interface PayloadKvSelect<T extends boolean = true> {
key?: T;
data?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents_select".
*/
export interface PayloadLockedDocumentsSelect<T extends boolean = true> {
document?: T;
globalSlug?: T;
user?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-preferences_select".
*/
export interface PayloadPreferencesSelect<T extends boolean = true> {
user?: T;
key?: T;
value?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-migrations_select".
*/
export interface PayloadMigrationsSelect<T extends boolean = true> {
name?: T;
batch?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "metadata".
*/
export interface Metadatum {
id: number;
tagline: string;
resume: number | Media;
/**
* Optional: Override the filename for the resume (e.g., "resume.pdf")
*/
resumeFilename?: string | null;
updatedAt?: string | null;
createdAt?: string | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "metadata_select".
*/
export interface MetadataSelect<T extends boolean = true> {
tagline?: T;
resume?: T;
resumeFilename?: T;
updatedAt?: T;
createdAt?: T;
globalType?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "auth".
*/
export interface Auth {
[k: string]: unknown;
}
declare module 'payload' {
export interface GeneratedTypes extends Config {}
}
-61
View File
@@ -1,61 +0,0 @@
import { postgresAdapter } from "@payloadcms/db-postgres";
import { lexicalEditor } from "@payloadcms/richtext-lexical";
import path from "path";
import { buildConfig } from "payload";
import { fileURLToPath } from "url";
import { s3Storage } from "@payloadcms/storage-s3";
import { migrations } from "./migrations";
import { Users } from "./collections/Users";
import { Media } from "./collections/Media";
import { Projects } from "./collections/Projects";
import { Technologies } from "./collections/Technologies";
import { Links } from "./collections/Links";
import { Metadata } from "./globals/Metadata";
const filename = fileURLToPath(import.meta.url);
const dirname = path.dirname(filename);
export default buildConfig({
admin: {
user: Users.slug,
importMap: {
baseDir: path.resolve(dirname),
},
},
routes: {
admin: "/",
},
collections: [Users, Media, Projects, Technologies, Links],
globals: [Metadata],
editor: lexicalEditor(),
secret: process.env.PAYLOAD_SECRET || "",
typescript: {
outputFile: path.resolve(dirname, "payload-types.ts"),
},
db: postgresAdapter({
prodMigrations: migrations,
pool: {
connectionString: process.env.DATABASE_URL,
},
}),
graphQL: {
disablePlaygroundInProduction: true,
},
plugins: [
s3Storage({
collections: {
media: true,
},
bucket: process.env.R2_BUCKET_NAME!,
config: {
endpoint: process.env.R2_ENDPOINT,
region: "auto",
credentials: {
accessKeyId: process.env.R2_ACCESS_KEY_ID!,
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,
},
},
}),
],
});
@@ -1,20 +0,0 @@
import { test, expect, Page } from '@playwright/test'
test.describe('Frontend', () => {
let page: Page
test.beforeAll(async ({ browser }, testInfo) => {
const context = await browser.newContext()
page = await context.newPage()
})
test('can go on homepage', async ({ page }) => {
await page.goto('http://localhost:3000')
await expect(page).toHaveTitle(/Payload Blank Template/)
const headging = page.locator('h1').first()
await expect(headging).toHaveText('Welcome to your new project.')
})
})
-20
View File
@@ -1,20 +0,0 @@
import { getPayload, Payload } from 'payload'
import config from '@/payload.config'
import { describe, it, beforeAll, expect } from 'vitest'
let payload: Payload
describe('API', () => {
beforeAll(async () => {
const payloadConfig = await config
payload = await getPayload({ config: payloadConfig })
})
it('fetches users', async () => {
const users = await payload.find({
collection: 'users',
})
expect(users).toBeDefined()
})
})
-45
View File
@@ -1,45 +0,0 @@
{
"compilerOptions": {
"baseUrl": ".",
"lib": [
"DOM",
"DOM.Iterable",
"ES2022"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"strictNullChecks": false,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": [
"./src/*"
],
"@payload-config": [
"./src/payload.config.ts"
]
},
"target": "ES2022",
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
"exclude": [
"node_modules"
],
}
-12
View File
@@ -1,12 +0,0 @@
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
import tsconfigPaths from 'vite-tsconfig-paths'
export default defineConfig({
plugins: [tsconfigPaths(), react()],
test: {
environment: 'jsdom',
setupFiles: ['./vitest.setup.ts'],
include: ['tests/int/**/*.int.spec.ts'],
},
})
-4
View File
@@ -1,4 +0,0 @@
// Any setup scripts you might need go here
// Load .env files
import 'dotenv/config'
-1
View File
@@ -1 +0,0 @@
engine-strict=true
-11
View File
@@ -1,11 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>
-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="107" height="128" viewBox="0 0 107 128"><title>svelte-logo</title><path d="M94.157 22.819c-10.4-14.885-30.94-19.297-45.792-9.835L22.282 29.608A29.92 29.92 0 0 0 8.764 49.65a31.5 31.5 0 0 0 3.108 20.231 30 30 0 0 0-4.477 11.183 31.9 31.9 0 0 0 5.448 24.116c10.402 14.887 30.942 19.297 45.791 9.835l26.083-16.624A29.92 29.92 0 0 0 98.235 78.35a31.53 31.53 0 0 0-3.105-20.232 30 30 0 0 0 4.474-11.182 31.88 31.88 0 0 0-5.447-24.116" style="fill:#ff3e00"/><path d="M45.817 106.582a20.72 20.72 0 0 1-22.237-8.243 19.17 19.17 0 0 1-3.277-14.503 18 18 0 0 1 .624-2.435l.49-1.498 1.337.981a33.6 33.6 0 0 0 10.203 5.098l.97.294-.09.968a5.85 5.85 0 0 0 1.052 3.878 6.24 6.24 0 0 0 6.695 2.485 5.8 5.8 0 0 0 1.603-.704L69.27 76.28a5.43 5.43 0 0 0 2.45-3.631 5.8 5.8 0 0 0-.987-4.371 6.24 6.24 0 0 0-6.698-2.487 5.7 5.7 0 0 0-1.6.704l-9.953 6.345a19 19 0 0 1-5.296 2.326 20.72 20.72 0 0 1-22.237-8.243 19.17 19.17 0 0 1-3.277-14.502 17.99 17.99 0 0 1 8.13-12.052l26.081-16.623a19 19 0 0 1 5.3-2.329 20.72 20.72 0 0 1 22.237 8.243 19.17 19.17 0 0 1 3.277 14.503 18 18 0 0 1-.624 2.435l-.49 1.498-1.337-.98a33.6 33.6 0 0 0-10.203-5.1l-.97-.294.09-.968a5.86 5.86 0 0 0-1.052-3.878 6.24 6.24 0 0 0-6.696-2.485 5.8 5.8 0 0 0-1.602.704L37.73 51.72a5.42 5.42 0 0 0-2.449 3.63 5.79 5.79 0 0 0 .986 4.372 6.24 6.24 0 0 0 6.698 2.486 5.8 5.8 0 0 0 1.602-.704l9.952-6.342a19 19 0 0 1 5.295-2.328 20.72 20.72 0 0 1 22.237 8.242 19.17 19.17 0 0 1 3.277 14.503 18 18 0 0 1-8.13 12.053l-26.081 16.622a19 19 0 0 1-5.3 2.328" style="fill:#fff"/></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

-360
View File
@@ -1,360 +0,0 @@
<script lang="ts">
import { cn } from "$lib/utils";
import type { ClassValue } from "clsx";
import { onMount, onDestroy } from "svelte";
let { class: className = "" }: { class?: ClassValue } = $props();
let canvas: HTMLCanvasElement;
let gl: WebGLRenderingContext | null = null;
let animationId: number | null = null;
// Noise sampling scale - larger values create smoother, more gradual flow patterns
const SCALE = 1000;
// Maximum displacement distance from grid position (in pixels)
const LENGTH = 10;
// Distance between grid points (in pixels) - controls dot density
const SPACING = 20;
// Global animation speed multiplier - higher values make everything move faster
const TIMESCALE = 10.25 / 1000;
// Rotation/angle animation speed multiplier
const ANGLE_TIME_SCALE = 2.0;
// Pulsing/length animation speed multiplier
const LENGTH_TIME_SCALE = 1.5;
// Base opacity of dots (0-1)
const OPACITY = 0.9;
// Radius of each dot (in pixels)
const RADIUS = 3.5;
// How much opacity varies with angle (0-1)
const ANGLE_OPACITY_AMPLITUDE = 0.8;
// Minimum opacity from angle calculation
const ANGLE_OPACITY_FLOOR = 0.1;
// Lower bound of random per-dot opacity
const RANDOM_OPACITY_MIN = 0.5;
// Upper bound of random per-dot opacity
const RANDOM_OPACITY_MAX = 1.0;
// Simplex noise GLSL implementation
const vertexShader = `
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0.0, 1.0);
}
`;
const fragmentShader = `
precision mediump float;
uniform vec2 u_resolution;
uniform float u_time;
uniform float u_seed;
uniform float u_dpr;
uniform float u_scale;
uniform float u_length;
uniform float u_spacing;
uniform float u_opacity;
uniform float u_radius;
uniform float u_angleTimeScale;
uniform float u_lengthTimeScale;
uniform float u_angleOpacityAmp;
uniform float u_angleOpacityFloor;
uniform float u_randomOpacityMin;
uniform float u_randomOpacityMax;
const float PI = 3.14159265359;
// Simplex 3D noise
vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec4 permute(vec4 x) { return mod289(((x*34.0)+1.0)*x); }
vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }
float snoise(vec3 v) {
const vec2 C = vec2(1.0/6.0, 1.0/3.0);
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
vec3 i = floor(v + dot(v, C.yyy));
vec3 x0 = v - i + dot(i, C.xxx);
vec3 g = step(x0.yzx, x0.xyz);
vec3 l = 1.0 - g;
vec3 i1 = min(g.xyz, l.zxy);
vec3 i2 = max(g.xyz, l.zxy);
vec3 x1 = x0 - i1 + C.xxx;
vec3 x2 = x0 - i2 + C.yyy;
vec3 x3 = x0 - D.yyy;
i = mod289(i + u_seed);
vec4 p = permute(permute(permute(
i.z + vec4(0.0, i1.z, i2.z, 1.0))
+ i.y + vec4(0.0, i1.y, i2.y, 1.0))
+ i.x + vec4(0.0, i1.x, i2.x, 1.0));
float n_ = 0.142857142857;
vec3 ns = n_ * D.wyz - D.xzx;
vec4 j = p - 49.0 * floor(p * ns.z * ns.z);
vec4 x_ = floor(j * ns.z);
vec4 y_ = floor(j - 7.0 * x_);
vec4 x = x_ *ns.x + ns.yyyy;
vec4 y = y_ *ns.x + ns.yyyy;
vec4 h = 1.0 - abs(x) - abs(y);
vec4 b0 = vec4(x.xy, y.xy);
vec4 b1 = vec4(x.zw, y.zw);
vec4 s0 = floor(b0)*2.0 + 1.0;
vec4 s1 = floor(b1)*2.0 + 1.0;
vec4 sh = -step(h, vec4(0.0));
vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy;
vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww;
vec3 p0 = vec3(a0.xy, h.x);
vec3 p1 = vec3(a0.zw, h.y);
vec3 p2 = vec3(a1.xy, h.z);
vec3 p3 = vec3(a1.zw, h.w);
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2,p2), dot(p3,p3)));
p0 *= norm.x;
p1 *= norm.y;
p2 *= norm.z;
p3 *= norm.w;
vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
m = m * m;
return 42.0 * dot(m*m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3)));
}
// Hash function for random per-point opacity
float hash(vec2 p) {
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
}
// Convert snoise [-1,1] to p5-style noise [0,1]
float noise01(vec3 v) {
return (snoise(v) + 1.0) * 0.5;
}
void main() {
vec2 pixelCoord = gl_FragCoord.xy;
// Find nearest grid point (account for DPR)
float spacing = u_spacing * u_dpr;
float scaleDpr = u_scale * u_dpr;
vec2 gridCoord = floor(pixelCoord / spacing) * spacing;
// Calculate distance to all nearby grid points (9 neighbors)
float minDist = 1000000.0;
vec2 closestPoint = vec2(0.0);
float pointOpacity = 0.0;
for (float dx = -1.0; dx <= 1.0; dx += 1.0) {
for (float dy = -1.0; dy <= 1.0; dy += 1.0) {
vec2 testGrid = gridCoord + vec2(dx * spacing, dy * spacing);
// Get force direction at this grid point (matching original p5 formula)
// Original: (noise(x/SCALE, y/SCALE, z) - 0.5) * 2 * TWO_PI
float rad = (noise01(vec3(testGrid / scaleDpr, u_time * u_angleTimeScale)) - 0.5) * 4.0 * PI;
// Original: (noise(x/SCALE, y/SCALE, z*2) + 0.5) * LENGTH
float len = (noise01(vec3(testGrid / scaleDpr, u_time * u_lengthTimeScale)) + 0.5) * u_length * u_dpr;
// Calculate displaced position
vec2 displacedPoint = testGrid + vec2(cos(rad), sin(rad)) * len;
float dist = distance(pixelCoord, displacedPoint);
if (dist < minDist) {
minDist = dist;
closestPoint = testGrid;
pointOpacity = hash(testGrid) * (u_randomOpacityMax - u_randomOpacityMin) + u_randomOpacityMin;
}
}
}
// Recalculate angle for opacity calculation
float rad = (noise01(vec3(closestPoint / scaleDpr, u_time * u_angleTimeScale)) - 0.5) * 4.0 * PI;
// Draw circle with configurable radius
float circle = 1.0 - smoothstep(0.0, u_radius * u_dpr, minDist);
// Calculate opacity based on angle
float angleOpacity = (abs(cos(rad)) * u_angleOpacityAmp + u_angleOpacityFloor) * pointOpacity * u_opacity;
// Light gray dots with calculated opacity
gl_FragColor = vec4(vec3(200.0/255.0), circle * angleOpacity);
}
`;
function createShader(gl: WebGLRenderingContext, type: number, source: string): WebGLShader | null {
const shader = gl.createShader(type);
if (!shader) return null;
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error('Shader compile error:', gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
function createProgram(gl: WebGLRenderingContext, vertexShader: WebGLShader, fragmentShader: WebGLShader): WebGLProgram | null {
const program = gl.createProgram();
if (!program) return null;
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error('Program link error:', gl.getProgramInfoLog(program));
gl.deleteProgram(program);
return null;
}
return program;
}
function resizeCanvas() {
if (!canvas) return;
const dpr = window.devicePixelRatio || 1;
canvas.width = window.innerWidth * dpr;
canvas.height = window.innerHeight * dpr;
canvas.style.width = `${window.innerWidth}px`;
canvas.style.height = `${window.innerHeight}px`;
if (gl) {
gl.viewport(0, 0, canvas.width, canvas.height);
}
}
onMount(() => {
gl = canvas.getContext('webgl', { alpha: true, premultipliedAlpha: false });
if (!gl) {
console.error('WebGL not supported');
return;
}
console.log('WebGL context created');
const vShader = createShader(gl, gl.VERTEX_SHADER, vertexShader);
const fShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShader);
if (!vShader || !fShader) {
console.error('Shader creation failed');
return;
}
console.log('Shaders compiled successfully');
const program = createProgram(gl, vShader, fShader);
if (!program) return;
// Set up geometry (full screen quad)
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
-1, -1,
1, -1,
-1, 1,
-1, 1,
1, -1,
1, 1,
]), gl.STATIC_DRAW);
const positionLocation = gl.getAttribLocation(program, 'a_position');
const resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
const timeLocation = gl.getUniformLocation(program, 'u_time');
const seedLocation = gl.getUniformLocation(program, 'u_seed');
const dprLocation = gl.getUniformLocation(program, 'u_dpr');
const scaleLocation = gl.getUniformLocation(program, 'u_scale');
const lengthLocation = gl.getUniformLocation(program, 'u_length');
const spacingLocation = gl.getUniformLocation(program, 'u_spacing');
const opacityLocation = gl.getUniformLocation(program, 'u_opacity');
const radiusLocation = gl.getUniformLocation(program, 'u_radius');
const angleTimeScaleLocation = gl.getUniformLocation(program, 'u_angleTimeScale');
const lengthTimeScaleLocation = gl.getUniformLocation(program, 'u_lengthTimeScale');
const angleOpacityAmpLocation = gl.getUniformLocation(program, 'u_angleOpacityAmp');
const angleOpacityFloorLocation = gl.getUniformLocation(program, 'u_angleOpacityFloor');
const randomOpacityMinLocation = gl.getUniformLocation(program, 'u_randomOpacityMin');
const randomOpacityMaxLocation = gl.getUniformLocation(program, 'u_randomOpacityMax');
gl.useProgram(program);
gl.enableVertexAttribArray(positionLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
// Enable blending for transparency
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
const dpr = window.devicePixelRatio || 1;
// Set static uniforms (these don't change per frame)
gl.uniform1f(seedLocation, Math.random() * 1000);
gl.uniform1f(dprLocation, dpr);
gl.uniform1f(scaleLocation, SCALE);
gl.uniform1f(lengthLocation, LENGTH);
gl.uniform1f(spacingLocation, SPACING);
gl.uniform1f(opacityLocation, OPACITY);
gl.uniform1f(radiusLocation, RADIUS);
gl.uniform1f(angleTimeScaleLocation, ANGLE_TIME_SCALE);
gl.uniform1f(lengthTimeScaleLocation, LENGTH_TIME_SCALE);
gl.uniform1f(angleOpacityAmpLocation, ANGLE_OPACITY_AMPLITUDE);
gl.uniform1f(angleOpacityFloorLocation, ANGLE_OPACITY_FLOOR);
gl.uniform1f(randomOpacityMinLocation, RANDOM_OPACITY_MIN);
gl.uniform1f(randomOpacityMaxLocation, RANDOM_OPACITY_MAX);
resizeCanvas();
let startTime = Date.now();
function render() {
if (!gl || !canvas) return;
const time = (Date.now() - startTime) / 1000 * TIMESCALE;
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
gl.uniform1f(timeLocation, time);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 6);
animationId = requestAnimationFrame(render);
}
render();
window.addEventListener('resize', resizeCanvas);
return () => {
window.removeEventListener('resize', resizeCanvas);
};
});
onDestroy(() => {
if (animationId !== null) {
cancelAnimationFrame(animationId);
}
if (gl) {
gl.getExtension('WEBGL_lose_context')?.loseContext();
}
});
</script>
<!-- Dots overlay with fade-in animation -->
<canvas
bind:this={canvas}
class={cn(
"pointer-events-none fixed inset-0 -z-10",
className
)}
></canvas>
-1
View File
@@ -1 +0,0 @@
// place files you want to import through the `$lib` alias in this folder.
-33
View File
@@ -1,33 +0,0 @@
import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";
import * as schema from "@xevion/db";
import { projectsRelations } from "@xevion/db";
const extendedSchema = {
...schema,
relations_projects: projectsRelations,
};
let _db: ReturnType<typeof drizzle> | null = null;
export function getDb() {
if (!_db) {
const connectionString = process.env.DATABASE_URL;
if (!connectionString) {
throw new Error("DATABASE_URL environment variable is not set");
}
const sql = postgres(connectionString);
_db = drizzle(sql, { schema: extendedSchema });
}
return _db;
}
// For backward compatibility
export const db = new Proxy({} as ReturnType<typeof drizzle>, {
get(target, prop) {
return getDb()[prop as keyof ReturnType<typeof drizzle>];
},
});
-12
View File
@@ -1,12 +0,0 @@
<script lang="ts">
import AppWrapper from "$lib/components/AppWrapper.svelte";
</script>
<AppWrapper>
<div class="flex min-h-screen items-center justify-center">
<div class="text-center">
<h1 class="font-hanken text-4xl text-zinc-200 md:text-5xl">Blog</h1>
<p class="mt-4 text-lg text-zinc-400">Coming soon...</p>
</div>
</div>
</AppWrapper>
@@ -1,21 +0,0 @@
import { getDb } from "$lib/server/db";
import { projects } from "@xevion/db";
import { eq, desc } from "drizzle-orm";
import type { PageServerLoad } from "./$types";
export const load: PageServerLoad = async (event) => {
const db = getDb(event);
// Use Drizzle relations for efficient join query
const projectsWithLinks = await db.query.projects.findMany({
where: eq(projects.status, "published"),
orderBy: [desc(projects.updatedAt)],
with: {
links: true,
},
});
return {
projects: projectsWithLinks,
};
};
-15
View File
@@ -1,15 +0,0 @@
import { redirect } from "@sveltejs/kit";
import { getDb } from "$lib/server/db";
import { metadata } from "@xevion/db";
import type { RequestHandler } from "./$types";
export const GET: RequestHandler = async (event) => {
const db = getDb(event);
// TODO: Query the metadata global for resume URL
// For now, redirect to a placeholder
// const meta = await db.select().from(metadata).limit(1);
// Placeholder redirect until we have the schema set up
redirect(302, "https://example.com/resume.pdf");
};
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 648 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.
-88
View File
@@ -1,88 +0,0 @@
==================================================================
https://keybase.io/xevion
--------------------------------------------------------------------
I hereby claim:
* I am an admin of https://xevion.dev
* I am xevion (https://keybase.io/xevion) on keybase.
* I have a public key with fingerprint 04EE F43A E775 B57F 5029 572E 1EF2 4DA2 70E7 9ECD
To do so, I am signing this object:
{
"body": {
"key": {
"eldest_kid": "012026f3d2df48d71d6ca5a33418101c284f7a73aac8944dc52edbfef17bb92369600a",
"fingerprint": "04eef43ae775b57f5029572e1ef24da270e79ecd",
"host": "keybase.io",
"key_id": "1ef24da270e79ecd",
"kid": "010167e9d3b055e24b9e6b83ec0e59f3e8daf5a5cbfe4f3f7edb7e1aa1e6a1f1dfd00a",
"uid": "120150a540a9487c406e6cf5e0423419",
"username": "xevion"
},
"merkle_root": {
"ctime": 1607280978,
"hash_meta": "ee4f985b1f5b4915e4963c7ce2945ac76673edc180e59ffdeafca8e57fcac740",
"seqno": 18330340
},
"revoke": {
"sig_ids": [
"4d1ae3b707b77cd3199a1a4d1c4becab985c2baecbc6c478da499b27d7fe7f230f"
]
},
"service": {
"hostname": "xevion.dev",
"protocol": "https:"
},
"type": "web_service_binding",
"version": 1
},
"ctime": 1607280982,
"expire_in": 157680000,
"prev": "12ae982e85b7fea5f216f2fe50d4145330bbf762a009c9183dc22d134da279ab",
"seqno": 32,
"tag": "signature"
}
which yields the signature:
-----BEGIN PGP MESSAGE-----
Version: Keybase OpenPGP v2.1.13
Comment: https://keybase.io/crypto
yMP0AnicbZN9bBRFGMavxUJaKbaAAkUElkSBVpidnd3ZPYyA0ICAjYBAaYVzZvZd
etz17rgvKNiqICpQ+YjhIyBobARUvhQaiESFhgQrVr7EohRKFSUCJYGKgYrU2SIx
Gvefzb77vO/zzG9mDmV28GSkPHL9mfciFzfVpRypiSU8vrpBUxcoPGyXKd4FSgDa
XxC0IRb3Bfy24lWQihE2HM3GtkNMm6q2IZjONI2opopUgU3iUEY1xoRpEWILHYPN
HXBUyrmFNcMyEGJKnuL4Q7MgGon6Q3F3LAFwiMaAUp3r1NERtnSKQQUHE5thioBa
IGzZWBKOuR0yHGcxGOIPy5r88LXH+x/9vdxINShYtsaRrgMm3AKDmxoIBLrlaGDa
zNGZLmRW4mgOlakpqIypYDDVUW3Hvps7cdcHI1VHTCeIWcSkgiADDOHogAiWKCxX
GINoiJWCVM+DpD8cUsrzlFKIBoLgi4bDcRetiPtdgWogik1kUVMuj8VKfKUQZ7IP
ZBTL1Lnq6JxYqg7EMjRBBWCL6ExQw6Aa2EI129fg2MAcwUyQ/IT8S5BMEYM5obB0
MDUNaQTJCFFIhgPgusf8syS1mOItVoitMtA4RZRTKmxNtSymMlkVhINgXKYQmDMQ
XBiCUAmLWBbH1KYOUAdryFFmlLtu0aRftA93t+lfyx9iQ1IGikTD8bAIB2W9JB6P
xLwulnhZxBXOBe77e4SP+0O2PCKyIwnRmIvPq0rlf4iZOE+BeRF/FHx+V6FTw0Ty
cX2knbtRDKQKJEUZlekOVg0HO6Ajm6hEl1Q4d6iBGUKWsCQmW2Bsq1r7IbIY/weh
Jq3ibJacKbmFWDwRBaW85uDz93lSMjwd01Ldu+PJSM+6d6MmHsjyVJ6P9Nze0jCO
v7JjUvCHdZ0K2sb0a1mRzFvb/VLfWk/jniVNlT6cf6JgW+m3t6JK9QtfTqvNH/v7
/QU3Dn8UxBfmrOzy/tPjGnqfahrQkdYeaDZHhCdXxNe/++ofbZnPtUVsz5rak4v3
bpvQ66uuT149/frMal/WzSt8+1B4dsvlPunHznyc03Vgn26hQZlDNiyZ+wXPT+09
uqIsc+TxziWJr4u7p530NOdcGvvB1W8e2P74mQG7qi7+tMjbevi1vluRfW7fzty0
hTkpqwo3li0TuY34WMHS5jtjro0s+5QUrfFXLjq116P30xdW3G4qOLIycKi48tzn
garNA9dMKY1UTbvua9l5Pe3sSy/n0vD4lEWzKz4cmKA3lW5HJwy+nZc9rP+KX3MP
tyWzT2WR5niwpbmqfveCTo1XWjOH7lrnOdgwTr2xP2tjYdfut2Y/ukEL+FqLr7UO
O7K5Qw91xoO35z6xLHtqed3pLYE5iZGn72QsbV1iNZc89Vj6psFF62syerzVeDY5
aVUpPf/2O6O8O5Tl+Wuzx5/YOWp+aq9V00fM9o+ad3nrpM6Jarh0fPRR1Dh6XzVJ
zf4x3ml8Uf9Plr3ZM2XvjOX1dY2/FU1pSk+bvP8G7t/hl89mlpftyZ44vUufg2Lp
ntXbEkW8b/3xC8MnPJwTrKE/B18c8EbhUA75Kxu++75+4uqrY5K58//EhfuG7z77
UPFfKC78RA==
=XyA8
-----END PGP MESSAGE-----
And finally, I am proving ownership of this host by posting or
appending to this document.
View my publicly-auditable identity here: https://keybase.io/xevion
==================================================================
-3
View File
@@ -1,3 +0,0 @@
# allow crawling everything by default
User-agent: *
Disallow:
-19
View File
@@ -1,19 +0,0 @@
{
"name": "Xevion.dev",
"short_name": "Xevion.dev",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#000000",
"display": "standalone"
}
-2674
View File
File diff suppressed because it is too large Load Diff
-218
View File
@@ -1,218 +0,0 @@
#!/usr/bin/env bun
/**
* Production entrypoint for xevion.dev Docker container.
* Manages environment validation, database migrations, and service orchestration.
*/
import { spawn, type Subprocess } from "bun";
const log = (
level: "info" | "warn" | "error",
message: string,
data?: Record<string, unknown>,
) => {
const entry = {
level,
timestamp: new Date().toISOString(),
message,
...data,
};
console.log(JSON.stringify(entry));
};
function validateEnvironment(): void {
log("info", "starting deployment", { service: "entrypoint" });
const required = ["DATABASE_URL", "PAYLOAD_SECRET"] as const;
const optional = ["R2_BUCKET_NAME"] as const;
for (const key of required) {
if (!process.env[key]) {
log("error", "missing required environment variable", {
service: "entrypoint",
variable: key,
});
process.exit(1);
}
}
const missing: string[] = [];
for (const key of optional) {
if (!process.env[key]) {
missing.push(key);
}
}
if (missing.length > 0) {
log("warn", "missing optional environment variables", {
service: "entrypoint",
variables: missing,
});
}
log("info", "environment validated", { service: "entrypoint" });
}
async function runMigrations(): Promise<void> {
log("info", "migrations will run on first payload start", {
service: "entrypoint",
});
}
function displayConfig(): void {
const config = {
service: "entrypoint",
port: process.env.PORT || "3000",
nodeEnv: process.env.NODE_ENV || "production",
r2Bucket: process.env.R2_BUCKET_NAME || null,
runtime: `Bun ${Bun.version}`,
};
log("info", "configuration", config);
}
interface Service {
name: string;
proc: Subprocess;
}
async function startServices(): Promise<Service[]> {
const port = process.env.PORT || "3000";
const services: Service[] = [];
const caddy = spawn({
cmd: ["caddy", "run", "--config", "Caddyfile"],
cwd: "/app",
stdout: "pipe",
stderr: "pipe",
});
services.push({ name: "caddy", proc: caddy });
log("info", "service started", { service: "caddy", pid: caddy.pid, port });
// Transform Caddy's JSON logs to match our format
(async () => {
for await (const chunk of caddy.stderr) {
const lines = new TextDecoder().decode(chunk).trim().split("\n");
for (const line of lines) {
if (!line) continue;
try {
const caddyLog = JSON.parse(line);
log(caddyLog.level || "info", caddyLog.msg || caddyLog.message, {
service: "caddy",
logger: caddyLog.logger,
...Object.fromEntries(
Object.entries(caddyLog).filter(
([k]) =>
!["level", "ts", "msg", "message", "logger"].includes(k),
),
),
});
} catch {
// Not JSON, log as-is
log("info", line, { service: "caddy" });
}
}
}
})();
const payload = spawn({
cmd: ["bun", "/app/apps/payload/.next/standalone/apps/payload/server.js"],
cwd: "/app",
env: {
...process.env,
PORT: "5001",
HOSTNAME: "0.0.0.0",
NEXT_TELEMETRY_DISABLED: "1",
},
stdout: "pipe",
stderr: "pipe",
});
services.push({ name: "payload", proc: payload });
log("info", "service started", {
service: "payload",
pid: payload.pid,
port: 5001,
});
// Log stdout and stderr from Next.js
(async () => {
for await (const chunk of payload.stdout) {
const line = new TextDecoder().decode(chunk).trim();
if (line) log("info", line, { service: "payload" });
}
})();
(async () => {
for await (const chunk of payload.stderr) {
const line = new TextDecoder().decode(chunk).trim();
if (line) log("error", line, { service: "payload" });
}
})();
const web = spawn({
cmd: ["/app/apps/web/web-server"],
cwd: "/app",
env: { ...process.env, PORT: "5000", VERBOSE: "false" },
stdout: "pipe",
stderr: "inherit",
});
services.push({ name: "web", proc: web });
log("info", "service started", { service: "web", pid: web.pid, port: 5000 });
log("info", "all services started", { service: "entrypoint" });
return services;
}
function setupShutdownHandlers(services: Service[]): void {
const cleanup = async () => {
log("info", "shutdown signal received", { service: "entrypoint" });
for (const service of services) {
try {
service.proc.kill();
} catch {
// Process already dead
}
}
await Promise.allSettled(services.map((s) => s.proc.exited));
log("info", "all services stopped", { service: "entrypoint" });
process.exit(0);
};
process.on("SIGTERM", cleanup);
process.on("SIGINT", cleanup);
}
async function main(): Promise<void> {
validateEnvironment();
await runMigrations();
displayConfig();
const services = await startServices();
setupShutdownHandlers(services);
const results = await Promise.allSettled(services.map((s) => s.proc.exited));
const failures = results.filter(
(r) => r.status === "rejected" || r.value !== 0,
);
if (failures.length > 0) {
log("error", "service exited unexpectedly", {
service: "entrypoint",
count: failures.length,
});
process.exit(1);
}
}
main().catch((error) => {
log("error", "fatal error", {
service: "entrypoint",
error: error.message,
stack: error.stack,
});
process.exit(1);
});
-38
View File
@@ -1,38 +0,0 @@
{
"name": "xevion.dev",
"private": true,
"type": "module",
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev --filter=@xevion/web --env-mode=loose",
"dev:local": "turbo run dev --filter=@xevion/web --env-mode=loose",
"dev:remote": "turbo run dev:remote --filter=@xevion/web --env-mode=loose",
"dev:payload": "turbo run dev --filter=@xevion/payload --env-mode=loose",
"preview": "turbo run preview --filter=@xevion/web",
"preview:payload": "turbo run preview --filter=@xevion/payload",
"lint": "turbo run lint",
"check": "turbo run check",
"type-check": "turbo run type-check",
"test": "turbo run test",
"deploy": "turbo run deploy",
"clean": "turbo run clean && rm -rf node_modules .turbo",
"graph": "turbo run build --graph=dependency-graph.html",
"graph:dev": "turbo run dev --graph=dev-graph.html --dry-run",
"payload": "bun --filter=@xevion/payload payload",
"docker:build": "docker build -t xevion.dev .",
"docker:run": "docker run -p 3000:3000 --env-file <(cat .env 2>/dev/null || echo 'DATABASE_URL=postgresql://xevion:xevion@host.docker.internal:5432/xevion'; echo 'PAYLOAD_SECRET=development-secret-change-in-production'; echo 'ORIGIN=http://localhost:3000') xevion.dev",
"docker:db": "docker run --name xevion-db -p 5432:5432 -e POSTGRES_USER=xevion -e POSTGRES_PASSWORD=xevion -e POSTGRES_DB=xevion -d postgres"
},
"dependencies": {},
"devDependencies": {
"@types/bun": "^1.3.5",
"prettier": "^3.7.4",
"turbo": "^2.3.4",
"typescript": "^5.9.3"
},
"packageManager": "bun@1.3.5",
"workspaces": [
"apps/*",
"packages/*"
]
}
-25
View File
@@ -1,25 +0,0 @@
{
"name": "@xevion/db",
"version": "0.0.0",
"private": true,
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"type-check": "tsc --noEmit",
"clean": "rm -rf dist .turbo node_modules *.tsbuildinfo"
},
"dependencies": {
"drizzle-orm": "0.44.7",
"@payloadcms/db-postgres": "^3.69.0"
},
"devDependencies": {
"@xevion/typescript-config": "workspace:*"
}
}
-5
View File
@@ -1,5 +0,0 @@
// Export the schema generated by PayloadCMS
export * from "./schema";
// Export custom relations that extend Payload's auto-generated schema
export { projectsRelations } from "./relations";
-24
View File
@@ -1,24 +0,0 @@
// Custom Drizzle relations that extend the auto-generated Payload schema
// This file adds the reverse relationships that Payload doesn't auto-generate
import { relations } from "drizzle-orm";
import { projects, links, technologies, projects_rels, media } from "./schema";
// Override the auto-generated relations_projects to add links
export const projectsRelations = relations(projects, ({ one, many }) => ({
bannerImage: one(media, {
fields: [projects.bannerImage],
references: [media.id],
relationName: "bannerImage",
}),
_rels: many(projects_rels, {
relationName: "_rels",
}),
// Add the reverse relationship for links
links: many(links, {
relationName: "project",
}),
}));
// Note: Other relations are auto-generated and exported from schema.ts
// We only override the ones that need custom reverse relationships
-630
View File
@@ -1,630 +0,0 @@
/* tslint:disable */
/* eslint-disable */
/**
* This file was automatically generated by Payload.
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
* and re-run `payload generate:db-schema` to regenerate this file.
*/
import type {} from "@payloadcms/db-postgres";
import {
pgTable,
index,
uniqueIndex,
foreignKey,
integer,
varchar,
timestamp,
serial,
numeric,
boolean,
jsonb,
pgEnum,
} from "@payloadcms/db-postgres/drizzle/pg-core";
import { sql, relations } from "@payloadcms/db-postgres/drizzle";
export const enum_projects_status = pgEnum("enum_projects_status", [
"draft",
"published",
"archived",
]);
export const users_sessions = pgTable(
"users_sessions",
{
_order: integer("_order").notNull(),
_parentID: integer("_parent_id").notNull(),
id: varchar("id").primaryKey(),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
}),
expiresAt: timestamp("expires_at", {
mode: "string",
withTimezone: true,
precision: 3,
}).notNull(),
},
(columns) => [
index("users_sessions_order_idx").on(columns._order),
index("users_sessions_parent_id_idx").on(columns._parentID),
foreignKey({
columns: [columns["_parentID"]],
foreignColumns: [users.id],
name: "users_sessions_parent_id_fk",
}).onDelete("cascade"),
],
);
export const users = pgTable(
"users",
{
id: serial("id").primaryKey(),
updatedAt: timestamp("updated_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
email: varchar("email").notNull(),
resetPasswordToken: varchar("reset_password_token"),
resetPasswordExpiration: timestamp("reset_password_expiration", {
mode: "string",
withTimezone: true,
precision: 3,
}),
salt: varchar("salt"),
hash: varchar("hash"),
loginAttempts: numeric("login_attempts", { mode: "number" }).default(0),
lockUntil: timestamp("lock_until", {
mode: "string",
withTimezone: true,
precision: 3,
}),
},
(columns) => [
index("users_updated_at_idx").on(columns.updatedAt),
index("users_created_at_idx").on(columns.createdAt),
uniqueIndex("users_email_idx").on(columns.email),
],
);
export const media = pgTable(
"media",
{
id: serial("id").primaryKey(),
alt: varchar("alt").notNull(),
updatedAt: timestamp("updated_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
url: varchar("url"),
thumbnailURL: varchar("thumbnail_u_r_l"),
filename: varchar("filename"),
mimeType: varchar("mime_type"),
filesize: numeric("filesize", { mode: "number" }),
width: numeric("width", { mode: "number" }),
height: numeric("height", { mode: "number" }),
focalX: numeric("focal_x", { mode: "number" }),
focalY: numeric("focal_y", { mode: "number" }),
},
(columns) => [
index("media_updated_at_idx").on(columns.updatedAt),
index("media_created_at_idx").on(columns.createdAt),
uniqueIndex("media_filename_idx").on(columns.filename),
],
);
export const projects = pgTable(
"projects",
{
id: serial("id").primaryKey(),
name: varchar("name").notNull(),
description: varchar("description").notNull(),
shortDescription: varchar("short_description").notNull(),
icon: varchar("icon"),
status: enum_projects_status("status").notNull().default("draft"),
featured: boolean("featured").default(false),
autocheckUpdated: boolean("autocheck_updated").default(false),
lastUpdated: timestamp("last_updated", {
mode: "string",
withTimezone: true,
precision: 3,
}),
wakatimeOffset: numeric("wakatime_offset", { mode: "number" }),
bannerImage: integer("banner_image_id").references(() => media.id, {
onDelete: "set null",
}),
updatedAt: timestamp("updated_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
},
(columns) => [
index("projects_banner_image_idx").on(columns.bannerImage),
index("projects_updated_at_idx").on(columns.updatedAt),
index("projects_created_at_idx").on(columns.createdAt),
],
);
export const projects_rels = pgTable(
"projects_rels",
{
id: serial("id").primaryKey(),
order: integer("order"),
parent: integer("parent_id").notNull(),
path: varchar("path").notNull(),
technologiesID: integer("technologies_id"),
},
(columns) => [
index("projects_rels_order_idx").on(columns.order),
index("projects_rels_parent_idx").on(columns.parent),
index("projects_rels_path_idx").on(columns.path),
index("projects_rels_technologies_id_idx").on(columns.technologiesID),
foreignKey({
columns: [columns["parent"]],
foreignColumns: [projects.id],
name: "projects_rels_parent_fk",
}).onDelete("cascade"),
foreignKey({
columns: [columns["technologiesID"]],
foreignColumns: [technologies.id],
name: "projects_rels_technologies_fk",
}).onDelete("cascade"),
],
);
export const technologies = pgTable(
"technologies",
{
id: serial("id").primaryKey(),
name: varchar("name").notNull(),
url: varchar("url"),
updatedAt: timestamp("updated_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
},
(columns) => [
index("technologies_updated_at_idx").on(columns.updatedAt),
index("technologies_created_at_idx").on(columns.createdAt),
],
);
export const links = pgTable(
"links",
{
id: serial("id").primaryKey(),
url: varchar("url").notNull(),
icon: varchar("icon"),
description: varchar("description"),
project: integer("project_id")
.notNull()
.references(() => projects.id, {
onDelete: "set null",
}),
updatedAt: timestamp("updated_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
},
(columns) => [
index("links_project_idx").on(columns.project),
index("links_updated_at_idx").on(columns.updatedAt),
index("links_created_at_idx").on(columns.createdAt),
],
);
export const payload_kv = pgTable(
"payload_kv",
{
id: serial("id").primaryKey(),
key: varchar("key").notNull(),
data: jsonb("data").notNull(),
},
(columns) => [uniqueIndex("payload_kv_key_idx").on(columns.key)],
);
export const payload_locked_documents = pgTable(
"payload_locked_documents",
{
id: serial("id").primaryKey(),
globalSlug: varchar("global_slug"),
updatedAt: timestamp("updated_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
},
(columns) => [
index("payload_locked_documents_global_slug_idx").on(columns.globalSlug),
index("payload_locked_documents_updated_at_idx").on(columns.updatedAt),
index("payload_locked_documents_created_at_idx").on(columns.createdAt),
],
);
export const payload_locked_documents_rels = pgTable(
"payload_locked_documents_rels",
{
id: serial("id").primaryKey(),
order: integer("order"),
parent: integer("parent_id").notNull(),
path: varchar("path").notNull(),
usersID: integer("users_id"),
mediaID: integer("media_id"),
projectsID: integer("projects_id"),
technologiesID: integer("technologies_id"),
linksID: integer("links_id"),
},
(columns) => [
index("payload_locked_documents_rels_order_idx").on(columns.order),
index("payload_locked_documents_rels_parent_idx").on(columns.parent),
index("payload_locked_documents_rels_path_idx").on(columns.path),
index("payload_locked_documents_rels_users_id_idx").on(columns.usersID),
index("payload_locked_documents_rels_media_id_idx").on(columns.mediaID),
index("payload_locked_documents_rels_projects_id_idx").on(
columns.projectsID,
),
index("payload_locked_documents_rels_technologies_id_idx").on(
columns.technologiesID,
),
index("payload_locked_documents_rels_links_id_idx").on(columns.linksID),
foreignKey({
columns: [columns["parent"]],
foreignColumns: [payload_locked_documents.id],
name: "payload_locked_documents_rels_parent_fk",
}).onDelete("cascade"),
foreignKey({
columns: [columns["usersID"]],
foreignColumns: [users.id],
name: "payload_locked_documents_rels_users_fk",
}).onDelete("cascade"),
foreignKey({
columns: [columns["mediaID"]],
foreignColumns: [media.id],
name: "payload_locked_documents_rels_media_fk",
}).onDelete("cascade"),
foreignKey({
columns: [columns["projectsID"]],
foreignColumns: [projects.id],
name: "payload_locked_documents_rels_projects_fk",
}).onDelete("cascade"),
foreignKey({
columns: [columns["technologiesID"]],
foreignColumns: [technologies.id],
name: "payload_locked_documents_rels_technologies_fk",
}).onDelete("cascade"),
foreignKey({
columns: [columns["linksID"]],
foreignColumns: [links.id],
name: "payload_locked_documents_rels_links_fk",
}).onDelete("cascade"),
],
);
export const payload_preferences = pgTable(
"payload_preferences",
{
id: serial("id").primaryKey(),
key: varchar("key"),
value: jsonb("value"),
updatedAt: timestamp("updated_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
},
(columns) => [
index("payload_preferences_key_idx").on(columns.key),
index("payload_preferences_updated_at_idx").on(columns.updatedAt),
index("payload_preferences_created_at_idx").on(columns.createdAt),
],
);
export const payload_preferences_rels = pgTable(
"payload_preferences_rels",
{
id: serial("id").primaryKey(),
order: integer("order"),
parent: integer("parent_id").notNull(),
path: varchar("path").notNull(),
usersID: integer("users_id"),
},
(columns) => [
index("payload_preferences_rels_order_idx").on(columns.order),
index("payload_preferences_rels_parent_idx").on(columns.parent),
index("payload_preferences_rels_path_idx").on(columns.path),
index("payload_preferences_rels_users_id_idx").on(columns.usersID),
foreignKey({
columns: [columns["parent"]],
foreignColumns: [payload_preferences.id],
name: "payload_preferences_rels_parent_fk",
}).onDelete("cascade"),
foreignKey({
columns: [columns["usersID"]],
foreignColumns: [users.id],
name: "payload_preferences_rels_users_fk",
}).onDelete("cascade"),
],
);
export const payload_migrations = pgTable(
"payload_migrations",
{
id: serial("id").primaryKey(),
name: varchar("name"),
batch: numeric("batch", { mode: "number" }),
updatedAt: timestamp("updated_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
})
.defaultNow()
.notNull(),
},
(columns) => [
index("payload_migrations_updated_at_idx").on(columns.updatedAt),
index("payload_migrations_created_at_idx").on(columns.createdAt),
],
);
export const metadata = pgTable(
"metadata",
{
id: serial("id").primaryKey(),
tagline: varchar("tagline").notNull(),
resume: integer("resume_id")
.notNull()
.references(() => media.id, {
onDelete: "set null",
}),
resumeFilename: varchar("resume_filename"),
updatedAt: timestamp("updated_at", {
mode: "string",
withTimezone: true,
precision: 3,
}),
createdAt: timestamp("created_at", {
mode: "string",
withTimezone: true,
precision: 3,
}),
},
(columns) => [index("metadata_resume_idx").on(columns.resume)],
);
export const relations_users_sessions = relations(
users_sessions,
({ one }) => ({
_parentID: one(users, {
fields: [users_sessions._parentID],
references: [users.id],
relationName: "sessions",
}),
}),
);
export const relations_users = relations(users, ({ many }) => ({
sessions: many(users_sessions, {
relationName: "sessions",
}),
}));
export const relations_media = relations(media, () => ({}));
export const relations_projects_rels = relations(projects_rels, ({ one }) => ({
parent: one(projects, {
fields: [projects_rels.parent],
references: [projects.id],
relationName: "_rels",
}),
technologiesID: one(technologies, {
fields: [projects_rels.technologiesID],
references: [technologies.id],
relationName: "technologies",
}),
}));
export const relations_projects = relations(projects, ({ one, many }) => ({
bannerImage: one(media, {
fields: [projects.bannerImage],
references: [media.id],
relationName: "bannerImage",
}),
_rels: many(projects_rels, {
relationName: "_rels",
}),
}));
export const relations_technologies = relations(technologies, () => ({}));
export const relations_links = relations(links, ({ one }) => ({
project: one(projects, {
fields: [links.project],
references: [projects.id],
relationName: "project",
}),
}));
export const relations_payload_kv = relations(payload_kv, () => ({}));
export const relations_payload_locked_documents_rels = relations(
payload_locked_documents_rels,
({ one }) => ({
parent: one(payload_locked_documents, {
fields: [payload_locked_documents_rels.parent],
references: [payload_locked_documents.id],
relationName: "_rels",
}),
usersID: one(users, {
fields: [payload_locked_documents_rels.usersID],
references: [users.id],
relationName: "users",
}),
mediaID: one(media, {
fields: [payload_locked_documents_rels.mediaID],
references: [media.id],
relationName: "media",
}),
projectsID: one(projects, {
fields: [payload_locked_documents_rels.projectsID],
references: [projects.id],
relationName: "projects",
}),
technologiesID: one(technologies, {
fields: [payload_locked_documents_rels.technologiesID],
references: [technologies.id],
relationName: "technologies",
}),
linksID: one(links, {
fields: [payload_locked_documents_rels.linksID],
references: [links.id],
relationName: "links",
}),
}),
);
export const relations_payload_locked_documents = relations(
payload_locked_documents,
({ many }) => ({
_rels: many(payload_locked_documents_rels, {
relationName: "_rels",
}),
}),
);
export const relations_payload_preferences_rels = relations(
payload_preferences_rels,
({ one }) => ({
parent: one(payload_preferences, {
fields: [payload_preferences_rels.parent],
references: [payload_preferences.id],
relationName: "_rels",
}),
usersID: one(users, {
fields: [payload_preferences_rels.usersID],
references: [users.id],
relationName: "users",
}),
}),
);
export const relations_payload_preferences = relations(
payload_preferences,
({ many }) => ({
_rels: many(payload_preferences_rels, {
relationName: "_rels",
}),
}),
);
export const relations_payload_migrations = relations(
payload_migrations,
() => ({}),
);
export const relations_metadata = relations(metadata, ({ one }) => ({
resume: one(media, {
fields: [metadata.resume],
references: [media.id],
relationName: "resume",
}),
}));
type DatabaseSchema = {
enum_projects_status: typeof enum_projects_status;
users_sessions: typeof users_sessions;
users: typeof users;
media: typeof media;
projects: typeof projects;
projects_rels: typeof projects_rels;
technologies: typeof technologies;
links: typeof links;
payload_kv: typeof payload_kv;
payload_locked_documents: typeof payload_locked_documents;
payload_locked_documents_rels: typeof payload_locked_documents_rels;
payload_preferences: typeof payload_preferences;
payload_preferences_rels: typeof payload_preferences_rels;
payload_migrations: typeof payload_migrations;
metadata: typeof metadata;
relations_users_sessions: typeof relations_users_sessions;
relations_users: typeof relations_users;
relations_media: typeof relations_media;
relations_projects_rels: typeof relations_projects_rels;
relations_projects: typeof relations_projects;
relations_technologies: typeof relations_technologies;
relations_links: typeof relations_links;
relations_payload_kv: typeof relations_payload_kv;
relations_payload_locked_documents_rels: typeof relations_payload_locked_documents_rels;
relations_payload_locked_documents: typeof relations_payload_locked_documents;
relations_payload_preferences_rels: typeof relations_payload_preferences_rels;
relations_payload_preferences: typeof relations_payload_preferences;
relations_payload_migrations: typeof relations_payload_migrations;
relations_metadata: typeof relations_metadata;
};
declare module "@payloadcms/db-postgres" {
export interface GeneratedDatabaseSchema {
schema: DatabaseSchema;
}
}
-8
View File
@@ -1,8 +0,0 @@
{
"extends": "@xevion/typescript-config/base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"]
}
-21
View File
@@ -1,21 +0,0 @@
{
"name": "@xevion/types",
"version": "0.0.0",
"private": true,
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"type-check": "tsc --noEmit",
"clean": "rm -rf dist .turbo node_modules *.tsbuildinfo"
},
"devDependencies": {
"@xevion/typescript-config": "workspace:*"
}
}
-3
View File
@@ -1,3 +0,0 @@
// This file will be populated by Payload's generate:types command
// Placeholder export
export type PayloadTypes = Record<string, any>;
-8
View File
@@ -1,8 +0,0 @@
{
"extends": "@xevion/typescript-config/base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"]
}
-17
View File
@@ -1,17 +0,0 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022"],
"module": "ESNext",
"moduleResolution": "bundler",
"esModuleInterop": true,
"strict": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"declaration": true,
"declarationMap": true
}
}
-9
View File
@@ -1,9 +0,0 @@
{
"name": "@xevion/typescript-config",
"version": "0.0.0",
"private": true,
"license": "MIT",
"publishConfig": {
"access": "public"
}
}
-119
View File
@@ -1,119 +0,0 @@
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": [
".env",
".env.*",
"tsconfig.json",
"package.json",
"bun.lock"
],
"globalEnv": ["NODE_ENV", "DATABASE_URL", "PAYLOAD_SECRET"],
"tasks": {
"build": {
"dependsOn": ["^build"],
"inputs": [
"src/**",
"public/**",
"static/**",
"*.config.*",
"tsconfig.json",
"package.json"
],
"outputs": [".svelte-kit/**", "build/**", "dist/**", ".next/**"],
"outputLogs": "new-only"
},
"dev": {
"cache": false,
"persistent": true
},
"deploy": {
"dependsOn": ["build"],
"cache": false
},
"@xevion/payload#build:worker": {
"dependsOn": ["^build"],
"inputs": [
"src/**",
"public/**",
"static/**",
"*.config.*",
"tsconfig.json",
"package.json"
],
"outputs": [".svelte-kit/**", "dist/**", ".next/**"],
"outputLogs": "new-only"
},
"@xevion/web#dev": {
"dependsOn": ["@xevion/payload#build:worker"],
"cache": false,
"persistent": true
},
"lint": {
"dependsOn": ["^build"],
"inputs": ["src/**", "*.config.*", "package.json"],
"outputLogs": "new-only"
},
"check": {
"dependsOn": ["^build"],
"inputs": ["src/**", "*.config.*", "tsconfig.json", "package.json"],
"outputLogs": "new-only"
},
"type-check": {
"dependsOn": ["^build"],
"inputs": ["src/**", "*.config.*", "tsconfig.json", "package.json"],
"outputs": ["*.tsbuildinfo"],
"outputLogs": "errors-only"
},
"test": {
"dependsOn": ["^build"],
"inputs": ["src/**", "tests/**", "test/**", "*.config.*", "package.json"],
"outputLogs": "new-only"
},
"test:int": {
"dependsOn": ["^build"],
"inputs": ["src/**", "tests/int/**", "vitest.config.*", "package.json"],
"env": ["NODE_ENV"],
"outputLogs": "new-only"
},
"test:e2e": {
"dependsOn": ["build"],
"inputs": [
"src/**",
"tests/e2e/**",
"playwright.config.*",
"package.json"
],
"env": ["NODE_ENV"],
"outputLogs": "new-only"
},
"generate:types": {
"inputs": [
"src/collections/**",
"src/globals/**",
"src/payload.config.ts"
],
"outputs": ["src/payload-types.ts"],
"cache": false
},
"generate:schema": {
"inputs": [
"src/collections/**",
"src/globals/**",
"src/payload.config.ts"
],
"outputs": [
"src/payload-generated-schema.ts",
"../../packages/db/src/schema.ts"
],
"cache": false
},
"clean": {
"cache": false
},
"preview": {
"dependsOn": ["build"],
"cache": false,
"persistent": true
}
}
}
+3
View File
@@ -0,0 +1,3 @@
.svelte-kit
build
node_modules
+4
View File
@@ -0,0 +1,4 @@
{
"plugins": ["prettier-plugin-svelte"],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}
+661
View File
@@ -0,0 +1,661 @@
{
"lockfileVersion": 1,
"configVersion": 1,
"workspaces": {
"": {
"dependencies": {
"@fontsource-variable/inter": "^5.1.0",
"@fontsource/hanken-grotesk": "^5.1.0",
"@fontsource/schibsted-grotesk": "^5.2.8",
"bits-ui": "^2.8.2",
"clsx": "^2.1.1",
"tailwind-merge": "^3.3.1",
},
"devDependencies": {
"@eslint/js": "^9.39.2",
"@iconify/json": "^2.2.424",
"@sveltejs/kit": "^2.21.0",
"@sveltejs/vite-plugin-svelte": "^6.2.1",
"@tailwindcss/vite": "^4.1.11",
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-svelte": "^3.13.1",
"globals": "^17.0.0",
"prettier": "^3.7.4",
"prettier-plugin-svelte": "^3.4.1",
"svelte": "^5.45.6",
"svelte-adapter-bun": "^1.0.1",
"svelte-check": "^4.3.4",
"tailwindcss": "^4.1.11",
"typescript-eslint": "^8.51.0",
"unplugin-icons": "^22.5.0",
"vite": "^7.2.6",
},
},
},
"packages": {
"@antfu/install-pkg": ["@antfu/install-pkg@1.1.0", "", { "dependencies": { "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" } }, "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ=="],
"@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="],
"@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.27.2", "", { "os": "android", "cpu": "arm" }, "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.2", "", { "os": "android", "cpu": "arm64" }, "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.27.2", "", { "os": "android", "cpu": "x64" }, "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.2", "", { "os": "linux", "cpu": "arm" }, "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.2", "", { "os": "none", "cpu": "x64" }, "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg=="],
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="],
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="],
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="],
"@eslint/config-array": ["@eslint/config-array@0.21.1", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA=="],
"@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="],
"@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="],
"@eslint/eslintrc": ["@eslint/eslintrc@3.3.3", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ=="],
"@eslint/js": ["@eslint/js@9.39.2", "", {}, "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA=="],
"@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="],
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="],
"@floating-ui/core": ["@floating-ui/core@1.7.3", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="],
"@floating-ui/dom": ["@floating-ui/dom@1.7.4", "", { "dependencies": { "@floating-ui/core": "^1.7.3", "@floating-ui/utils": "^0.2.10" } }, "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA=="],
"@floating-ui/utils": ["@floating-ui/utils@0.2.10", "", {}, "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="],
"@fontsource-variable/inter": ["@fontsource-variable/inter@5.2.8", "", {}, "sha512-kOfP2D+ykbcX/P3IFnokOhVRNoTozo5/JxhAIVYLpea/UBmCQ/YWPBfWIDuBImXX/15KH+eKh4xpEUyS2sQQGQ=="],
"@fontsource/hanken-grotesk": ["@fontsource/hanken-grotesk@5.2.8", "", {}, "sha512-J/e6hdfNCbyc4WK5hmZtk0zjaIsFx3pvCdPVxY25iYw2C9v1ZggGz4nfHnRjMhcz4WfaadUuwLNtvj8sQ70tkg=="],
"@fontsource/schibsted-grotesk": ["@fontsource/schibsted-grotesk@5.2.8", "", {}, "sha512-CyyDW5aS89oKGFAVndOsJTQ5pqzKuPnSKWjrdJdMT5TD/eA2JyWapUBhvy6X/lqqrB/GNk74PIff7coPifeVyg=="],
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
"@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="],
"@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="],
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
"@iconify/json": ["@iconify/json@2.2.424", "", { "dependencies": { "@iconify/types": "*", "pathe": "^2.0.3" } }, "sha512-Lxx8ad2DgyTGV88ec0mlaJ+OSjr0SyU0j8Awfbxl9JrxxHmBEFQJ+jywhztWAhLnaMUG3+G1htNJYzEsoAsNMQ=="],
"@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="],
"@iconify/utils": ["@iconify/utils@3.1.0", "", { "dependencies": { "@antfu/install-pkg": "^1.1.0", "@iconify/types": "^2.0.0", "mlly": "^1.8.0" } }, "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw=="],
"@internationalized/date": ["@internationalized/date@3.10.1", "", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-oJrXtQiAXLvT9clCf1K4kxp3eKsQhIaZqxEyowkBcsvZDdZkbWrVmnGknxs5flTD0VGsxrxKgBCZty1EzoiMzA=="],
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
"@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="],
"@oxc-project/runtime": ["@oxc-project/runtime@0.71.0", "", {}, "sha512-QwoF5WUXIGFQ+hSxWEib4U/aeLoiDN9JlP18MnBgx9LLPRDfn1iICtcow7Jgey6HLH4XFceWXQD5WBJ39dyJcw=="],
"@oxc-project/types": ["@oxc-project/types@0.71.0", "", {}, "sha512-5CwQ4MI+P4MQbjLWXgNurA+igGwu/opNetIE13LBs9+V93R64MLvDKOOLZIXSzEfovU3Zef3q3GjPnMTgJTn2w=="],
"@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="],
"@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-beta.9-commit.d91dfb5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Mp0/gqiPdepHjjVm7e0yL1acWvI0rJVVFQEADSezvAjon9sjQ7CEg9JnXICD4B1YrPmN9qV/e7cQZCp87tTV4w=="],
"@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-beta.9-commit.d91dfb5", "", { "os": "darwin", "cpu": "x64" }, "sha512-40re4rMNrsi57oavRzIOpRGmg3QRlW6Ea8Q3znaqgOuJuKVrrm2bIQInTfkZJG7a4/5YMX7T951d0+toGLTdCA=="],
"@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-beta.9-commit.d91dfb5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-8BDM939bbMariZupiHp3OmP5N+LXPT4mULA0hZjDaq970PCxv4krZOSMG+HkWUUwmuQROtV+/00xw39EO0P+8g=="],
"@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.9-commit.d91dfb5", "", { "os": "linux", "cpu": "arm" }, "sha512-sntsPaPgrECpBB/+2xrQzVUt0r493TMPI+4kWRMhvMsmrxOqH1Ep5lM0Wua/ZdbfZNwm1aVa5pcESQfNfM4Fhw=="],
"@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-beta.9-commit.d91dfb5", "", { "os": "linux", "cpu": "arm64" }, "sha512-5clBW/I+er9F2uM1OFjJFWX86y7Lcy0M+NqsN4s3o07W+8467Zk8oQa4B45vdaXoNUF/yqIAgKkA/OEdQDxZqA=="],
"@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-beta.9-commit.d91dfb5", "", { "os": "linux", "cpu": "arm64" }, "sha512-wv+rnAfQDk9p/CheX8/Kmqk2o1WaFa4xhWI9gOyDMk/ljvOX0u0ubeM8nI1Qfox7Tnh71eV5AjzSePXUhFOyOg=="],
"@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-beta.9-commit.d91dfb5", "", { "os": "linux", "cpu": "x64" }, "sha512-gxD0/xhU4Py47IH3bKZbWtvB99tMkUPGPJFRfSc5UB9Osoje0l0j1PPbxpUtXIELurYCqwLBKXIMTQGifox1BQ=="],
"@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-beta.9-commit.d91dfb5", "", { "os": "linux", "cpu": "x64" }, "sha512-HotuVe3XUjDwqqEMbm3o3IRkP9gdm8raY/btd/6KE3JGLF/cv4+3ff1l6nOhAZI8wulWDPEXPtE7v+HQEaTXnA=="],
"@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-beta.9-commit.d91dfb5", "", { "dependencies": { "@napi-rs/wasm-runtime": "^0.2.4" }, "cpu": "none" }, "sha512-8Cx+ucbd8n2dIr21FqBh6rUvTVL0uTgEtKR7l+MUZ5BgY4dFh1e4mPVX8oqmoYwOxBiXrsD2JIOCz4AyKLKxWA=="],
"@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-beta.9-commit.d91dfb5", "", { "os": "win32", "cpu": "arm64" }, "sha512-Vhq5vikrVDxAa75fxsyqj0c0Y/uti/TwshXI71Xb8IeUQJOBnmLUsn5dgYf5ljpYYkNa0z9BPAvUDIDMmyDi+w=="],
"@rolldown/binding-win32-ia32-msvc": ["@rolldown/binding-win32-ia32-msvc@1.0.0-beta.9-commit.d91dfb5", "", { "os": "win32", "cpu": "ia32" }, "sha512-lN7RIg9Iugn08zP2aZN9y/MIdG8iOOCE93M1UrFlrxMTqPf8X+fDzmR/OKhTSd1A2pYNipZHjyTcb5H8kyQSow=="],
"@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-beta.9-commit.d91dfb5", "", { "os": "win32", "cpu": "x64" }, "sha512-7/7cLIn48Y+EpQ4CePvf8reFl63F15yPUlg4ZAhl+RXJIfydkdak1WD8Ir3AwAO+bJBXzrfNL+XQbxm0mcQZmw=="],
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.9-commit.d91dfb5", "", {}, "sha512-8sExkWRK+zVybw3+2/kBkYBFeLnEUWz1fT7BLHplpzmtqkOfTbAQ9gkt4pzwGIIZmg4Qn5US5ACjUBenrhezwQ=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.54.0", "", { "os": "android", "cpu": "arm" }, "sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.54.0", "", { "os": "android", "cpu": "arm64" }, "sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw=="],
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.54.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw=="],
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.54.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A=="],
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.54.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA=="],
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.54.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ=="],
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.54.0", "", { "os": "linux", "cpu": "arm" }, "sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ=="],
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.54.0", "", { "os": "linux", "cpu": "arm" }, "sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA=="],
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.54.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng=="],
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.54.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg=="],
"@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.54.0", "", { "os": "linux", "cpu": "none" }, "sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw=="],
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.54.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA=="],
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.54.0", "", { "os": "linux", "cpu": "none" }, "sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ=="],
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.54.0", "", { "os": "linux", "cpu": "none" }, "sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A=="],
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.54.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ=="],
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.54.0", "", { "os": "linux", "cpu": "x64" }, "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ=="],
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.54.0", "", { "os": "linux", "cpu": "x64" }, "sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw=="],
"@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.54.0", "", { "os": "none", "cpu": "arm64" }, "sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg=="],
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.54.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw=="],
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.54.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ=="],
"@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.54.0", "", { "os": "win32", "cpu": "x64" }, "sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ=="],
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.54.0", "", { "os": "win32", "cpu": "x64" }, "sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg=="],
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
"@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.8", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-esgN+54+q0NjB0Y/4BomT9samII7jGwNy/2a3wNZbT2A2RpmXsXwUt24LvLhx6jUq2gVk4cWEvcRO6MFQbOfNA=="],
"@sveltejs/kit": ["@sveltejs/kit@2.49.2", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/cookie": "^0.6.0", "acorn": "^8.14.1", "cookie": "^0.6.0", "devalue": "^5.3.2", "esm-env": "^1.2.2", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "sade": "^1.8.1", "set-cookie-parser": "^2.6.0", "sirv": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["@opentelemetry/api"], "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-Vp3zX/qlwerQmHMP6x0Ry1oY7eKKRcOWGc2P59srOp4zcqyn+etJyQpELgOi4+ZSUgteX8Y387NuwruLgGXLUQ=="],
"@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@6.2.1", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0", "debug": "^4.4.1", "deepmerge": "^4.3.1", "magic-string": "^0.30.17", "vitefu": "^1.1.1" }, "peerDependencies": { "svelte": "^5.0.0", "vite": "^6.3.0 || ^7.0.0" } }, "sha512-YZs/OSKOQAQCnJvM/P+F1URotNnYNeU3P2s4oIpzm1uFaqUEqRxUB0g5ejMjEb5Gjb9/PiBI5Ktrq4rUUF8UVQ=="],
"@sveltejs/vite-plugin-svelte-inspector": ["@sveltejs/vite-plugin-svelte-inspector@5.0.1", "", { "dependencies": { "debug": "^4.4.1" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^6.0.0-next.0", "svelte": "^5.0.0", "vite": "^6.3.0 || ^7.0.0" } }, "sha512-ubWshlMk4bc8mkwWbg6vNvCeT7lGQojE3ijDh3QTR6Zr/R+GXxsGbyH4PExEPpiFmqPhYiVSVmHBjUcVc1JIrA=="],
"@swc/helpers": ["@swc/helpers@0.5.18", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ=="],
"@tailwindcss/node": ["@tailwindcss/node@4.1.18", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.1.18" } }, "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ=="],
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.18", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.18", "@tailwindcss/oxide-darwin-arm64": "4.1.18", "@tailwindcss/oxide-darwin-x64": "4.1.18", "@tailwindcss/oxide-freebsd-x64": "4.1.18", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", "@tailwindcss/oxide-linux-x64-musl": "4.1.18", "@tailwindcss/oxide-wasm32-wasi": "4.1.18", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" } }, "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A=="],
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.18", "", { "os": "android", "cpu": "arm64" }, "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q=="],
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.18", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A=="],
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.18", "", { "os": "darwin", "cpu": "x64" }, "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw=="],
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.18", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA=="],
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18", "", { "os": "linux", "cpu": "arm" }, "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA=="],
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.18", "", { "os": "linux", "cpu": "arm64" }, "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw=="],
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.18", "", { "os": "linux", "cpu": "arm64" }, "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg=="],
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.18", "", { "os": "linux", "cpu": "x64" }, "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g=="],
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.18", "", { "os": "linux", "cpu": "x64" }, "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ=="],
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.18", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.0", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.4.0" }, "cpu": "none" }, "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA=="],
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.18", "", { "os": "win32", "cpu": "arm64" }, "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA=="],
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.18", "", { "os": "win32", "cpu": "x64" }, "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q=="],
"@tailwindcss/vite": ["@tailwindcss/vite@4.1.18", "", { "dependencies": { "@tailwindcss/node": "4.1.18", "@tailwindcss/oxide": "4.1.18", "tailwindcss": "4.1.18" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA=="],
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
"@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="],
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.51.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.51.0", "@typescript-eslint/type-utils": "8.51.0", "@typescript-eslint/utils": "8.51.0", "@typescript-eslint/visitor-keys": "8.51.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.2.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.51.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-XtssGWJvypyM2ytBnSnKtHYOGT+4ZwTnBVl36TA4nRO2f4PRNGz5/1OszHzcZCvcBMh+qb7I06uoCmLTRdR9og=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.51.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.51.0", "@typescript-eslint/types": "8.51.0", "@typescript-eslint/typescript-estree": "8.51.0", "@typescript-eslint/visitor-keys": "8.51.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-3xP4XzzDNQOIqBMWogftkwxhg5oMKApqY0BAflmLZiFYHqyhSOxv/cd/zPQLTcCXr4AkaKb25joocY0BD1WC6A=="],
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.51.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.51.0", "@typescript-eslint/types": "^8.51.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Luv/GafO07Z7HpiI7qeEW5NW8HUtZI/fo/kE0YbtQEFpJRUuR0ajcWfCE5bnMvL7QQFrmT/odMe8QZww8X2nfQ=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.51.0", "", { "dependencies": { "@typescript-eslint/types": "8.51.0", "@typescript-eslint/visitor-keys": "8.51.0" } }, "sha512-JhhJDVwsSx4hiOEQPeajGhCWgBMBwVkxC/Pet53EpBVs7zHHtayKefw1jtPaNRXpI9RA2uocdmpdfE7T+NrizA=="],
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.51.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Qi5bSy/vuHeWyir2C8u/uqGMIlIDu8fuiYWv48ZGlZ/k+PRPHtaAu7erpc7p5bzw2WNNSniuxoMSO4Ar6V9OXw=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.51.0", "", { "dependencies": { "@typescript-eslint/types": "8.51.0", "@typescript-eslint/typescript-estree": "8.51.0", "@typescript-eslint/utils": "8.51.0", "debug": "^4.3.4", "ts-api-utils": "^2.2.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-0XVtYzxnobc9K0VU7wRWg1yiUrw4oQzexCG2V2IDxxCxhqBMSMbjB+6o91A+Uc0GWtgjCa3Y8bi7hwI0Tu4n5Q=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.51.0", "", {}, "sha512-TizAvWYFM6sSscmEakjY3sPqGwxZRSywSsPEiuZF6d5GmGD9Gvlsv0f6N8FvAAA0CD06l3rIcWNbsN1e5F/9Ag=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.51.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.51.0", "@typescript-eslint/tsconfig-utils": "8.51.0", "@typescript-eslint/types": "8.51.0", "@typescript-eslint/visitor-keys": "8.51.0", "debug": "^4.3.4", "minimatch": "^9.0.4", "semver": "^7.6.0", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.2.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-1qNjGqFRmlq0VW5iVlcyHBbCjPB7y6SxpBkrbhNWMy/65ZoncXCEPJxkRZL8McrseNH6lFhaxCIaX+vBuFnRng=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.51.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.51.0", "@typescript-eslint/types": "8.51.0", "@typescript-eslint/typescript-estree": "8.51.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-11rZYxSe0zabiKaCP2QAwRf/dnmgFgvTmeDTtZvUvXG3UuAdg/GU02NExmmIXzz3vLGgMdtrIosI84jITQOxUA=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.51.0", "", { "dependencies": { "@typescript-eslint/types": "8.51.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-mM/JRQOzhVN1ykejrvwnBRV3+7yTKK8tVANVN3o1O0t0v7o+jqdVu9crPy5Y9dov15TJk/FTIgoUGHrTOVL3Zg=="],
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"ansis": ["ansis@4.2.0", "", {}, "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig=="],
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
"aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="],
"axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"bits-ui": ["bits-ui@2.15.2", "", { "dependencies": { "@floating-ui/core": "^1.7.1", "@floating-ui/dom": "^1.7.1", "esm-env": "^1.1.2", "runed": "^0.35.1", "svelte-toolbelt": "^0.10.6", "tabbable": "^6.2.0" }, "peerDependencies": { "@internationalized/date": "^3.8.1", "svelte": "^5.33.0" } }, "sha512-S8eDbFkZCN17kZ7J9fD3MRXziV9ozjdFt2D3vTr2bvXCl7BtrIqguYt2U/zrFgLdR2erwybvCKv0JXYn8uKLDQ=="],
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
"confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="],
"cookie": ["cookie@0.6.0", "", {}, "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="],
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
"cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="],
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
"deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
"dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
"devalue": ["devalue@5.6.1", "", {}, "sha512-jDwizj+IlEZBunHcOuuFVBnIMPAEHvTsJj0BcIp94xYguLRVBcXO853px/MyIJvbVzWdsGvrRweIUWJw8hBP7A=="],
"enhanced-resolve": ["enhanced-resolve@5.18.4", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q=="],
"esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.2", "@esbuild/android-arm": "0.27.2", "@esbuild/android-arm64": "0.27.2", "@esbuild/android-x64": "0.27.2", "@esbuild/darwin-arm64": "0.27.2", "@esbuild/darwin-x64": "0.27.2", "@esbuild/freebsd-arm64": "0.27.2", "@esbuild/freebsd-x64": "0.27.2", "@esbuild/linux-arm": "0.27.2", "@esbuild/linux-arm64": "0.27.2", "@esbuild/linux-ia32": "0.27.2", "@esbuild/linux-loong64": "0.27.2", "@esbuild/linux-mips64el": "0.27.2", "@esbuild/linux-ppc64": "0.27.2", "@esbuild/linux-riscv64": "0.27.2", "@esbuild/linux-s390x": "0.27.2", "@esbuild/linux-x64": "0.27.2", "@esbuild/netbsd-arm64": "0.27.2", "@esbuild/netbsd-x64": "0.27.2", "@esbuild/openbsd-arm64": "0.27.2", "@esbuild/openbsd-x64": "0.27.2", "@esbuild/openharmony-arm64": "0.27.2", "@esbuild/sunos-x64": "0.27.2", "@esbuild/win32-arm64": "0.27.2", "@esbuild/win32-ia32": "0.27.2", "@esbuild/win32-x64": "0.27.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="],
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
"eslint": ["eslint@9.39.2", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.2", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw=="],
"eslint-config-prettier": ["eslint-config-prettier@10.1.8", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w=="],
"eslint-plugin-svelte": ["eslint-plugin-svelte@3.13.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.6.1", "@jridgewell/sourcemap-codec": "^1.5.0", "esutils": "^2.0.3", "globals": "^16.0.0", "known-css-properties": "^0.37.0", "postcss": "^8.4.49", "postcss-load-config": "^3.1.4", "postcss-safe-parser": "^7.0.0", "semver": "^7.6.3", "svelte-eslint-parser": "^1.4.0" }, "peerDependencies": { "eslint": "^8.57.1 || ^9.0.0", "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" }, "optionalPeers": ["svelte"] }, "sha512-Ng+kV/qGS8P/isbNYVE3sJORtubB+yLEcYICMkUWNaDTb0SwZni/JhAYXh/Dz/q2eThUwWY0VMPZ//KYD1n3eQ=="],
"eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
"eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
"esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="],
"espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="],
"esquery": ["esquery@1.7.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g=="],
"esrap": ["esrap@2.2.1", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, "sha512-GiYWG34AN/4CUyaWAgunGt0Rxvr1PTMlGC0vvEov/uOQYWne2bpN03Um+k8jT+q3op33mKouP2zeJ6OlM+qeUg=="],
"esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="],
"estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
"exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="],
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
"fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
"file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="],
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
"flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
"flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
"globals": ["globals@17.0.0", "", {}, "sha512-gv5BeD2EssA793rlFWVPMMCqefTlpusw6/2TbAVMy0FzcG8wKJn4O+NqJ4+XWmmwrayJgw5TzrmWjFgmz1XPqw=="],
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
"ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
"import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
"inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="],
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
"is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="],
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
"jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
"js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="],
"json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
"json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
"kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],
"known-css-properties": ["known-css-properties@0.37.0", "", {}, "sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ=="],
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
"lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="],
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="],
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="],
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="],
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA=="],
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.2", "", { "os": "linux", "cpu": "arm" }, "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA=="],
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A=="],
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA=="],
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w=="],
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA=="],
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ=="],
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="],
"lilconfig": ["lilconfig@2.1.0", "", {}, "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="],
"local-pkg": ["local-pkg@1.1.2", "", { "dependencies": { "mlly": "^1.7.4", "pkg-types": "^2.3.0", "quansync": "^0.2.11" } }, "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A=="],
"locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="],
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
"lz-string": ["lz-string@1.5.0", "", { "bin": { "lz-string": "bin/bin.js" } }, "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ=="],
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"mlly": ["mlly@1.8.0", "", { "dependencies": { "acorn": "^8.15.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.1" } }, "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g=="],
"mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="],
"mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
"p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
"package-manager-detector": ["package-manager-detector@1.6.0", "", {}, "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA=="],
"parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
"pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="],
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
"postcss-load-config": ["postcss-load-config@3.1.4", "", { "dependencies": { "lilconfig": "^2.0.5", "yaml": "^1.10.2" }, "peerDependencies": { "postcss": ">=8.0.9", "ts-node": ">=9.0.0" }, "optionalPeers": ["postcss", "ts-node"] }, "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg=="],
"postcss-safe-parser": ["postcss-safe-parser@7.0.1", "", { "peerDependencies": { "postcss": "^8.4.31" } }, "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A=="],
"postcss-scss": ["postcss-scss@4.0.9", "", { "peerDependencies": { "postcss": "^8.4.29" } }, "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A=="],
"postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
"prettier": ["prettier@3.7.4", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA=="],
"prettier-plugin-svelte": ["prettier-plugin-svelte@3.4.1", "", { "peerDependencies": { "prettier": "^3.0.0", "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" } }, "sha512-xL49LCloMoZRvSwa6IEdN2GV6cq2IqpYGstYtMT+5wmml1/dClEoI0MZR78MiVPpu6BdQFfN0/y73yO6+br5Pg=="],
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
"quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="],
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
"rolldown": ["rolldown@1.0.0-beta.9-commit.d91dfb5", "", { "dependencies": { "@oxc-project/runtime": "0.71.0", "@oxc-project/types": "0.71.0", "@rolldown/pluginutils": "1.0.0-beta.9-commit.d91dfb5", "ansis": "^4.0.0" }, "optionalDependencies": { "@rolldown/binding-darwin-arm64": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-darwin-x64": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-freebsd-x64": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-linux-x64-musl": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-wasm32-wasi": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.9-commit.d91dfb5" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-FHkj6gGEiEgmAXQchglofvUUdwj2Oiw603Rs+zgFAnn9Cb7T7z3fiaEc0DbN3ja4wYkW6sF2rzMEtC1V4BGx/g=="],
"rollup": ["rollup@4.54.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.54.0", "@rollup/rollup-android-arm64": "4.54.0", "@rollup/rollup-darwin-arm64": "4.54.0", "@rollup/rollup-darwin-x64": "4.54.0", "@rollup/rollup-freebsd-arm64": "4.54.0", "@rollup/rollup-freebsd-x64": "4.54.0", "@rollup/rollup-linux-arm-gnueabihf": "4.54.0", "@rollup/rollup-linux-arm-musleabihf": "4.54.0", "@rollup/rollup-linux-arm64-gnu": "4.54.0", "@rollup/rollup-linux-arm64-musl": "4.54.0", "@rollup/rollup-linux-loong64-gnu": "4.54.0", "@rollup/rollup-linux-ppc64-gnu": "4.54.0", "@rollup/rollup-linux-riscv64-gnu": "4.54.0", "@rollup/rollup-linux-riscv64-musl": "4.54.0", "@rollup/rollup-linux-s390x-gnu": "4.54.0", "@rollup/rollup-linux-x64-gnu": "4.54.0", "@rollup/rollup-linux-x64-musl": "4.54.0", "@rollup/rollup-openharmony-arm64": "4.54.0", "@rollup/rollup-win32-arm64-msvc": "4.54.0", "@rollup/rollup-win32-ia32-msvc": "4.54.0", "@rollup/rollup-win32-x64-gnu": "4.54.0", "@rollup/rollup-win32-x64-msvc": "4.54.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw=="],
"runed": ["runed@0.35.1", "", { "dependencies": { "dequal": "^2.0.3", "esm-env": "^1.0.0", "lz-string": "^1.5.0" }, "peerDependencies": { "@sveltejs/kit": "^2.21.0", "svelte": "^5.7.0" }, "optionalPeers": ["@sveltejs/kit"] }, "sha512-2F4Q/FZzbeJTFdIS/PuOoPRSm92sA2LhzTnv6FXhCoENb3huf5+fDuNOg1LNvGOouy3u/225qxmuJvcV3IZK5Q=="],
"sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="],
"semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"set-cookie-parser": ["set-cookie-parser@2.7.2", "", {}, "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="],
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
"sirv": ["sirv@3.0.2", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
"strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
"style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="],
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
"svelte": ["svelte@5.46.1", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "devalue": "^5.5.0", "esm-env": "^1.2.1", "esrap": "^2.2.1", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-ynjfCHD3nP2el70kN5Pmg37sSi0EjOm9FgHYQdC4giWG/hzO3AatzXXJJgP305uIhGQxSufJLuYWtkY8uK/8RA=="],
"svelte-adapter-bun": ["svelte-adapter-bun@1.0.1", "", { "dependencies": { "rolldown": "^1.0.0-beta.38" }, "peerDependencies": { "@sveltejs/kit": "^2.4.0", "typescript": "^5" } }, "sha512-tNOvfm8BGgG+rmEA7hkmqtq07v7zoo4skLQc+hIoQ79J+1fkEMpJEA2RzCIe3aPc8JdrsMJkv3mpiZPMsgahjA=="],
"svelte-check": ["svelte-check@4.3.5", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-e4VWZETyXaKGhpkxOXP+B/d0Fp/zKViZoJmneZWe/05Y2aqSKj3YN2nLfYPJBQ87WEiY4BQCQ9hWGu9mPT1a1Q=="],
"svelte-eslint-parser": ["svelte-eslint-parser@1.4.1", "", { "dependencies": { "eslint-scope": "^8.2.0", "eslint-visitor-keys": "^4.0.0", "espree": "^10.0.0", "postcss": "^8.4.49", "postcss-scss": "^4.0.9", "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" }, "optionalPeers": ["svelte"] }, "sha512-1eqkfQ93goAhjAXxZiu1SaKI9+0/sxp4JIWQwUpsz7ybehRE5L8dNuz7Iry7K22R47p5/+s9EM+38nHV2OlgXA=="],
"svelte-toolbelt": ["svelte-toolbelt@0.10.6", "", { "dependencies": { "clsx": "^2.1.1", "runed": "^0.35.1", "style-to-object": "^1.0.8" }, "peerDependencies": { "svelte": "^5.30.2" } }, "sha512-YWuX+RE+CnWYx09yseAe4ZVMM7e7GRFZM6OYWpBKOb++s+SQ8RBIMMe+Bs/CznBMc0QPLjr+vDBxTAkozXsFXQ=="],
"tabbable": ["tabbable@6.4.0", "", {}, "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg=="],
"tailwind-merge": ["tailwind-merge@3.4.0", "", {}, "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g=="],
"tailwindcss": ["tailwindcss@4.1.18", "", {}, "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw=="],
"tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="],
"tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="],
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
"totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="],
"ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="],
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"typescript-eslint": ["typescript-eslint@8.51.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.51.0", "@typescript-eslint/parser": "8.51.0", "@typescript-eslint/typescript-estree": "8.51.0", "@typescript-eslint/utils": "8.51.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-jh8ZuM5oEh2PSdyQG9YAEM1TCGuWenLSuSUhf/irbVUNW9O5FhbFVONviN2TgMTBnUmyHv7E56rYnfLZK6TkiA=="],
"ufo": ["ufo@1.6.1", "", {}, "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA=="],
"unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="],
"unplugin-icons": ["unplugin-icons@22.5.0", "", { "dependencies": { "@antfu/install-pkg": "^1.1.0", "@iconify/utils": "^3.0.2", "debug": "^4.4.3", "local-pkg": "^1.1.2", "unplugin": "^2.3.10" }, "peerDependencies": { "@svgr/core": ">=7.0.0", "@svgx/core": "^1.0.1", "@vue/compiler-sfc": "^3.0.2 || ^2.7.0", "svelte": "^3.0.0 || ^4.0.0 || ^5.0.0", "vue-template-compiler": "^2.6.12", "vue-template-es2015-compiler": "^1.9.0" }, "optionalPeers": ["@svgr/core", "@svgx/core", "@vue/compiler-sfc", "svelte", "vue-template-compiler", "vue-template-es2015-compiler"] }, "sha512-MBlMtT5RuMYZy4TZgqUL2OTtOdTUVsS1Mhj6G1pEzMlFJlEnq6mhUfoIt45gBWxHcsOdXJDWLg3pRZ+YmvAVWQ=="],
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
"vite": ["vite@7.3.0", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg=="],
"vitefu": ["vitefu@1.1.1", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ=="],
"webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="],
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
"word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
"yaml": ["yaml@1.10.2", "", {}, "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="],
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
"zimmerframe": ["zimmerframe@1.1.4", "", {}, "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ=="],
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
"@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="],
"@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
"@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"eslint-plugin-svelte/globals": ["globals@16.5.0", "", {}, "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ=="],
"mlly/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"mlly/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
}
}
+32
View File
@@ -0,0 +1,32 @@
import js from "@eslint/js";
import ts from "typescript-eslint";
import svelte from "eslint-plugin-svelte";
import prettier from "eslint-config-prettier";
import globals from "globals";
export default ts.config(
js.configs.recommended,
...ts.configs.recommended,
...svelte.configs["flat/recommended"],
prettier,
...svelte.configs["flat/prettier"],
{
languageOptions: {
globals: {
...globals.browser,
...globals.node,
},
},
},
{
files: ["**/*.svelte"],
languageOptions: {
parserOptions: {
parser: ts.parser,
},
},
},
{
ignores: ["build/", ".svelte-kit/", "dist/"],
},
);
+13 -16
View File
@@ -1,45 +1,42 @@
{ {
"name": "@xevion/web",
"private": true, "private": true,
"version": "0.0.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite dev --port 5000", "dev": "vite dev",
"build": "vite build", "build": "vite build",
"preview": "vite preview --port 5000", "preview": "vite preview",
"start": "node build/index.js",
"prepare": "svelte-kit sync || echo ''", "prepare": "svelte-kit sync || echo ''",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"deploy": "echo 'Use Docker deployment'", "clean": "rm -rf .svelte-kit build node_modules",
"clean": "rm -rf .svelte-kit build .turbo node_modules" "lint": "eslint .",
"format": "prettier --write ."
}, },
"dependencies": { "dependencies": {
"@fontsource-variable/inter": "^5.1.0", "@fontsource-variable/inter": "^5.1.0",
"@fontsource/hanken-grotesk": "^5.1.0", "@fontsource/hanken-grotesk": "^5.1.0",
"@fontsource/schibsted-grotesk": "^5.2.8", "@fontsource/schibsted-grotesk": "^5.2.8",
"@xevion/db": "workspace:*",
"bits-ui": "^2.8.2", "bits-ui": "^2.8.2",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"drizzle-orm": "^0.44.7",
"p5": "^1.11.7",
"pino": "^9.6.0",
"pino-pretty": "^13.0.0",
"postgres": "^3.4.5",
"svelte-wrap-balancer": "^0.0.4",
"tailwind-merge": "^3.3.1" "tailwind-merge": "^3.3.1"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.39.2",
"@iconify/json": "^2.2.424", "@iconify/json": "^2.2.424",
"@sveltejs/adapter-node": "^5.2.9",
"@sveltejs/kit": "^2.21.0", "@sveltejs/kit": "^2.21.0",
"@sveltejs/vite-plugin-svelte": "^6.2.1", "@sveltejs/vite-plugin-svelte": "^6.2.1",
"@tailwindcss/vite": "^4.1.11", "@tailwindcss/vite": "^4.1.11",
"@types/p5": "^1.7.7", "eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-svelte": "^3.13.1",
"globals": "^17.0.0",
"prettier": "^3.7.4",
"prettier-plugin-svelte": "^3.4.1",
"svelte": "^5.45.6", "svelte": "^5.45.6",
"svelte-adapter-bun": "^1.0.1", "svelte-adapter-bun": "^1.0.1",
"svelte-check": "^4.3.4", "svelte-check": "^4.3.4",
"tailwindcss": "^4.1.11", "tailwindcss": "^4.1.11",
"typescript-eslint": "^8.51.0",
"unplugin-icons": "^22.5.0", "unplugin-icons": "^22.5.0",
"vite": "^7.2.6" "vite": "^7.2.6"
} }
+11
View File
@@ -0,0 +1,11 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>
@@ -15,9 +15,7 @@
</script> </script>
<div class="pointer-events-none fixed inset-0 -z-20 bg-black"></div> <div class="pointer-events-none fixed inset-0 -z-20 bg-black"></div>
<Dots class={[ <Dots class={[backgroundClass]} />
backgroundClass
]} />
<main class={cn("relative min-h-screen text-zinc-50", className)}> <main class={cn("relative min-h-screen text-zinc-50", className)}>
{#if children} {#if children}
{@render children()} {@render children()}
+398
View File
@@ -0,0 +1,398 @@
<script lang="ts">
import { cn } from "$lib/utils";
import type { ClassValue } from "clsx";
import { onMount, onDestroy } from "svelte";
let {
class: className = "",
scale = 1000,
length = 10,
spacing = 20,
timeScale = 10.25 / 1000,
angleTimeScale = 2.0,
lengthTimeScale = 1.5,
opacity = 0.9,
radius = 3.5,
angleOpacityAmplitude = 0.8,
angleOpacityFloor = 0.1,
randomOpacityMin = 0.5,
randomOpacityMax = 1.0,
dotColor = [200 / 255, 200 / 255, 200 / 255] as [number, number, number],
}: {
class?: ClassValue;
scale?: number;
length?: number;
spacing?: number;
timeScale?: number;
angleTimeScale?: number;
lengthTimeScale?: number;
opacity?: number;
radius?: number;
angleOpacityAmplitude?: number;
angleOpacityFloor?: number;
randomOpacityMin?: number;
randomOpacityMax?: number;
dotColor?: [number, number, number];
} = $props();
let canvas: HTMLCanvasElement;
let cleanupFns: (() => void)[] = [];
function addCleanup(fn: () => void) {
cleanupFns.push(fn);
}
class UniformManager {
private gl: WebGLRenderingContext;
private locations = new Map<string, WebGLUniformLocation>();
constructor(
gl: WebGLRenderingContext,
program: WebGLProgram,
uniforms: string[],
) {
this.gl = gl;
uniforms.forEach((name) => {
const loc = gl.getUniformLocation(program, name);
if (loc) this.locations.set(name, loc);
});
}
set(
name: string,
value: number | [number, number] | [number, number, number],
) {
const loc = this.locations.get(name);
if (!loc) return;
if (Array.isArray(value)) {
if (value.length === 2) {
this.gl.uniform2f(loc, value[0], value[1]);
} else if (value.length === 3) {
this.gl.uniform3f(loc, value[0], value[1], value[2]);
}
} else {
this.gl.uniform1f(loc, value);
}
}
setStatic(values: Record<string, number>) {
Object.entries(values).forEach(([name, value]) => this.set(name, value));
}
}
const vertexShader = `
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0.0, 1.0);
}
`;
const fragmentShader = `
precision mediump float;
uniform vec2 u_resolution;
uniform float u_time;
uniform float u_seed;
uniform float u_dpr;
uniform float u_scale;
uniform float u_length;
uniform float u_spacing;
uniform float u_opacity;
uniform float u_radius;
uniform float u_angleTimeScale;
uniform float u_lengthTimeScale;
uniform float u_angleOpacityAmp;
uniform float u_angleOpacityFloor;
uniform float u_randomOpacityMin;
uniform float u_randomOpacityMax;
uniform vec3 u_dotColor;
const float PI = 3.14159265359;
// Simplex 3D noise
vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec4 permute(vec4 x) { return mod289(((x*34.0)+1.0)*x); }
vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }
float snoise(vec3 v) {
const vec2 C = vec2(1.0/6.0, 1.0/3.0);
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
vec3 i = floor(v + dot(v, C.yyy));
vec3 x0 = v - i + dot(i, C.xxx);
vec3 g = step(x0.yzx, x0.xyz);
vec3 l = 1.0 - g;
vec3 i1 = min(g.xyz, l.zxy);
vec3 i2 = max(g.xyz, l.zxy);
vec3 x1 = x0 - i1 + C.xxx;
vec3 x2 = x0 - i2 + C.yyy;
vec3 x3 = x0 - D.yyy;
i = mod289(i + u_seed);
vec4 p = permute(permute(permute(
i.z + vec4(0.0, i1.z, i2.z, 1.0))
+ i.y + vec4(0.0, i1.y, i2.y, 1.0))
+ i.x + vec4(0.0, i1.x, i2.x, 1.0));
float n_ = 0.142857142857;
vec3 ns = n_ * D.wyz - D.xzx;
vec4 j = p - 49.0 * floor(p * ns.z * ns.z);
vec4 x_ = floor(j * ns.z);
vec4 y_ = floor(j - 7.0 * x_);
vec4 x = x_ *ns.x + ns.yyyy;
vec4 y = y_ *ns.x + ns.yyyy;
vec4 h = 1.0 - abs(x) - abs(y);
vec4 b0 = vec4(x.xy, y.xy);
vec4 b1 = vec4(x.zw, y.zw);
vec4 s0 = floor(b0)*2.0 + 1.0;
vec4 s1 = floor(b1)*2.0 + 1.0;
vec4 sh = -step(h, vec4(0.0));
vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy;
vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww;
vec3 p0 = vec3(a0.xy, h.x);
vec3 p1 = vec3(a0.zw, h.y);
vec3 p2 = vec3(a1.xy, h.z);
vec3 p3 = vec3(a1.zw, h.w);
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2,p2), dot(p3,p3)));
p0 *= norm.x;
p1 *= norm.y;
p2 *= norm.z;
p3 *= norm.w;
vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
m = m * m;
return 42.0 * dot(m*m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3)));
}
float hash(vec2 p) {
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
}
float noise01(vec3 v) {
return (snoise(v) + 1.0) * 0.5;
}
void main() {
vec2 pixelCoord = gl_FragCoord.xy;
float spacing = u_spacing * u_dpr;
float scaleDpr = u_scale * u_dpr;
vec2 gridCoord = floor(pixelCoord / spacing) * spacing;
float minDist = 1000000.0;
float closestRad = 0.0;
float pointOpacity = 0.0;
// Check 9 neighboring grid points
for (float dx = -1.0; dx <= 1.0; dx += 1.0) {
for (float dy = -1.0; dy <= 1.0; dy += 1.0) {
vec2 testGrid = gridCoord + vec2(dx * spacing, dy * spacing);
float rad = (noise01(vec3(testGrid / scaleDpr, u_time * u_angleTimeScale)) - 0.5) * 4.0 * PI;
float len = (noise01(vec3(testGrid / scaleDpr, u_time * u_lengthTimeScale)) + 0.5) * u_length * u_dpr;
vec2 displacedPoint = testGrid + vec2(cos(rad), sin(rad)) * len;
float dist = distance(pixelCoord, displacedPoint);
if (dist < minDist) {
minDist = dist;
closestRad = rad;
pointOpacity = hash(testGrid) * (u_randomOpacityMax - u_randomOpacityMin) + u_randomOpacityMin;
}
}
}
float circle = 1.0 - smoothstep(0.0, u_radius * u_dpr, minDist);
float angleOpacity = (abs(cos(closestRad)) * u_angleOpacityAmp + u_angleOpacityFloor) * pointOpacity * u_opacity;
gl_FragColor = vec4(u_dotColor, circle * angleOpacity);
}
`;
function createShader(
gl: WebGLRenderingContext,
type: number,
source: string,
): WebGLShader | null {
const shader = gl.createShader(type);
if (!shader) return null;
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error("Shader compile error:", gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
function createProgram(
gl: WebGLRenderingContext,
vertexShader: WebGLShader,
fragmentShader: WebGLShader,
): WebGLProgram | null {
const program = gl.createProgram();
if (!program) return null;
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error("Program link error:", gl.getProgramInfoLog(program));
gl.deleteProgram(program);
return null;
}
return program;
}
function initWebGL(canvas: HTMLCanvasElement) {
const gl = canvas.getContext("webgl", {
alpha: true,
premultipliedAlpha: false,
});
if (!gl) {
console.error("WebGL not supported");
return null;
}
const vShader = createShader(gl, gl.VERTEX_SHADER, vertexShader);
const fShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShader);
if (!vShader || !fShader) {
console.error("Shader compilation failed");
return null;
}
const program = createProgram(gl, vShader, fShader);
if (!program) {
console.error("Program linking failed");
return null;
}
return { gl, program };
}
onMount(() => {
const context = initWebGL(canvas);
if (!context) return;
const { gl, program } = context;
// Setup fullscreen quad geometry
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]),
gl.STATIC_DRAW,
);
const positionLocation = gl.getAttribLocation(program, "a_position");
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
// Setup uniform manager
const uniforms = new UniformManager(gl, program, [
"u_resolution",
"u_time",
"u_seed",
"u_dpr",
"u_scale",
"u_length",
"u_spacing",
"u_opacity",
"u_radius",
"u_angleTimeScale",
"u_lengthTimeScale",
"u_angleOpacityAmp",
"u_angleOpacityFloor",
"u_randomOpacityMin",
"u_randomOpacityMax",
"u_dotColor",
]);
gl.useProgram(program);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
const dpr = window.devicePixelRatio || 1;
// Set static uniforms
uniforms.setStatic({
u_seed: Math.random() * 1000,
u_dpr: dpr,
u_scale: scale,
u_length: length,
u_spacing: spacing,
u_opacity: opacity,
u_radius: radius,
u_angleTimeScale: angleTimeScale,
u_lengthTimeScale: lengthTimeScale,
u_angleOpacityAmp: angleOpacityAmplitude,
u_angleOpacityFloor: angleOpacityFloor,
u_randomOpacityMin: randomOpacityMin,
u_randomOpacityMax: randomOpacityMax,
});
uniforms.set("u_dotColor", dotColor);
const resizeCanvas = () => {
canvas.width = window.innerWidth * dpr;
canvas.height = window.innerHeight * dpr;
canvas.style.width = `${window.innerWidth}px`;
canvas.style.height = `${window.innerHeight}px`;
gl.viewport(0, 0, canvas.width, canvas.height);
};
resizeCanvas();
window.addEventListener("resize", resizeCanvas);
addCleanup(() => window.removeEventListener("resize", resizeCanvas));
const startTime = Date.now();
let animationId: number;
function render() {
const time = ((Date.now() - startTime) / 1000) * timeScale;
uniforms.set("u_resolution", [canvas.width, canvas.height]);
uniforms.set("u_time", time);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 6);
animationId = requestAnimationFrame(render);
}
render();
addCleanup(() => cancelAnimationFrame(animationId));
addCleanup(() => gl.getExtension("WEBGL_lose_context")?.loseContext());
});
onDestroy(() => {
cleanupFns.forEach((fn) => fn());
});
</script>
<canvas
bind:this={canvas}
class={cn("pointer-events-none fixed inset-0 -z-10", className)}
></canvas>
@@ -5,7 +5,7 @@
import IconSimpleIconsDiscord from "~icons/simple-icons/discord"; import IconSimpleIconsDiscord from "~icons/simple-icons/discord";
import MaterialSymbolsMailRounded from "~icons/material-symbols/mail-rounded"; import MaterialSymbolsMailRounded from "~icons/material-symbols/mail-rounded";
import MaterialSymbolsVpnKey from "~icons/material-symbols/vpn-key"; import MaterialSymbolsVpnKey from "~icons/material-symbols/vpn-key";
import IconLucideRss from "~icons/lucide/rss"; // import IconLucideRss from "~icons/lucide/rss";
</script> </script>
<AppWrapper class="overflow-x-hidden font-schibsted"> <AppWrapper class="overflow-x-hidden font-schibsted">
@@ -57,13 +57,13 @@
<IconSimpleIconsLinkedin class="size-4 text-zinc-300" /> <IconSimpleIconsLinkedin class="size-4 text-zinc-300" />
<span class="text-sm text-zinc-100">LinkedIn</span> <span class="text-sm text-zinc-100">LinkedIn</span>
</a> </a>
<a <button
href="#" type="button"
class="flex items-center gap-x-1.5 px-1.5 py-1 rounded-sm bg-zinc-900 shadow-sm hover:bg-zinc-800 transition-colors" class="flex items-center gap-x-1.5 px-1.5 py-1 rounded-sm bg-zinc-900 shadow-sm hover:bg-zinc-800 transition-colors"
> >
<IconSimpleIconsDiscord class="size-4 text-zinc-300" /> <IconSimpleIconsDiscord class="size-4 text-zinc-300" />
<span class="text-sm text-zinc-100">Discord</span> <span class="text-sm text-zinc-100">Discord</span>
</a> </button>
<a <a
href="mailto:your.email@example.com" href="mailto:your.email@example.com"
class="flex items-center gap-x-1.5 px-1.5 py-1 rounded-sm bg-zinc-900 shadow-sm hover:bg-zinc-800 transition-colors" class="flex items-center gap-x-1.5 px-1.5 py-1 rounded-sm bg-zinc-900 shadow-sm hover:bg-zinc-800 transition-colors"
@@ -71,13 +71,13 @@
<MaterialSymbolsMailRounded class="size-4.5 text-zinc-300" /> <MaterialSymbolsMailRounded class="size-4.5 text-zinc-300" />
<span class="text-sm text-zinc-100">Email</span> <span class="text-sm text-zinc-100">Email</span>
</a> </a>
<a <button
href="#" type="button"
class="flex items-center gap-x-1.5 px-1.5 py-1 rounded-sm bg-zinc-900 shadow-sm hover:bg-zinc-800 transition-colors" class="flex items-center gap-x-1.5 px-1.5 py-1 rounded-sm bg-zinc-900 shadow-sm hover:bg-zinc-800 transition-colors"
> >
<MaterialSymbolsVpnKey class="size-4.5 text-zinc-300" /> <MaterialSymbolsVpnKey class="size-4.5 text-zinc-300" />
<span class="text-sm text-zinc-100">PGP Key</span> <span class="text-sm text-zinc-100">PGP Key</span>
</a> </button>
</div> </div>
</div> </div>
</div> </div>
+21
View File
@@ -0,0 +1,21 @@
import type { PageServerLoad } from "./$types";
interface ProjectLink {
url: string;
title?: string;
}
export interface Project {
id: string;
name: string;
shortDescription: string;
icon?: string;
links: ProjectLink[];
}
export const load: PageServerLoad = async () => {
// TODO: Fetch from Rust backend API
return {
projects: [] as Project[],
};
};
@@ -1,6 +1,5 @@
<script lang="ts"> <script lang="ts">
import AppWrapper from "$lib/components/AppWrapper.svelte"; import AppWrapper from "$lib/components/AppWrapper.svelte";
import Balancer from "svelte-wrap-balancer";
import { cn } from "$lib/utils"; import { cn } from "$lib/utils";
let { data } = $props(); let { data } = $props();
@@ -8,17 +7,17 @@
<AppWrapper> <AppWrapper>
<div <div
class="relative z-10 mx-auto grid grid-cols-1 justify-center gap-y-4 px-4 py-20 align-middle sm:grid-cols-2 md:max-w-[50rem] lg:max-w-[75rem] lg:grid-cols-3 lg:gap-y-9" class="relative z-10 mx-auto grid grid-cols-1 justify-center gap-y-4 px-4 py-20 align-middle sm:grid-cols-2 md:max-w-200 lg:max-w-300 lg:grid-cols-3 lg:gap-y-9"
> >
<div class="mb-3 text-center sm:col-span-2 md:mb-5 lg:col-span-3 lg:mb-7"> <div class="mb-3 text-center sm:col-span-2 md:mb-5 lg:col-span-3 lg:mb-7">
<h1 class="pb-3 font-hanken text-4xl text-zinc-200 opacity-100 md:text-5xl"> <h1
class="pb-3 font-hanken text-4xl text-zinc-200 opacity-100 md:text-5xl"
>
Projects Projects
</h1> </h1>
<Balancer> <p class="text-lg text-zinc-400">
<p class="text-lg text-zinc-400"> created, maintained, or contributed to by me...
created, maintained, or contributed to by me... </p>
</p>
</Balancer>
</div> </div>
{#each data.projects as project (project.id)} {#each data.projects as project (project.id)}
@@ -39,7 +38,7 @@
<i <i
class={cn( class={cn(
project.icon ?? "fa-heart", project.icon ?? "fa-heart",
"fa-solid text-3xl text-opacity-80 saturate-0" "fa-solid text-3xl text-opacity-80 saturate-0",
)} )}
></i> ></i>
</div> </div>
+7
View File
@@ -0,0 +1,7 @@
import { redirect } from "@sveltejs/kit";
import type { RequestHandler } from "./$types";
export const GET: RequestHandler = async () => {
// TODO: Fetch resume URL from Rust backend API
redirect(302, "https://example.com/resume.pdf");
};