Format with built in prettier format rules.

This commit is contained in:
Bradley Shellnut 2022-07-07 12:32:55 -07:00
parent ff536be706
commit 18e7cb1992
31 changed files with 870 additions and 890 deletions

View file

@ -1,20 +1,20 @@
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
plugins: ['svelte3', '@typescript-eslint'],
ignorePatterns: ['*.cjs'],
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
settings: {
'svelte3/typescript': () => require('typescript')
},
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020
},
env: {
browser: true,
es2017: true,
node: true
}
root: true,
parser: '@typescript-eslint/parser',
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
plugins: ['svelte3', '@typescript-eslint'],
ignorePatterns: ['*.cjs'],
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
settings: {
'svelte3/typescript': () => require('typescript')
},
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020
},
env: {
browser: true,
es2017: true,
node: true
}
};

View file

@ -1,6 +1,6 @@
{
"useTabs": false,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100
}
"useTabs": false,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100
}

View file

@ -1,6 +1,3 @@
{
"cSpell.words": [
"kickstarter",
"msrp"
]
}
"cSpell.words": ["kickstarter", "msrp"]
}

View file

@ -3,15 +3,15 @@
"version": "0.0.1",
"scripts": {
"dev": "vite dev --host",
"build": "vite build",
"package": "svelte-kit package",
"preview": "vite preview",
"prepare": "svelte-kit sync",
"test": "playwright test",
"check": "svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check --plugin-search-dir=. . && eslint .",
"format": "prettier --write --plugin-search-dir=. ."
"build": "vite build",
"package": "svelte-kit package",
"preview": "vite preview",
"prepare": "svelte-kit sync",
"test": "playwright test",
"check": "svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check --plugin-search-dir=. . && eslint .",
"format": "prettier --write --plugin-search-dir=. ."
},
"devDependencies": {
"@playwright/test": "^1.23.2",

View file

@ -1,10 +1,10 @@
import type { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
webServer: {
command: 'npm run build && npm run preview',
port: 3000
}
webServer: {
command: 'npm run build && npm run preview',
port: 3000
}
};
export default config;

View file

@ -1,103 +1,107 @@
@import '@fontsource/fira-mono';
:root {
font-family: Arial, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
--font-mono: 'Fira Mono', monospace;
--pure-white: #ffffff;
--primary-color: #b9c6d2;
--secondary-color: #d0dde9;
--tertiary-color: #edf0f8;
--accent-color: #ff3e00;
--heading-color: rgba(0, 0, 0, 0.7);
--text-color: #444444;
--background-without-opacity: rgba(255, 255, 255, 0.7);
--column-width: 42rem;
--column-margin-top: 4rem;
font-family: Arial, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
--font-mono: 'Fira Mono', monospace;
--pure-white: #ffffff;
--primary-color: #b9c6d2;
--secondary-color: #d0dde9;
--tertiary-color: #edf0f8;
--accent-color: #ff3e00;
--heading-color: rgba(0, 0, 0, 0.7);
--text-color: #444444;
--background-without-opacity: rgba(255, 255, 255, 0.7);
--column-width: 42rem;
--column-margin-top: 4rem;
}
body {
min-height: 100vh;
margin: 0;
background-color: var(--primary-color);
background: linear-gradient(180deg,
var(--primary-color) 0%,
var(--secondary-color) 10.45%,
var(--tertiary-color) 41.35%);
min-height: 100vh;
margin: 0;
background-color: var(--primary-color);
background: linear-gradient(
180deg,
var(--primary-color) 0%,
var(--secondary-color) 10.45%,
var(--tertiary-color) 41.35%
);
}
body::before {
content: '';
width: 80vw;
height: 100vh;
position: absolute;
top: 0;
left: 10vw;
z-index: -1;
background: radial-gradient(50% 50% at 50% 50%,
var(--pure-white) 0%,
rgba(255, 255, 255, 0) 100%);
opacity: 0.05;
content: '';
width: 80vw;
height: 100vh;
position: absolute;
top: 0;
left: 10vw;
z-index: -1;
background: radial-gradient(
50% 50% at 50% 50%,
var(--pure-white) 0%,
rgba(255, 255, 255, 0) 100%
);
opacity: 0.05;
}
#svelte {
min-height: 100vh;
display: flex;
flex-direction: column;
min-height: 100vh;
display: flex;
flex-direction: column;
}
h1,
h2,
p {
font-weight: 400;
color: var(--heading-color);
font-weight: 400;
color: var(--heading-color);
}
p {
line-height: 1.5;
line-height: 1.5;
}
a {
color: var(--accent-color);
text-decoration: none;
color: var(--accent-color);
text-decoration: none;
}
a:hover {
text-decoration: underline;
text-decoration: underline;
}
h1 {
font-size: 2rem;
text-align: center;
font-size: 2rem;
text-align: center;
}
h2 {
font-size: 1rem;
font-size: 1rem;
}
pre {
font-size: 16px;
font-family: var(--font-mono);
background-color: rgba(255, 255, 255, 0.45);
border-radius: 3px;
box-shadow: 2px 2px 6px rgb(255 255 255 / 25%);
padding: 0.5em;
overflow-x: auto;
color: var(--text-color);
font-size: 16px;
font-family: var(--font-mono);
background-color: rgba(255, 255, 255, 0.45);
border-radius: 3px;
box-shadow: 2px 2px 6px rgb(255 255 255 / 25%);
padding: 0.5em;
overflow-x: auto;
color: var(--text-color);
}
input,
button {
font-size: inherit;
font-family: inherit;
font-size: inherit;
font-family: inherit;
}
button:focus:not(:focus-visible) {
outline: none;
outline: none;
}
@media (min-width: 720px) {
h1 {
font-size: 2.4rem;
}
}
h1 {
font-size: 2.4rem;
}
}

8
src/app.d.ts vendored
View file

@ -4,8 +4,8 @@
// for information about these interfaces
// and what to do when importing types
declare namespace App {
// interface Locals {}
// interface Platform {}
// interface Session {}
// interface Stuff {}
// interface Locals {}
// interface Platform {}
// interface Session {}
// interface Stuff {}
}

View file

@ -1,43 +1,41 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="description" content="Bored? Find a game! Bored Game!" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script>
const htmlElement = document.documentElement;
const userTheme = localStorage.theme;
const userFont = localStorage.font;
<head>
<meta charset="utf-8" />
<meta name="description" content="Bored? Find a game! Bored Game!" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script>
const htmlElement = document.documentElement
const userTheme = localStorage.theme
const userFont = localStorage.font
// check if the user set a theme
if (userTheme) {
htmlElement.dataset.theme = userTheme;
}
// check if the user set a theme
if (userTheme) {
htmlElement.dataset.theme = userTheme
}
// otherwise check for user preference
if (!userTheme && prefersDarkMode) {
htmlElement.dataset.theme = '🌛 Night';
localStorage.theme = '🌛 Night';
}
// otherwise check for user preference
if (!userTheme && prefersDarkMode) {
htmlElement.dataset.theme = '🌛 Night'
localStorage.theme = '🌛 Night'
}
if (!userTheme && prefersLightMode) {
htmlElement.dataset.theme = '☀️ Daylight';
localStorage.theme = '☀️ Daylight';
}
if (!userTheme && prefersLightMode) {
htmlElement.dataset.theme = '☀️ Daylight'
localStorage.theme = '☀️ Daylight'
}
// if nothing is set default to dark mode
if (!userTheme && !prefersDarkMode && !prefersLightMode) {
htmlElement.dataset.theme = '🌛 Night';
localStorage.theme = '🌛 Night';
}
</script>
%sveltekit.head%
</head>
// if nothing is set default to dark mode
if (!userTheme && !prefersDarkMode && !prefersLightMode) {
htmlElement.dataset.theme = '🌛 Night'
localStorage.theme = '🌛 Night'
}
</script>
%sveltekit.head%
</head>
<body>
<div id="svelte">%sveltekit.body%</div>
</body>
</html>
<body>
<div id="svelte">%sveltekit.body%</div>
</body>
</html>

View file

@ -3,22 +3,22 @@ import { v4 as uuid } from '@lukeed/uuid';
import type { Handle } from '@sveltejs/kit';
export const handle: Handle = async ({ event, resolve }) => {
const cookies = cookie.parse(event.request.headers.get('cookie') || '');
event.locals.userid = cookies.userid || uuid();
const cookies = cookie.parse(event.request.headers.get('cookie') || '');
event.locals.userid = cookies.userid || uuid();
const response = await resolve(event);
const response = await resolve(event);
if (!cookies.userid) {
// if this is the first time the user has visited this app,
// set a cookie so that we recognize them when they return
response.headers.set(
'set-cookie',
cookie.serialize('userid', event.locals.userid, {
path: '/',
httpOnly: true
})
);
}
if (!cookies.userid) {
// if this is the first time the user has visited this app,
// set a cookie so that we recognize them when they return
response.headers.set(
'set-cookie',
cookie.serialize('userid', event.locals.userid, {
path: '/',
httpOnly: true
})
);
}
return response;
return response;
};

View file

@ -1,103 +1,103 @@
<script lang="ts">
import { spring } from 'svelte/motion';
import { spring } from 'svelte/motion';
let count = 0;
let count = 0;
const displayed_count = spring();
$: displayed_count.set(count);
$: offset = modulo($displayed_count, 1);
const displayed_count = spring();
$: displayed_count.set(count);
$: offset = modulo($displayed_count, 1);
function modulo(n: number, m: number) {
// handle negative numbers
return ((n % m) + m) % m;
}
function modulo(n: number, m: number) {
// handle negative numbers
return ((n % m) + m) % m;
}
</script>
<div class="counter">
<button on:click={() => (count -= 1)} aria-label="Decrease the counter by one">
<svg aria-hidden="true" viewBox="0 0 1 1">
<path d="M0,0.5 L1,0.5" />
</svg>
</button>
<button on:click={() => (count -= 1)} aria-label="Decrease the counter by one">
<svg aria-hidden="true" viewBox="0 0 1 1">
<path d="M0,0.5 L1,0.5" />
</svg>
</button>
<div class="counter-viewport">
<div class="counter-digits" style="transform: translate(0, {100 * offset}%)">
<strong class="hidden" aria-hidden="true">{Math.floor($displayed_count + 1)}</strong>
<strong>{Math.floor($displayed_count)}</strong>
</div>
</div>
<div class="counter-viewport">
<div class="counter-digits" style="transform: translate(0, {100 * offset}%)">
<strong class="hidden" aria-hidden="true">{Math.floor($displayed_count + 1)}</strong>
<strong>{Math.floor($displayed_count)}</strong>
</div>
</div>
<button on:click={() => (count += 1)} aria-label="Increase the counter by one">
<svg aria-hidden="true" viewBox="0 0 1 1">
<path d="M0,0.5 L1,0.5 M0.5,0 L0.5,1" />
</svg>
</button>
<button on:click={() => (count += 1)} aria-label="Increase the counter by one">
<svg aria-hidden="true" viewBox="0 0 1 1">
<path d="M0,0.5 L1,0.5 M0.5,0 L0.5,1" />
</svg>
</button>
</div>
<style>
.counter {
display: flex;
border-top: 1px solid rgba(0, 0, 0, 0.1);
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
margin: 1rem 0;
}
.counter {
display: flex;
border-top: 1px solid rgba(0, 0, 0, 0.1);
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
margin: 1rem 0;
}
.counter button {
width: 2em;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
border: 0;
background-color: transparent;
touch-action: manipulation;
color: var(--text-color);
font-size: 2rem;
}
.counter button {
width: 2em;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
border: 0;
background-color: transparent;
touch-action: manipulation;
color: var(--text-color);
font-size: 2rem;
}
.counter button:hover {
background-color: var(--secondary-color);
}
.counter button:hover {
background-color: var(--secondary-color);
}
svg {
width: 25%;
height: 25%;
}
svg {
width: 25%;
height: 25%;
}
path {
vector-effect: non-scaling-stroke;
stroke-width: 2px;
stroke: var(--text-color);
}
path {
vector-effect: non-scaling-stroke;
stroke-width: 2px;
stroke: var(--text-color);
}
.counter-viewport {
width: 8em;
height: 4em;
overflow: hidden;
text-align: center;
position: relative;
}
.counter-viewport {
width: 8em;
height: 4em;
overflow: hidden;
text-align: center;
position: relative;
}
.counter-viewport strong {
position: absolute;
display: flex;
width: 100%;
height: 100%;
font-weight: 400;
color: var(--accent-color);
font-size: 4rem;
align-items: center;
justify-content: center;
}
.counter-viewport strong {
position: absolute;
display: flex;
width: 100%;
height: 100%;
font-weight: 400;
color: var(--accent-color);
font-size: 4rem;
align-items: center;
justify-content: center;
}
.counter-digits {
position: absolute;
width: 100%;
height: 100%;
}
.counter-digits {
position: absolute;
width: 100%;
height: 100%;
}
.hidden {
top: -100%;
user-select: none;
}
.hidden {
top: -100%;
user-select: none;
}
</style>

View file

@ -12,9 +12,9 @@
'🌛 Night': { name: '🌛 Night' },
'☀️ Daylight': { name: '☀️ Daylight' },
'🐺 Night Howl': { name: '🐺 Night Howl' },
'🧠 Night Mind': { name: '🧠 Night Mind' },
}
'🧠 Night Mind': { name: '🧠 Night Mind' }
};
let selectedTheme = getTheme() ?? themes['🌛 Night'];
function getTheme() {

View file

@ -3,82 +3,82 @@ import { invalidate } from '$app/navigation';
// this action (https://svelte.dev/tutorial/actions) allows us to
// progressively enhance a <form> that already works without JS
export function enhance(
form: HTMLFormElement,
{
pending,
error,
result
}: {
pending?: ({ data, form }: { data: FormData; form: HTMLFormElement }) => void;
error?: ({
data,
form,
response,
error
}: {
data: FormData;
form: HTMLFormElement;
response: Response | null;
error: Error | null;
}) => void;
result?: ({
data,
form,
response
}: {
data: FormData;
response: Response;
form: HTMLFormElement;
}) => void;
} = {}
form: HTMLFormElement,
{
pending,
error,
result
}: {
pending?: ({ data, form }: { data: FormData; form: HTMLFormElement }) => void;
error?: ({
data,
form,
response,
error
}: {
data: FormData;
form: HTMLFormElement;
response: Response | null;
error: Error | null;
}) => void;
result?: ({
data,
form,
response
}: {
data: FormData;
response: Response;
form: HTMLFormElement;
}) => void;
} = {}
) {
let current_token: unknown;
let current_token: unknown;
async function handle_submit(e: SubmitEvent) {
const token = (current_token = {});
async function handle_submit(e: SubmitEvent) {
const token = (current_token = {});
e.preventDefault();
e.preventDefault();
const data = new FormData(form);
const data = new FormData(form);
if (pending) pending({ data, form });
if (pending) pending({ data, form });
try {
const response = await fetch(form.action, {
method: form.method,
headers: {
accept: 'application/json'
},
body: data
});
try {
const response = await fetch(form.action, {
method: form.method,
headers: {
accept: 'application/json'
},
body: data
});
if (token !== current_token) return;
if (token !== current_token) return;
if (response.ok) {
if (result) result({ data, form, response });
if (response.ok) {
if (result) result({ data, form, response });
const url = new URL(form.action);
url.search = url.hash = '';
invalidate(url.href);
} else if (error) {
error({ data, form, error: null, response });
} else {
console.error(await response.text());
}
} catch (e: unknown) {
if (error && e instanceof Error) {
error({ data, form, error: e, response: null });
} else {
throw e;
}
}
}
const url = new URL(form.action);
url.search = url.hash = '';
invalidate(url.href);
} else if (error) {
error({ data, form, error: null, response });
} else {
console.error(await response.text());
}
} catch (e: unknown) {
if (error && e instanceof Error) {
error({ data, form, error: e, response: null });
} else {
throw e;
}
}
}
form.addEventListener('submit', handle_submit);
form.addEventListener('submit', handle_submit);
return {
destroy() {
form.removeEventListener('submit', handle_submit);
}
};
return {
destroy() {
form.removeEventListener('submit', handle_submit);
}
};
}

View file

@ -3,27 +3,27 @@ import { writable } from 'svelte/store';
// Custom store
const newToast = () => {
const { subscribe, update } = writable([]);
const { subscribe, update } = writable([]);
function send(message: string, { duration = 2000, type = 'INFO' } = {}) {
const id = Math.floor(Math.random() * 1000);
const newMessage = {
id,
duration,
type,
message
};
update((store) => [...store, newMessage]);
}
function send(message: string, { duration = 2000, type = 'INFO' } = {}) {
const id = Math.floor(Math.random() * 1000);
const newMessage = {
id,
duration,
type,
message
};
update((store) => [...store, newMessage]);
}
function remove(id: number) {
update((store) => {
const newStore = store.filter((item: ToastData) => item.id !== id);
return [...newStore];
});
}
function remove(id: number) {
update((store) => {
const newStore = store.filter((item: ToastData) => item.id !== id);
return [...newStore];
});
}
return { subscribe, send, remove };
return { subscribe, send, remove };
};
export const toast = newToast();

View file

@ -9,7 +9,7 @@ export type ToastData = {
duration: number;
type: ToastType;
message: string;
}
};
export type GameType = {
id: string;
@ -18,7 +18,7 @@ export type GameType = {
url: string;
edit_url: string;
thumb_url: string;
image_url: string,
image_url: string;
price: number;
price_ca: number;
price_uk: number;
@ -33,7 +33,7 @@ export type GameType = {
description: string;
players: string;
playtime: string;
}
};
export type SearchQuery = {
client_id: string;
@ -84,4 +84,4 @@ export type SearchQuery = {
lt_reddit_week_count?: number;
lt_reddit_day_count?: number;
fields?: string;
}
};

View file

@ -1,10 +1,10 @@
import { z } from "zod";
import { z } from 'zod';
export const BoardGameSearch = z.object({
minAge: z.number(),
maxAge: z.number(),
minPlayers: z.number(),
maxPlayers: z.number(),
maxPlayers: z.number()
});
export const Game = z.object({
@ -26,5 +26,5 @@ export const Game = z.object({
min_age: z.number(),
description: z.string(),
players: z.string(),
playtime: z.string(),
playtime: z.string()
});

View file

@ -9,14 +9,19 @@
guarantees are made. Don't use it to organize your life.)
*/
import { URLSearchParams } from "url";
import { URLSearchParams } from 'url';
const base = 'https://api.boardgameatlas.com/api';
export function boardGameApi(method: string, resource: string, queryParams: Record<string, string>, data?: Record<string, unknown>) {
export function boardGameApi(
method: string,
resource: string,
queryParams: Record<string, string>,
data?: Record<string, unknown>
) {
queryParams.client_id = import.meta.env.VITE_PUBLIC_CLIENT_ID;
const urlQueryParams = new URLSearchParams(queryParams)
const url = `${base}/${resource}${urlQueryParams ? `?${urlQueryParams}` : ''}`
const urlQueryParams = new URLSearchParams(queryParams);
const url = `${base}/${resource}${urlQueryParams ? `?${urlQueryParams}` : ''}`;
return fetch(url, {
method,
headers: {

View file

@ -1,50 +1,50 @@
<script context="module">
import { browser, dev } from '$app/env';
import { browser, dev } from '$app/env';
// we don't need any JS on this page, though we'll load
// it in dev so that we get hot module replacement...
export const hydrate = dev;
// we don't need any JS on this page, though we'll load
// it in dev so that we get hot module replacement...
export const hydrate = dev;
// ...but if the client-side router is already loaded
// (i.e. we came here from elsewhere in the app), use it
export const router = browser;
// ...but if the client-side router is already loaded
// (i.e. we came here from elsewhere in the app), use it
export const router = browser;
// since there's no dynamic data here, we can prerender
// it so that it gets served as a static asset in prod
export const prerender = true;
// since there's no dynamic data here, we can prerender
// it so that it gets served as a static asset in prod
export const prerender = true;
</script>
<svelte:head>
<title>About</title>
<title>About</title>
</svelte:head>
<div class="content">
<h1>About this app</h1>
<h1>About this app</h1>
<p>
This is a <a href="https://kit.svelte.dev">SvelteKit</a> app. You can make your own by typing the
following into your command line and following the prompts:
</p>
<p>
This is a <a href="https://kit.svelte.dev">SvelteKit</a> app. You can make your own by typing the
following into your command line and following the prompts:
</p>
<!-- TODO lose the @next! -->
<pre>npm init svelte@next</pre>
<!-- TODO lose the @next! -->
<pre>npm init svelte@next</pre>
<p>
The page you're looking at is purely static HTML, with no client-side interactivity needed.
Because of that, we don't need to load any JavaScript. Try viewing the page's source, or opening
the devtools network panel and reloading.
</p>
<p>
The page you're looking at is purely static HTML, with no client-side interactivity needed.
Because of that, we don't need to load any JavaScript. Try viewing the page's source, or opening
the devtools network panel and reloading.
</p>
<p>
The <a href="/todos">TODOs</a> page illustrates SvelteKit's data loading and form handling. Try using
it with JavaScript disabled!
</p>
<p>
The <a href="/todos">TODOs</a> page illustrates SvelteKit's data loading and form handling. Try using
it with JavaScript disabled!
</p>
</div>
<style>
.content {
width: 100%;
max-width: var(--column-width);
margin: var(--column-margin-top) auto 0 auto;
}
.content {
width: 100%;
max-width: var(--column-width);
margin: var(--column-margin-top) auto 0 auto;
}
</style>

View file

@ -1,5 +1,5 @@
import type { RequestHandler } from "@sveltejs/kit";
import type { SearchQuery } from "$lib/types";
import type { RequestHandler } from '@sveltejs/kit';
import type { SearchQuery } from '$lib/types';
export const post: RequestHandler = async ({ request }) => {
const form = await request.formData();
@ -8,8 +8,8 @@ export const post: RequestHandler = async ({ request }) => {
order_by: 'rank',
ascending: false,
limit: 20,
client_id: import.meta.env.VITE_PUBLIC_CLIENT_ID,
}
client_id: import.meta.env.VITE_PUBLIC_CLIENT_ID
};
const minAge = form.get('minAge');
const minPlayers = form.get('minPlayers');
@ -47,7 +47,7 @@ export const post: RequestHandler = async ({ request }) => {
if (exactMinPlayers) {
queryParams.min_players = +minPlayers;
} else {
queryParams.gt_min_players = (+minPlayers === 1 ? 0 : (+minPlayers - 1));
queryParams.gt_min_players = +minPlayers === 1 ? 0 : +minPlayers - 1;
}
}
@ -70,12 +70,14 @@ export const post: RequestHandler = async ({ request }) => {
const urlQueryParams = new URLSearchParams(newQueryParams);
const url = `https://api.boardgameatlas.com/api/search${urlQueryParams ? `?${urlQueryParams}` : ''}`
const url = `https://api.boardgameatlas.com/api/search${
urlQueryParams ? `?${urlQueryParams}` : ''
}`;
const response = await fetch(url, {
method: 'get',
headers: {
'content-type': 'application/json'
},
}
});
console.log('response', response);
if (response.status === 404) {
@ -94,7 +96,7 @@ export const post: RequestHandler = async ({ request }) => {
console.log('games', games);
return {
body: {
games: gameResponse?.games,
games: gameResponse?.games
}
};
}
@ -102,4 +104,4 @@ export const post: RequestHandler = async ({ request }) => {
return {
status: response.status
};
}
};

View file

@ -1,6 +1,6 @@
<script lang="ts">
import type { Game } from "$lib/types";
import { Checkbox, NumberInput } from "carbon-components-svelte";
import type { Game } from '$lib/types';
import { Checkbox, NumberInput } from 'carbon-components-svelte';
// import { enhance } from "$lib/form";
let games: Game[] = [];
@ -21,16 +21,15 @@ import { Checkbox, NumberInput } from "carbon-components-svelte";
}
let minAge = 0;
let minPlayers = 1;
let maxPlayers = 1;
let minPlayers = 1;
let maxPlayers = 1;
let exactMinAge = false;
let exactMinPlayers = false;
let exactMaxPlayers = false;
</script>
<svelte:head>
<title>Games</title>
<title>Games</title>
</svelte:head>
<h1>Search Boardgames!</h1>
@ -50,7 +49,12 @@ import { Checkbox, NumberInput } from "carbon-components-svelte";
invalidText="Number must be between 0 and 120"
label="Min Age"
/>
<Checkbox name="exactMinAge" bind:value={exactMinAge} labelText="Search exact?" bind:checked={exactMinAge} />
<Checkbox
name="exactMinAge"
bind:value={exactMinAge}
labelText="Search exact?"
bind:checked={exactMinAge}
/>
</div>
<div>
<NumberInput
@ -61,7 +65,12 @@ import { Checkbox, NumberInput } from "carbon-components-svelte";
invalidText="Number must be between 1 and 50"
label="Min Players"
/>
<Checkbox name="exactMinPlayers" labelText="Search exact?" bind:value={exactMinPlayers} bind:checked={exactMinPlayers} />
<Checkbox
name="exactMinPlayers"
labelText="Search exact?"
bind:value={exactMinPlayers}
bind:checked={exactMinPlayers}
/>
</div>
<div>
<NumberInput
@ -72,7 +81,12 @@ import { Checkbox, NumberInput } from "carbon-components-svelte";
invalidText="Number must be between 1 and 50"
label="Max Players"
/>
<Checkbox name="exactMaxPlayers" labelText="Search exact?" bind:value={exactMaxPlayers} bind:checked={exactMaxPlayers} />
<Checkbox
name="exactMaxPlayers"
labelText="Search exact?"
bind:value={exactMaxPlayers}
bind:checked={exactMaxPlayers}
/>
</div>
</fieldset>
<button type="submit" disabled={submitting}>Submit</button>
@ -86,22 +100,22 @@ import { Checkbox, NumberInput } from "carbon-components-svelte";
</div>
<div class="games">
<h1>Games</h1>
<h1>Games</h1>
{#each games as game}
<section>
<div>
<h2>{game.name}</h2>
<p>price : {game.price}</p>
<p>year_published : {game.year_published}</p>
<p>min_players : {game.min_players}</p>
<p>max_players : {game.max_players}</p>
<p>min_playtime : {game.min_playtime}</p>
<p>max_playtime : {game.max_playtime}</p>
<p>min_age : {game.min_age}</p>
<p>players : {game.players}</p>
<p>playtime : {game.playtime}</p>
<div class="description">{@html game.description}</div>
</div>
<div>
<h2>{game.name}</h2>
<p>price : {game.price}</p>
<p>year_published : {game.year_published}</p>
<p>min_players : {game.min_players}</p>
<p>max_players : {game.max_players}</p>
<p>min_playtime : {game.min_playtime}</p>
<p>max_playtime : {game.max_playtime}</p>
<p>min_age : {game.min_age}</p>
<p>players : {game.players}</p>
<p>playtime : {game.playtime}</p>
<div class="description">{@html game.description}</div>
</div>
</section>
{/each}
</div>
@ -124,7 +138,7 @@ import { Checkbox, NumberInput } from "carbon-components-svelte";
display: grid;
gap: 2rem;
}
.description {
margin: 1rem;
}
@ -139,4 +153,4 @@ import { Checkbox, NumberInput } from "carbon-components-svelte";
gap: 1rem;
grid-template-columns: repeat(3, minmax(200px, 1fr));
}
</style>
</style>

View file

@ -81,4 +81,4 @@ import { boardGameApi } from '../_api';
// return {
// status: response.status
// };
// }
// }

View file

@ -19,8 +19,8 @@ export const post: RequestHandler = async ({ request, locals }) => {
gt_min_players: String(+minPlayers === 1 ? 0 : +minPlayers - 1),
lt_max_players: String(+maxPlayers + 1),
gt_min_age: String(+minAge === 1 ? 0 : +minAge - 1),
lt_max_age: String(+maxAge + 1),
}
lt_max_age: String(+maxAge + 1)
};
const response = await boardGameApi('get', `search`, queryParams);
console.log('response', response);
if (response.status === 404) {
@ -39,7 +39,7 @@ export const post: RequestHandler = async ({ request, locals }) => {
console.log('games', games);
return {
body: {
games: gameResponse?.games,
games: gameResponse?.games
}
};
}
@ -47,4 +47,4 @@ export const post: RequestHandler = async ({ request, locals }) => {
return {
status: response.status
};
};
};

View file

@ -12,11 +12,11 @@
const base = 'https://api.svelte.dev';
export function api(method: string, resource: string, data?: Record<string, unknown>) {
return fetch(`${base}/${resource}`, {
method,
headers: {
'content-type': 'application/json'
},
body: data && JSON.stringify(data)
});
return fetch(`${base}/${resource}`, {
method,
headers: {
'content-type': 'application/json'
},
body: data && JSON.stringify(data)
});
}

View file

@ -1,186 +1,186 @@
<script lang="ts">
import { enhance } from '$lib/form';
import { scale } from 'svelte/transition';
import { flip } from 'svelte/animate';
import { enhance } from '$lib/form';
import { scale } from 'svelte/transition';
import { flip } from 'svelte/animate';
type Todo = {
uid: string;
created_at: Date;
text: string;
done: boolean;
pending_delete: boolean;
};
type Todo = {
uid: string;
created_at: Date;
text: string;
done: boolean;
pending_delete: boolean;
};
export let todos: Todo[];
export let todos: Todo[];
</script>
<svelte:head>
<title>Todos</title>
<title>Todos</title>
</svelte:head>
<div class="todos">
<h1>Todos</h1>
<h1>Todos</h1>
<form
class="new"
action="/todos"
method="post"
use:enhance={{
result: async ({ form }) => {
form.reset();
}
}}
>
<input name="text" aria-label="Add todo" placeholder="+ tap to add a todo" />
</form>
<form
class="new"
action="/todos"
method="post"
use:enhance={{
result: async ({ form }) => {
form.reset();
}
}}
>
<input name="text" aria-label="Add todo" placeholder="+ tap to add a todo" />
</form>
{#each todos as todo (todo.uid)}
<div
class="todo"
class:done={todo.done}
transition:scale|local={{ start: 0.7 }}
animate:flip={{ duration: 200 }}
>
<form
action="/todos?_method=PATCH"
method="post"
use:enhance={{
pending: ({ data }) => {
todo.done = !!data.get('done');
}
}}
>
<input type="hidden" name="uid" value={todo.uid} />
<input type="hidden" name="done" value={todo.done ? '' : 'true'} />
<button class="toggle" aria-label="Mark todo as {todo.done ? 'not done' : 'done'}" />
</form>
{#each todos as todo (todo.uid)}
<div
class="todo"
class:done={todo.done}
transition:scale|local={{ start: 0.7 }}
animate:flip={{ duration: 200 }}
>
<form
action="/todos?_method=PATCH"
method="post"
use:enhance={{
pending: ({ data }) => {
todo.done = !!data.get('done');
}
}}
>
<input type="hidden" name="uid" value={todo.uid} />
<input type="hidden" name="done" value={todo.done ? '' : 'true'} />
<button class="toggle" aria-label="Mark todo as {todo.done ? 'not done' : 'done'}" />
</form>
<form class="text" action="/todos?_method=PATCH" method="post" use:enhance>
<input type="hidden" name="uid" value={todo.uid} />
<input aria-label="Edit todo" type="text" name="text" value={todo.text} />
<button class="save" aria-label="Save todo" />
</form>
<form class="text" action="/todos?_method=PATCH" method="post" use:enhance>
<input type="hidden" name="uid" value={todo.uid} />
<input aria-label="Edit todo" type="text" name="text" value={todo.text} />
<button class="save" aria-label="Save todo" />
</form>
<form
action="/todos?_method=DELETE"
method="post"
use:enhance={{
pending: () => (todo.pending_delete = true)
}}
>
<input type="hidden" name="uid" value={todo.uid} />
<button class="delete" aria-label="Delete todo" disabled={todo.pending_delete} />
</form>
</div>
{/each}
<form
action="/todos?_method=DELETE"
method="post"
use:enhance={{
pending: () => (todo.pending_delete = true)
}}
>
<input type="hidden" name="uid" value={todo.uid} />
<button class="delete" aria-label="Delete todo" disabled={todo.pending_delete} />
</form>
</div>
{/each}
</div>
<style>
.todos {
width: 100%;
max-width: var(--column-width);
margin: var(--column-margin-top) auto 0 auto;
line-height: 1;
}
.todos {
width: 100%;
max-width: var(--column-width);
margin: var(--column-margin-top) auto 0 auto;
line-height: 1;
}
.new {
margin: 0 0 0.5rem 0;
}
.new {
margin: 0 0 0.5rem 0;
}
input {
border: 1px solid transparent;
}
input {
border: 1px solid transparent;
}
input:focus-visible {
box-shadow: inset 1px 1px 6px rgba(0, 0, 0, 0.1);
border: 1px solid #ff3e00 !important;
outline: none;
}
input:focus-visible {
box-shadow: inset 1px 1px 6px rgba(0, 0, 0, 0.1);
border: 1px solid #ff3e00 !important;
outline: none;
}
.new input {
font-size: 28px;
width: 100%;
padding: 0.5em 1em 0.3em 1em;
box-sizing: border-box;
background: rgba(255, 255, 255, 0.05);
border-radius: 8px;
text-align: center;
}
.new input {
font-size: 28px;
width: 100%;
padding: 0.5em 1em 0.3em 1em;
box-sizing: border-box;
background: rgba(255, 255, 255, 0.05);
border-radius: 8px;
text-align: center;
}
.todo {
display: grid;
grid-template-columns: 2rem 1fr 2rem;
grid-gap: 0.5rem;
align-items: center;
margin: 0 0 0.5rem 0;
padding: 0.5rem;
background-color: white;
border-radius: 8px;
filter: drop-shadow(2px 4px 6px rgba(0, 0, 0, 0.1));
transform: translate(-1px, -1px);
transition: filter 0.2s, transform 0.2s;
}
.todo {
display: grid;
grid-template-columns: 2rem 1fr 2rem;
grid-gap: 0.5rem;
align-items: center;
margin: 0 0 0.5rem 0;
padding: 0.5rem;
background-color: white;
border-radius: 8px;
filter: drop-shadow(2px 4px 6px rgba(0, 0, 0, 0.1));
transform: translate(-1px, -1px);
transition: filter 0.2s, transform 0.2s;
}
.done {
transform: none;
opacity: 0.4;
filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.1));
}
.done {
transform: none;
opacity: 0.4;
filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.1));
}
form.text {
position: relative;
display: flex;
align-items: center;
flex: 1;
}
form.text {
position: relative;
display: flex;
align-items: center;
flex: 1;
}
.todo input {
flex: 1;
padding: 0.5em 2em 0.5em 0.8em;
border-radius: 3px;
}
.todo input {
flex: 1;
padding: 0.5em 2em 0.5em 0.8em;
border-radius: 3px;
}
.todo button {
width: 2em;
height: 2em;
border: none;
background-color: transparent;
background-position: 50% 50%;
background-repeat: no-repeat;
}
.todo button {
width: 2em;
height: 2em;
border: none;
background-color: transparent;
background-position: 50% 50%;
background-repeat: no-repeat;
}
button.toggle {
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 50%;
box-sizing: border-box;
background-size: 1em auto;
}
button.toggle {
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 50%;
box-sizing: border-box;
background-size: 1em auto;
}
.done .toggle {
background-image: url("data:image/svg+xml,%3Csvg width='22' height='16' viewBox='0 0 22 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M20.5 1.5L7.4375 14.5L1.5 8.5909' stroke='%23676778' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
.done .toggle {
background-image: url("data:image/svg+xml,%3Csvg width='22' height='16' viewBox='0 0 22 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M20.5 1.5L7.4375 14.5L1.5 8.5909' stroke='%23676778' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
.delete {
background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4.5 5V22H19.5V5H4.5Z' fill='%23676778' stroke='%23676778' stroke-width='1.5' stroke-linejoin='round'/%3E%3Cpath d='M10 10V16.5' stroke='white' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M14 10V16.5' stroke='white' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M2 5H22' stroke='%23676778' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M8 5L9.6445 2H14.3885L16 5H8Z' fill='%23676778' stroke='%23676778' stroke-width='1.5' stroke-linejoin='round'/%3E%3C/svg%3E%0A");
opacity: 0.2;
}
.delete {
background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4.5 5V22H19.5V5H4.5Z' fill='%23676778' stroke='%23676778' stroke-width='1.5' stroke-linejoin='round'/%3E%3Cpath d='M10 10V16.5' stroke='white' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M14 10V16.5' stroke='white' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M2 5H22' stroke='%23676778' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M8 5L9.6445 2H14.3885L16 5H8Z' fill='%23676778' stroke='%23676778' stroke-width='1.5' stroke-linejoin='round'/%3E%3C/svg%3E%0A");
opacity: 0.2;
}
.delete:hover,
.delete:focus {
transition: opacity 0.2s;
opacity: 1;
}
.delete:hover,
.delete:focus {
transition: opacity 0.2s;
opacity: 1;
}
.save {
position: absolute;
right: 0;
opacity: 0;
background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M20.5 2H3.5C2.67158 2 2 2.67157 2 3.5V20.5C2 21.3284 2.67158 22 3.5 22H20.5C21.3284 22 22 21.3284 22 20.5V3.5C22 2.67157 21.3284 2 20.5 2Z' fill='%23676778' stroke='%23676778' stroke-width='1.5' stroke-linejoin='round'/%3E%3Cpath d='M17 2V11H7.5V2H17Z' fill='white' stroke='white' stroke-width='1.5' stroke-linejoin='round'/%3E%3Cpath d='M13.5 5.5V7.5' stroke='%23676778' stroke-width='1.5' stroke-linecap='round'/%3E%3Cpath d='M5.99844 2H18.4992' stroke='%23676778' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E%0A");
}
.save {
position: absolute;
right: 0;
opacity: 0;
background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M20.5 2H3.5C2.67158 2 2 2.67157 2 3.5V20.5C2 21.3284 2.67158 22 3.5 22H20.5C21.3284 22 22 21.3284 22 20.5V3.5C22 2.67157 21.3284 2 20.5 2Z' fill='%23676778' stroke='%23676778' stroke-width='1.5' stroke-linejoin='round'/%3E%3Cpath d='M17 2V11H7.5V2H17Z' fill='white' stroke='white' stroke-width='1.5' stroke-linejoin='round'/%3E%3Cpath d='M13.5 5.5V7.5' stroke='%23676778' stroke-width='1.5' stroke-linecap='round'/%3E%3Cpath d='M5.99844 2H18.4992' stroke='%23676778' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E%0A");
}
.todo input:focus + .save,
.save:focus {
transition: opacity 0.2s;
opacity: 1;
}
.todo input:focus + .save,
.save:focus {
transition: opacity 0.2s;
opacity: 1;
}
</style>

View file

@ -28,7 +28,7 @@
--yellow: #ffc600;
--light: #ffffff;
--dark: #000000;
--lightGrey: #C5C5C5;
--lightGrey: #c5c5c5;
--lightGray: var(--lightGrey);
--imGoingToFaint: #fbfbfb;
--redBrown: #633539;
@ -45,7 +45,7 @@
--headerBackground: var(--greyBlue);
--footerBackground: var(--darkGrey);
--linkHover: var(--white);
--lightHairLine: #C5C5C5;
--lightHairLine: #c5c5c5;
--radius-base: 1rem;
@ -79,12 +79,9 @@
/* Elevation */
--level-0: none;
--level-1: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
--level-2: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
0 2px 4px -1px rgba(0, 0, 0, 0.06);
--level-3: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
0 4px 6px -2px rgba(0, 0, 0, 0.05);
--level-4: 0 20px 25px -5px rgba(0, 0, 0, 0.1),
0 10px 10px -5px rgba(0, 0, 0, 0.04);
--level-2: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--level-3: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
--level-4: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
/* Z Indexes */
--zBase: 1;
@ -150,7 +147,6 @@ body {
height: 100%;
}
::-webkit-scrollbar {
width: 4px;
height: 4px;
@ -175,7 +171,7 @@ body {
font-size: var(--font-18);
color: var(--color-text-primary);
// background-color: var(--color-bg-primary);
background-color: #2D3A3A;
background-color: #2d3a3a;
// background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25' viewBox='0 0 100 60'%3E%3Cg %3E%3Crect fill='%23555555' width='11' height='11'/%3E%3Crect fill='%23565656' x='10' width='11' height='11'/%3E%3Crect fill='%23575757' y='10' width='11' height='11'/%3E%3Crect fill='%23575757' x='20' width='11' height='11'/%3E%3Crect fill='%23585858' x='10' y='10' width='11' height='11'/%3E%3Crect fill='%23595959' y='20' width='11' height='11'/%3E%3Crect fill='%235a5a5a' x='30' width='11' height='11'/%3E%3Crect fill='%235b5b5b' x='20' y='10' width='11' height='11'/%3E%3Crect fill='%235c5c5c' x='10' y='20' width='11' height='11'/%3E%3Crect fill='%235c5c5c' y='30' width='11' height='11'/%3E%3Crect fill='%235d5d5d' x='40' width='11' height='11'/%3E%3Crect fill='%235e5e5e' x='30' y='10' width='11' height='11'/%3E%3Crect fill='%235f5f5f' x='20' y='20' width='11' height='11'/%3E%3Crect fill='%23606060' x='10' y='30' width='11' height='11'/%3E%3Crect fill='%23616161' y='40' width='11' height='11'/%3E%3Crect fill='%23626262' x='50' width='11' height='11'/%3E%3Crect fill='%23626262' x='40' y='10' width='11' height='11'/%3E%3Crect fill='%23636363' x='30' y='20' width='11' height='11'/%3E%3Crect fill='%23646464' x='20' y='30' width='11' height='11'/%3E%3Crect fill='%23656565' x='10' y='40' width='11' height='11'/%3E%3Crect fill='%23666666' y='50' width='11' height='11'/%3E%3Crect fill='%23676767' x='60' width='11' height='11'/%3E%3Crect fill='%23686868' x='50' y='10' width='11' height='11'/%3E%3Crect fill='%23686868' x='40' y='20' width='11' height='11'/%3E%3Crect fill='%23696969' x='30' y='30' width='11' height='11'/%3E%3Crect fill='%236a6a6a' x='20' y='40' width='11' height='11'/%3E%3Crect fill='%236b6b6b' x='10' y='50' width='11' height='11'/%3E%3Crect fill='%236c6c6c' x='70' width='11' height='11'/%3E%3Crect fill='%236d6d6d' x='60' y='10' width='11' height='11'/%3E%3Crect fill='%236e6e6e' x='50' y='20' width='11' height='11'/%3E%3Crect fill='%236e6e6e' x='40' y='30' width='11' height='11'/%3E%3Crect fill='%236f6f6f' x='30' y='40' width='11' height='11'/%3E%3Crect fill='%23707070' x='20' y='50' width='11' height='11'/%3E%3Crect fill='%23717171' x='80' width='11' height='11'/%3E%3Crect fill='%23727272' x='70' y='10' width='11' height='11'/%3E%3Crect fill='%23737373' x='60' y='20' width='11' height='11'/%3E%3Crect fill='%23747474' x='50' y='30' width='11' height='11'/%3E%3Crect fill='%23747474' x='40' y='40' width='11' height='11'/%3E%3Crect fill='%23757575' x='30' y='50' width='11' height='11'/%3E%3Crect fill='%23767676' x='90' width='11' height='11'/%3E%3Crect fill='%23777777' x='80' y='10' width='11' height='11'/%3E%3Crect fill='%23787878' x='70' y='20' width='11' height='11'/%3E%3Crect fill='%23797979' x='60' y='30' width='11' height='11'/%3E%3Crect fill='%237a7a7a' x='50' y='40' width='11' height='11'/%3E%3Crect fill='%237b7b7b' x='40' y='50' width='11' height='11'/%3E%3Crect fill='%237c7c7c' x='90' y='10' width='11' height='11'/%3E%3Crect fill='%237c7c7c' x='80' y='20' width='11' height='11'/%3E%3Crect fill='%237d7d7d' x='70' y='30' width='11' height='11'/%3E%3Crect fill='%237e7e7e' x='60' y='40' width='11' height='11'/%3E%3Crect fill='%237f7f7f' x='50' y='50' width='11' height='11'/%3E%3Crect fill='%23808080' x='90' y='20' width='11' height='11'/%3E%3Crect fill='%23818181' x='80' y='30' width='11' height='11'/%3E%3Crect fill='%23828282' x='70' y='40' width='11' height='11'/%3E%3Crect fill='%23838383' x='60' y='50' width='11' height='11'/%3E%3Crect fill='%23848484' x='90' y='30' width='11' height='11'/%3E%3Crect fill='%23848484' x='80' y='40' width='11' height='11'/%3E%3Crect fill='%23858585' x='70' y='50' width='11' height='11'/%3E%3Crect fill='%23868686' x='90' y='40' width='11' height='11'/%3E%3Crect fill='%23878787' x='80' y='50' width='11' height='11'/%3E%3Crect fill='%23888888' x='90' y='50' width='11' height='11'/%3E%3C/g%3E%3C/svg%3E");
background-attachment: fixed;
background-size: cover;
@ -238,4 +234,4 @@ ol {
padding: var(--spacing-20) 0;
background-color: var(--color-placeholder);
border-radius: var(--radius-base);
}
}

View file

@ -55,4 +55,4 @@ button {
ul,
ol {
list-style: none;
}
}

View file

@ -1,3 +1,3 @@
@use 'reset.scss';
@use 'global.scss';
@use 'theme.scss';
@use 'theme.scss';

View file

@ -1,283 +1,247 @@
html[data-theme='🌛 Night'] {
/* Global */
--clr-primary: hsl(173 100% 66%);
--clr-txt: hsl(0 0% 98%);
--clr-bg: hsl(210 7% 11%);
--bg: radial-gradient(hsl(173 100% 4%), var(--clr-bg));
--bg-opacity: 0.7;
/* Menu */
--clr-menu-text: hsl(0 0% 78%);
--clr-menu-bg: linear-gradient(
180deg,
hsl(180 7% 14%) 0%,
hsl(216 7% 14%) 100%
);
--clr-menu-arrow-bg: hsl(180 7% 14%);
--clr-menu-border: hsl(0 0% 19%);
--clr-theme-txt: hsl(177 100% 15%);
--clr-theme-active: hsl(177 100% 80%);
--clr-switch-on-bg: hsl(0 0% 24%);
--clr-switch-off-bg: hsl(0 0% 10%);
/* Hero */
--clr-hero-txt: hsl(174 27% 73%);
--clr-hero-bg: linear-gradient(
270deg,
hsl(210 15% 13%) 43%,
hsl(176 19% 15%) 66%
);
--clr-hero-divider-bg: hsl(0 0% 21%);
--clr-input-txt: hsl(177 100% 15%);
--clr-input-bg: hsl(210 13% 24%);
--clr-input-placeholder-txt: hsl(210 13% 50%);
--clr-input-border: hsl(0 0% 21%);
/* Card */
--clr-card-bg: linear-gradient(
180deg,
hsl(180 7% 14%) 0%,
hsl(216 7% 14%) 100%
);
--clr-card-txt: hsl(0 0% 78%);
/* Link */
--clr-link-txt: hsl(0 100% 98%);
--clr-link-background: hsl(0 0% 4%);
/* Footer */
--clr-footer-txt: hsl(0 0% 78%);
--clr-footer-bg: hsl(210 5% 7%);
/* Post */
--post-overlay-bg: radial-gradient(hsl(173 100% 4% / 80%), var(--clr-bg));
--post-blockquote-txt: hsl(173 100% 94%);
--post-blockquote-bg: hsl(173 60% 4%);
--post-blockquote-border: hsl(173 10% 10%);
--clr-code-bg: hsl(173 60% 4%);
--clr-code-title: hsl(173 100% 94%);
--clr-code-border: hsl(173 10% 10%);
--clr-code-line-number: hsl(173 20% 20%);
--clr-code-line-highlight: hsl(173 40% 8%);
--clr-code-inline-txt: hsl(173 100% 94%);
--clr-code-inline-bg: hsl(173 60% 4%);
--clr-token-1: hsl(173 100% 66%);
--clr-token-2: hsl(180 60% 80%);
--clr-token-3: hsl(173 100% 66%);
--clr-token-4: hsl(0 0% 98%);
--clr-token-5: hsl(173 10% 60%);
}
html[data-theme='☀️ Daylight'] {
/* Global */
--clr-primary: hsl(220 100% 50%);
--clr-txt: hsl(220 10% 10%);
--clr-bg: hsl(0 0% 98%);
--bg: radial-gradient(hsl(0 0% 98%), var(--clr-bg));
--bg-opacity: 0.7;
/* Menu */
--clr-menu-text: hsl(220 10% 10%);
--clr-menu-bg: linear-gradient(180deg, hsl(0 0% 98%) 0%, hsl(0 0% 94%) 100%);
--clr-menu-arrow-bg: hsl(0 0% 98%);
--clr-menu-border: hsl(0 0% 80%);
--clr-theme-txt: hsl(0 0% 98%);
--clr-theme-active: hsl(220 100% 60%);
--clr-switch-on-bg: hsl(220 40% 90%);
--clr-switch-off-bg: hsl(220 40% 80%);
/* Hero */
--clr-hero-txt: hsl(220 10% 40%);
--clr-hero-bg: linear-gradient(270deg, hsl(0 0% 94%) 43%, hsl(0 0% 98%) 66%);
--clr-hero-divider-bg: hsl(0 0% 80%);
--clr-input-txt: hsl(220 10% 98%);
--clr-input-bg: hsl(0 0% 98%);
--clr-input-placeholder-txt: hsl(220 10% 60%);
--clr-input-border: hsl(0 0% 80%);
/* Card */
--clr-card-bg: linear-gradient(180deg, hsl(0 0% 98%) 0%, hsl(0 0% 94%) 100%);
--clr-card-txt: hsl(220 10% 40%);
/* Link */
--clr-link-txt: hsl(220 10% 10%);
--clr-link-background: hsl(0 0% 100%);
/* Footer */
--clr-footer-txt: hsl(220 10% 10%);
--clr-footer-bg: hsl(0 0% 98%);
/* Post */
--post-overlay-bg: radial-gradient(hsl(0 0% 100% / 60%), var(--clr-bg));
--post-blockquote-txt: hsl(0 0% 40%);
--post-blockquote-bg: hsl(0 0% 98%);
--post-blockquote-border: hsl(0 0% 84%);
--clr-code-bg: hsl(0 0% 98%);
--clr-code-title: hsl(0 0% 40%);
--clr-code-border: hsl(0 0% 84%);
--clr-code-line-number: hsl(0 0% 60%);
--clr-code-line-highlight: hsl(0 0% 94%);
--clr-code-inline-txt: hsl(0 0% 98%);
--clr-code-inline-bg: hsl(0 0% 20%);
--clr-token-1: hsl(220 100% 50%);
--clr-token-2: hsl(220 60% 50%);
--clr-token-3: hsl(220 100% 50%);
--clr-token-4: hsl(0 0% 20%);
--clr-token-5: hsl(0 0% 60%);
}
html[data-theme='🐺 Night Howl'] {
/* Global */
--clr-primary: hsl(207 100% 94%);
--clr-txt: hsl(210 40% 80%);
--clr-bg: hsl(210 47% 12%);
--bg: radial-gradient(hsl(206 50% 11%), var(--clr-bg));
--bg-opacity: 0.7;
/* Menu */
--clr-menu-text: hsl(210 40% 80%);
--clr-menu-bg: linear-gradient(
180deg,
hsl(210 47% 14%) 0%,
hsl(210 47% 12%) 100%
);
--clr-menu-arrow-bg: hsl(210 47% 14%);
--clr-menu-border: hsl(210 40% 20%);
--clr-theme-txt: hsl(210 40% 20%);
--clr-theme-active: hsl(210 40% 80%);
--clr-switch-on-bg: hsl(210 40% 60%);
--clr-switch-off-bg: hsl(210 40% 20%);
/* Hero */
--clr-hero-txt: hsl(210 40% 60%);
--clr-hero-bg: linear-gradient(
270deg,
hsl(210 47% 12%) 43%,
hsl(210 47% 14%) 66%
);
--clr-hero-divider-bg: hsl(210 40% 20%);
--clr-input-txt: hsl(210 40% 20%);
--clr-input-bg: hsl(210 40% 16%);
--clr-input-placeholder-txt: hsl(210 40% 60%);
--clr-input-border: hsl(210 40% 20%);
/* Card */
--clr-card-bg: linear-gradient(
180deg,
hsl(210 47% 14%) 0%,
hsl(210 47% 12%) 100%
);
--clr-card-txt: hsl(210 40% 60%);
/* Link */
--clr-link-txt: hsl(210 40% 80%);
--clr-link-background: hsl(210 40% 4%);
/* Footer */
--clr-footer-txt: hsl(210 40% 80%);
--clr-footer-bg: hsl(210 47% 12%);
/* Post */
--post-overlay-bg: radial-gradient(hsl(206 50% 11% / 60%), var(--clr-bg));
--post-blockquote-txt: hsl(210 47% 80%);
--post-blockquote-bg: hsl(210 47% 14%);
--post-blockquote-border: hsl(210 40% 20%);
--clr-code-bg: hsl(210 47% 14%);
--clr-code-title: hsl(210 40% 60%);
--clr-code-border: hsl(210 40% 20%);
--clr-code-line-number: hsl(210 40% 40%);
--clr-code-line-highlight: hsl(210 40% 16%);
--clr-code-inline-txt: hsl(210 47% 98%);
--clr-code-inline-bg: hsl(210 47% 10%);
--clr-token-1: hsl(180 100% 43%);
--clr-token-2: hsl(197 100% 49%);
--clr-token-3: hsl(180 100% 43%);
--clr-token-4: hsl(206 50% 98%);
--clr-token-5: hsl(217 10% 64%);
}
html[data-theme='🧠 Night Mind'] {
/* Global */
--clr-primary: hsl(9 100% 84%);
--clr-txt: hsl(265 28% 98%);
--clr-bg: hsl(265 28% 10%);
--bg: radial-gradient(hsl(265 28% 20%), var(--clr-bg));
--bg-opacity: 0.7;
/* Menu */
--clr-menu-text: hsl(265 28% 98%);
--clr-menu-bg: linear-gradient(
180deg,
hsl(265 28% 20%) 0%,
hsl(265 28% 18%) 100%
);
--clr-menu-arrow-bg: hsl(265 28% 20%);
--clr-menu-border: hsl(265 28% 24%);
--clr-theme-txt: hsl(265 28% 20%);
--clr-theme-active: hsl(9 100% 90%);
--clr-switch-on-bg: hsl(265 28% 30%);
--clr-switch-off-bg: hsl(265 28% 24%);
/* Hero */
--clr-hero-txt: hsl(265 28% 80%);
--clr-hero-bg: linear-gradient(
270deg,
hsl(265 28% 20%) 43%,
hsl(265 28% 24%) 66%
);
--clr-hero-divider-bg: hsl(265 28% 24%);
--clr-input-txt: hsl(265 28% 20%);
--clr-input-bg: hsl(265 28% 24%);
--clr-input-placeholder-txt: hsl(265 28% 80%);
--clr-input-border: hsl(265 28% 26%);
/* Card */
--clr-card-bg: linear-gradient(
180deg,
hsl(265 28% 22%) 0%,
hsl(265 28% 20%) 100%
);
--clr-card-txt: hsl(265 28% 80%);
/* Link */
--clr-link-txt: hsl(265 28% 98%);
--clr-link-background: hsl(210 40% 4%);
/* Footer */
--clr-footer-txt: hsl(265 28% 98%);
--clr-footer-bg: hsl(265 28% 10%);
/* Post */
--post-overlay-bg: radial-gradient(hsl(265 28% 20% / 60%), var(--clr-bg));
--post-blockquote-txt: hsl(265 28% 90%);
--post-blockquote-bg: hsl(265 28% 10%);
--post-blockquote-border: hsl(265 28% 18%);
--clr-code-bg: hsl(265 28% 10%);
--clr-code-title: hsl(265 28% 80%);
--clr-code-border: hsl(265 28% 18%);
--clr-code-line-number: hsl(265 20% 34%);
--clr-code-line-highlight: hsl(265 28% 14%);
--clr-code-inline-txt: hsl(265 28% 98%);
--clr-code-inline-bg: hsl(265 28% 10%);
--clr-token-1: hsl(238 80% 80%);
--clr-token-2: hsl(205 80% 80%);
--clr-token-3: hsl(358 80% 80%);
--clr-token-4: hsl(256 80% 98%);
--clr-token-5: hsl(265 10% 60%);
}
/* Global */
--clr-primary: hsl(173 100% 66%);
--clr-txt: hsl(0 0% 98%);
--clr-bg: hsl(210 7% 11%);
--bg: radial-gradient(hsl(173 100% 4%), var(--clr-bg));
--bg-opacity: 0.7;
/* Menu */
--clr-menu-text: hsl(0 0% 78%);
--clr-menu-bg: linear-gradient(180deg, hsl(180 7% 14%) 0%, hsl(216 7% 14%) 100%);
--clr-menu-arrow-bg: hsl(180 7% 14%);
--clr-menu-border: hsl(0 0% 19%);
--clr-theme-txt: hsl(177 100% 15%);
--clr-theme-active: hsl(177 100% 80%);
--clr-switch-on-bg: hsl(0 0% 24%);
--clr-switch-off-bg: hsl(0 0% 10%);
/* Hero */
--clr-hero-txt: hsl(174 27% 73%);
--clr-hero-bg: linear-gradient(270deg, hsl(210 15% 13%) 43%, hsl(176 19% 15%) 66%);
--clr-hero-divider-bg: hsl(0 0% 21%);
--clr-input-txt: hsl(177 100% 15%);
--clr-input-bg: hsl(210 13% 24%);
--clr-input-placeholder-txt: hsl(210 13% 50%);
--clr-input-border: hsl(0 0% 21%);
/* Card */
--clr-card-bg: linear-gradient(180deg, hsl(180 7% 14%) 0%, hsl(216 7% 14%) 100%);
--clr-card-txt: hsl(0 0% 78%);
/* Link */
--clr-link-txt: hsl(0 100% 98%);
--clr-link-background: hsl(0 0% 4%);
/* Footer */
--clr-footer-txt: hsl(0 0% 78%);
--clr-footer-bg: hsl(210 5% 7%);
/* Post */
--post-overlay-bg: radial-gradient(hsl(173 100% 4% / 80%), var(--clr-bg));
--post-blockquote-txt: hsl(173 100% 94%);
--post-blockquote-bg: hsl(173 60% 4%);
--post-blockquote-border: hsl(173 10% 10%);
--clr-code-bg: hsl(173 60% 4%);
--clr-code-title: hsl(173 100% 94%);
--clr-code-border: hsl(173 10% 10%);
--clr-code-line-number: hsl(173 20% 20%);
--clr-code-line-highlight: hsl(173 40% 8%);
--clr-code-inline-txt: hsl(173 100% 94%);
--clr-code-inline-bg: hsl(173 60% 4%);
--clr-token-1: hsl(173 100% 66%);
--clr-token-2: hsl(180 60% 80%);
--clr-token-3: hsl(173 100% 66%);
--clr-token-4: hsl(0 0% 98%);
--clr-token-5: hsl(173 10% 60%);
}
html[data-theme='☀️ Daylight'] {
/* Global */
--clr-primary: hsl(220 100% 50%);
--clr-txt: hsl(220 10% 10%);
--clr-bg: hsl(0 0% 98%);
--bg: radial-gradient(hsl(0 0% 98%), var(--clr-bg));
--bg-opacity: 0.7;
/* Menu */
--clr-menu-text: hsl(220 10% 10%);
--clr-menu-bg: linear-gradient(180deg, hsl(0 0% 98%) 0%, hsl(0 0% 94%) 100%);
--clr-menu-arrow-bg: hsl(0 0% 98%);
--clr-menu-border: hsl(0 0% 80%);
--clr-theme-txt: hsl(0 0% 98%);
--clr-theme-active: hsl(220 100% 60%);
--clr-switch-on-bg: hsl(220 40% 90%);
--clr-switch-off-bg: hsl(220 40% 80%);
/* Hero */
--clr-hero-txt: hsl(220 10% 40%);
--clr-hero-bg: linear-gradient(270deg, hsl(0 0% 94%) 43%, hsl(0 0% 98%) 66%);
--clr-hero-divider-bg: hsl(0 0% 80%);
--clr-input-txt: hsl(220 10% 98%);
--clr-input-bg: hsl(0 0% 98%);
--clr-input-placeholder-txt: hsl(220 10% 60%);
--clr-input-border: hsl(0 0% 80%);
/* Card */
--clr-card-bg: linear-gradient(180deg, hsl(0 0% 98%) 0%, hsl(0 0% 94%) 100%);
--clr-card-txt: hsl(220 10% 40%);
/* Link */
--clr-link-txt: hsl(220 10% 10%);
--clr-link-background: hsl(0 0% 100%);
/* Footer */
--clr-footer-txt: hsl(220 10% 10%);
--clr-footer-bg: hsl(0 0% 98%);
/* Post */
--post-overlay-bg: radial-gradient(hsl(0 0% 100% / 60%), var(--clr-bg));
--post-blockquote-txt: hsl(0 0% 40%);
--post-blockquote-bg: hsl(0 0% 98%);
--post-blockquote-border: hsl(0 0% 84%);
--clr-code-bg: hsl(0 0% 98%);
--clr-code-title: hsl(0 0% 40%);
--clr-code-border: hsl(0 0% 84%);
--clr-code-line-number: hsl(0 0% 60%);
--clr-code-line-highlight: hsl(0 0% 94%);
--clr-code-inline-txt: hsl(0 0% 98%);
--clr-code-inline-bg: hsl(0 0% 20%);
--clr-token-1: hsl(220 100% 50%);
--clr-token-2: hsl(220 60% 50%);
--clr-token-3: hsl(220 100% 50%);
--clr-token-4: hsl(0 0% 20%);
--clr-token-5: hsl(0 0% 60%);
}
html[data-theme='🐺 Night Howl'] {
/* Global */
--clr-primary: hsl(207 100% 94%);
--clr-txt: hsl(210 40% 80%);
--clr-bg: hsl(210 47% 12%);
--bg: radial-gradient(hsl(206 50% 11%), var(--clr-bg));
--bg-opacity: 0.7;
/* Menu */
--clr-menu-text: hsl(210 40% 80%);
--clr-menu-bg: linear-gradient(180deg, hsl(210 47% 14%) 0%, hsl(210 47% 12%) 100%);
--clr-menu-arrow-bg: hsl(210 47% 14%);
--clr-menu-border: hsl(210 40% 20%);
--clr-theme-txt: hsl(210 40% 20%);
--clr-theme-active: hsl(210 40% 80%);
--clr-switch-on-bg: hsl(210 40% 60%);
--clr-switch-off-bg: hsl(210 40% 20%);
/* Hero */
--clr-hero-txt: hsl(210 40% 60%);
--clr-hero-bg: linear-gradient(270deg, hsl(210 47% 12%) 43%, hsl(210 47% 14%) 66%);
--clr-hero-divider-bg: hsl(210 40% 20%);
--clr-input-txt: hsl(210 40% 20%);
--clr-input-bg: hsl(210 40% 16%);
--clr-input-placeholder-txt: hsl(210 40% 60%);
--clr-input-border: hsl(210 40% 20%);
/* Card */
--clr-card-bg: linear-gradient(180deg, hsl(210 47% 14%) 0%, hsl(210 47% 12%) 100%);
--clr-card-txt: hsl(210 40% 60%);
/* Link */
--clr-link-txt: hsl(210 40% 80%);
--clr-link-background: hsl(210 40% 4%);
/* Footer */
--clr-footer-txt: hsl(210 40% 80%);
--clr-footer-bg: hsl(210 47% 12%);
/* Post */
--post-overlay-bg: radial-gradient(hsl(206 50% 11% / 60%), var(--clr-bg));
--post-blockquote-txt: hsl(210 47% 80%);
--post-blockquote-bg: hsl(210 47% 14%);
--post-blockquote-border: hsl(210 40% 20%);
--clr-code-bg: hsl(210 47% 14%);
--clr-code-title: hsl(210 40% 60%);
--clr-code-border: hsl(210 40% 20%);
--clr-code-line-number: hsl(210 40% 40%);
--clr-code-line-highlight: hsl(210 40% 16%);
--clr-code-inline-txt: hsl(210 47% 98%);
--clr-code-inline-bg: hsl(210 47% 10%);
--clr-token-1: hsl(180 100% 43%);
--clr-token-2: hsl(197 100% 49%);
--clr-token-3: hsl(180 100% 43%);
--clr-token-4: hsl(206 50% 98%);
--clr-token-5: hsl(217 10% 64%);
}
html[data-theme='🧠 Night Mind'] {
/* Global */
--clr-primary: hsl(9 100% 84%);
--clr-txt: hsl(265 28% 98%);
--clr-bg: hsl(265 28% 10%);
--bg: radial-gradient(hsl(265 28% 20%), var(--clr-bg));
--bg-opacity: 0.7;
/* Menu */
--clr-menu-text: hsl(265 28% 98%);
--clr-menu-bg: linear-gradient(180deg, hsl(265 28% 20%) 0%, hsl(265 28% 18%) 100%);
--clr-menu-arrow-bg: hsl(265 28% 20%);
--clr-menu-border: hsl(265 28% 24%);
--clr-theme-txt: hsl(265 28% 20%);
--clr-theme-active: hsl(9 100% 90%);
--clr-switch-on-bg: hsl(265 28% 30%);
--clr-switch-off-bg: hsl(265 28% 24%);
/* Hero */
--clr-hero-txt: hsl(265 28% 80%);
--clr-hero-bg: linear-gradient(270deg, hsl(265 28% 20%) 43%, hsl(265 28% 24%) 66%);
--clr-hero-divider-bg: hsl(265 28% 24%);
--clr-input-txt: hsl(265 28% 20%);
--clr-input-bg: hsl(265 28% 24%);
--clr-input-placeholder-txt: hsl(265 28% 80%);
--clr-input-border: hsl(265 28% 26%);
/* Card */
--clr-card-bg: linear-gradient(180deg, hsl(265 28% 22%) 0%, hsl(265 28% 20%) 100%);
--clr-card-txt: hsl(265 28% 80%);
/* Link */
--clr-link-txt: hsl(265 28% 98%);
--clr-link-background: hsl(210 40% 4%);
/* Footer */
--clr-footer-txt: hsl(265 28% 98%);
--clr-footer-bg: hsl(265 28% 10%);
/* Post */
--post-overlay-bg: radial-gradient(hsl(265 28% 20% / 60%), var(--clr-bg));
--post-blockquote-txt: hsl(265 28% 90%);
--post-blockquote-bg: hsl(265 28% 10%);
--post-blockquote-border: hsl(265 28% 18%);
--clr-code-bg: hsl(265 28% 10%);
--clr-code-title: hsl(265 28% 80%);
--clr-code-border: hsl(265 28% 18%);
--clr-code-line-number: hsl(265 20% 34%);
--clr-code-line-highlight: hsl(265 28% 14%);
--clr-code-inline-txt: hsl(265 28% 98%);
--clr-code-inline-bg: hsl(265 28% 10%);
--clr-token-1: hsl(238 80% 80%);
--clr-token-2: hsl(205 80% 80%);
--clr-token-3: hsl(358 80% 80%);
--clr-token-4: hsl(256 80% 98%);
--clr-token-5: hsl(265 10% 60%);
}

View file

@ -3,20 +3,20 @@ import preprocess from 'svelte-preprocess';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://github.com/sveltejs/svelte-preprocess
// for more information about preprocessors
preprocess: preprocess(),
kit: {
adapter: adapter(),
alias: {
$components: 'src/components',
$root: './src',
},
// Override http methods in the Todo forms
methodOverride: {
allowed: ['PATCH', 'DELETE']
}
}
// Consult https://github.com/sveltejs/svelte-preprocess
// for more information about preprocessors
preprocess: preprocess(),
kit: {
adapter: adapter(),
alias: {
$components: 'src/components',
$root: './src'
},
// Override http methods in the Todo forms
methodOverride: {
allowed: ['PATCH', 'DELETE']
}
}
};
export default config;

View file

@ -1,6 +1,6 @@
import { expect, test } from '@playwright/test';
test('about page has expected h1', async ({ page }) => {
await page.goto('/about');
expect(await page.textContent('h1')).toBe('About this app');
await page.goto('/about');
expect(await page.textContent('h1')).toBe('About this app');
});

View file

@ -1,13 +1,13 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true
}
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true
}
}

View file

@ -2,7 +2,7 @@ import { sveltekit } from '@sveltejs/kit/vite';
/** @type {import('vite').UserConfig} */
const config = {
plugins: [sveltekit()]
plugins: [sveltekit()]
};
export default config;