Add favicon, font, tweak styles

This commit is contained in:
Mihkel Martin Kasterpalu 2025-01-21 15:22:19 +02:00
parent a50e0d6ff8
commit cca4f55166
16 changed files with 175 additions and 80 deletions

View file

@ -48,9 +48,11 @@
"vite": "^5.4.11"
},
"dependencies": {
"@fontsource-variable/smooch-sans": "^5.1.1",
"better-sqlite3": "^11.8.0",
"drizzle-orm": "^0.38.4",
"lucide-svelte": "^0.473.0",
"mode-watcher": "^0.5.0",
"nanoid": "^5.0.9",
"spotify-web-api-node": "^5.0.2",
"svelte-kit-sessions": "^0.4.0"

20
pnpm-lock.yaml generated
View file

@ -8,6 +8,9 @@ importers:
.:
dependencies:
'@fontsource-variable/smooch-sans':
specifier: ^5.1.1
version: 5.1.1
better-sqlite3:
specifier: ^11.8.0
version: 11.8.1
@ -17,6 +20,9 @@ importers:
lucide-svelte:
specifier: ^0.473.0
version: 0.473.0(svelte@5.19.0)
mode-watcher:
specifier: ^0.5.0
version: 0.5.0(svelte@5.19.0)
nanoid:
specifier: ^5.0.9
version: 5.0.9
@ -599,6 +605,9 @@ packages:
'@floating-ui/utils@0.2.9':
resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==}
'@fontsource-variable/smooch-sans@5.1.1':
resolution: {integrity: sha512-ADcY3Pjkvu74x4T+p2gNIo8Ba7DGrX1IhQgJFefztWB8Tf5nX7Qb+tqAbtW7O/KYWJi4EjzrxCefHBM1PfOOsg==}
'@humanfs/core@0.19.1':
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
engines: {node: '>=18.18.0'}
@ -1692,6 +1701,11 @@ packages:
mkdirp-classic@0.5.3:
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
mode-watcher@0.5.0:
resolution: {integrity: sha512-5E6fh/aXhAVv+U+DbeM0hCmskQE9u7WSmvnCRijJB/MJu7HtB73sjiCaZ9n1M8QHmzLrBFo8XBAUcWXkDm8Z9A==}
peerDependencies:
svelte: ^4.0.0 || ^5.0.0-next.1
mri@1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'}
@ -2612,6 +2626,8 @@ snapshots:
'@floating-ui/utils@0.2.9': {}
'@fontsource-variable/smooch-sans@5.1.1': {}
'@humanfs/core@0.19.1': {}
'@humanfs/node@0.16.6':
@ -3644,6 +3660,10 @@ snapshots:
mkdirp-classic@0.5.3: {}
mode-watcher@0.5.0(svelte@5.19.0):
dependencies:
svelte: 5.19.0
mri@1.2.0: {}
mrmime@2.0.0: {}

View file

@ -2,8 +2,13 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<meta name="apple-mobile-web-app-title" content="Kasterpalu" />
<link rel="manifest" href="/site.webmanifest" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">

View file

@ -26,17 +26,17 @@
}}
onconsider={handleDndConsider}
onfinalize={handleDndFinalize}
class="grid grid-cols-3 items-center gap-14"
class="grid grid-cols-3 items-center gap-4 sm:gap-8 md:gap-10 lg:gap-14"
>
{#each items as item, i (item.id)}
<div animate:flip={{ duration: flipDurationMs, easing: expoOut }}>
<Card.Root
class="overflow-hidden rounded-xl border bg-card text-card-foreground shadow {type ===
'names'
? 'border-orange-300'
? 'border-red-400 '
: type === 'artists'
? 'border-cyan-300'
: 'border-purple-300'}"
? 'border-purple-400 '
: 'border-blue-400'}"
>
{#if image}
<Card.Content class="p-0">
@ -45,7 +45,13 @@
</Card.Content>
{:else}
<Card.Content>
<p class="text-center">
<p
class="text-center {type === 'names'
? 'text-red-900 dark:text-red-200'
: type === 'artists'
? 'text-purple-900 dark:text-purple-200'
: ''}"
>
{#if type === 'artists'}
{truncate(item.value, 30)}
{:else}

View file

@ -17,7 +17,6 @@ class SpotifyAPI {
return await this.api.clientCredentialsGrant().then(
(data) => {
console.log(data.body);
if (!data.body['expires_in'] || !data.body['access_token']) {
return false;
}

View file

@ -1,14 +1,39 @@
<script lang="ts">
import '../app.css';
import '@fontsource-variable/smooch-sans';
import { ModeWatcher, toggleMode } from 'mode-watcher';
import { Button } from '$lib/components/ui/button/index.js';
import Sun from 'lucide-svelte/icons/sun';
import Moon from 'lucide-svelte/icons/moon';
let { children } = $props();
</script>
<div class="flex min-h-screen flex-col items-center justify-center">
<header class="mb-24 flex flex-col items-center">
<h1 class="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl">Paku biiti</h1>
<p class="text-xl text-muted-foreground">
Lohista kokku õiged albumi <span class="text-orange-400">nimed</span>,
<span class="text-cyan-400">artistid</span> ja <span class="text-purple-400">pildid</span>.
<ModeWatcher />
<header class="container absolute top-0 flex justify-between py-6">
<a href="/">
<img src="/favicon.svg" alt="Mihkel Martin Kasterpalu logo" class="h-10" />
</a>
<Button onclick={toggleMode} variant="outline" size="icon">
<Sun
class="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0"
/>
<Moon
class="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"
/>
<span class="sr-only">Toggle theme</span>
</Button>
</header>
<div class="container flex min-h-screen flex-col items-center justify-center py-4">
<header class="font-title mb-24 flex flex-col items-center">
<h1 class="mb-1 scroll-m-20 text-6xl font-extrabold tracking-tight lg:text-7xl">Paku biiti</h1>
<p class="text-2xl font-semibold text-muted-foreground">
Lohista kokku õiged albumi <span class="text-red-600 dark:text-red-400">nimed</span>,
<span class="text-purple-600 dark:text-purple-400">artistid</span> ja
<span class="text-blue-600 dark:text-blue-400">pildid</span>.
</p>
</header>
<main class="w-full max-w-3xl">

View file

@ -30,17 +30,17 @@
</script>
{#snippet footer(loading: boolean)}
<div class="flex justify-evenly">
<p class="text-lg font-semibold">Skoor: {data.stage}</p>
<div class="mt-8 flex items-center justify-evenly">
<p class="font-title text-lg font-semibold">Skoor: {data.stage}</p>
{#if loading}
<Button disabled>
<Button disabled class="min-w-[4.5rem]">
<LoaderCircle class="animate-spin" />
Oota korra
Oota
</Button>
{:else}
<Button type="submit">Saada</Button>
<Button type="submit" class="min-w-[4.5rem]">Saada</Button>
{/if}
<p class="text-lg font-semibold">Parim: {data.highscore}</p>
<p class="font-title text-lg font-semibold">Parim: {data.highscore}</p>
</div>
{/snippet}
@ -74,16 +74,14 @@
action="?/submit"
method="POST"
use:enhance
class="grid w-full gap-6 px-8 transition-all {loading || data?.playing === false
? 'grayscale'
: ''}"
class="grid w-full gap-6 transition-all {loading || data?.playing === false ? 'grayscale' : ''}"
>
{#if data?.streamed?.albums}
{#await data.streamed.albums}
{#each { length: 2 } as _}
<section class="grid grid-cols-3 items-center gap-14">
{#each { length: 3 } as _}
<Skeleton class="h-[6rem] w-full rounded-xl " />
<Skeleton class="h-[5.25rem] w-full rounded-xl " />
{/each}
</section>
<Separator />

BIN
static/apple-touch-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
static/favicon-96x96.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

18
static/favicon.svg Normal file
View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="1480" height="1480" version="1.1" xmlns="http://www.w3.org/2000/svg">
<svg id="SvgjsSvg1026" class="img-fluid" width="1480" height="1480" cursor="move"
style="transform-origin:50% 50% 0px;transform:matrix(1, 0, 0, 1, -4, -2);transition:none"
viewBox="0 0 14800 14800" xmlns="http://www.w3.org/2000/svg">
<g id="SvgjsG1025" style="transform:none">
<g style="transform:none">
<path id="SvgjsPath1024"
d="m7170 14789c-113-3-232-7-265-8l-60-1 550-550-1300-1301-1300-1300 25 6c26 5 297 69 2204 515l1119 262 877-877v-20c0-11-196-785-434-1720-239-935-433-1701-431-1703 1-2 611 598 1356 1333l1353 1336 913-913c502-502 913-916 913-919 0-6-5948-5922-5959-5927-3-1-377 369-830 822l-823 823 639 2519c352 1386 639 2520 638 2522-2 2-488-114-1081-257-3433-828-3987-961-4002-961h-17l-480 480-479 480-7-8c-4-4-23-68-42-142-142-542-221-1089-236-1635l-6-240 14-500 15-165c58-610 171-1144 357-1700 554-1656 1707-3085 3216-3988 1082-648 2291-1002 3553-1041l245-8 247 8 246 8 169 16c232 22 648 79 661 91 2 1-65 69-149 151-404 393-664 761-823 1165l-46 116-34 134c-19 73-42 174-52 223l-16 90-10 410 16 113c18 120 60 300 74 314l9 9 718-256c395-141 721-258 726-260l7-5-14-53-15-52-12-220 17-85 18-85 58-142 52-78 52-79 85-86 86-86 56-36 55-36 62-21 61-21h44 43l48 16 47 16 60 55 59 55 30 61 30 62 42 160 10 320-204 2608 777 777 2533-2533 107 144c385 515 707 1093 948 1704l75 190 70 215c199 608 307 1171 352 1830l11 155v315 315l-11 155c-70 1025-326 1967-775 2855-825 1630-2206 2890-3904 3559-648 256-1308 412-2036 481l-160 15-190 5c-104 3-224 7-265 8-41 2-167 0-280-4z" />
<path id="SvgjsPath1023"
d="m11586 2508c9-69 65-831 72-987l7-164 167 125c91 69 230 179 308 243l141 119-348 348c-191 191-349 348-350 348s0-15 3-32z" />
</g>
</g>
<g id="SvgjsG1022" fill="#fff" style="transform:none"></g>
</svg>
<style>@media (prefers-color-scheme: light) { :root { filter: none; } }
@media (prefers-color-scheme: dark) { :root { filter: invert(100%); } }</style>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

21
static/site.webmanifest Normal file
View file

@ -0,0 +1,21 @@
{
"name": "Kasterpalu",
"short_name": "Kasterpalu",
"icons": [
{
"src": "/web-app-manifest-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/web-app-manifest-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -1,96 +1,97 @@
import { fontFamily } from "tailwindcss/defaultTheme";
import type { Config } from "tailwindcss";
import tailwindcssAnimate from "tailwindcss-animate";
import { fontFamily } from 'tailwindcss/defaultTheme';
import type { Config } from 'tailwindcss';
import tailwindcssAnimate from 'tailwindcss-animate';
const config: Config = {
darkMode: ["class"],
content: ["./src/**/*.{html,js,svelte,ts}"],
safelist: ["dark"],
darkMode: ['class'],
content: ['./src/**/*.{html,js,svelte,ts}'],
safelist: ['dark'],
theme: {
container: {
center: true,
padding: "2rem",
padding: '2rem',
screens: {
"2xl": "1400px"
'2xl': '1400px'
}
},
extend: {
colors: {
border: "hsl(var(--border) / <alpha-value>)",
input: "hsl(var(--input) / <alpha-value>)",
ring: "hsl(var(--ring) / <alpha-value>)",
background: "hsl(var(--background) / <alpha-value>)",
foreground: "hsl(var(--foreground) / <alpha-value>)",
border: 'hsl(var(--border) / <alpha-value>)',
input: 'hsl(var(--input) / <alpha-value>)',
ring: 'hsl(var(--ring) / <alpha-value>)',
background: 'hsl(var(--background) / <alpha-value>)',
foreground: 'hsl(var(--foreground) / <alpha-value>)',
primary: {
DEFAULT: "hsl(var(--primary) / <alpha-value>)",
foreground: "hsl(var(--primary-foreground) / <alpha-value>)"
DEFAULT: 'hsl(var(--primary) / <alpha-value>)',
foreground: 'hsl(var(--primary-foreground) / <alpha-value>)'
},
secondary: {
DEFAULT: "hsl(var(--secondary) / <alpha-value>)",
foreground: "hsl(var(--secondary-foreground) / <alpha-value>)"
DEFAULT: 'hsl(var(--secondary) / <alpha-value>)',
foreground: 'hsl(var(--secondary-foreground) / <alpha-value>)'
},
destructive: {
DEFAULT: "hsl(var(--destructive) / <alpha-value>)",
foreground: "hsl(var(--destructive-foreground) / <alpha-value>)"
DEFAULT: 'hsl(var(--destructive) / <alpha-value>)',
foreground: 'hsl(var(--destructive-foreground) / <alpha-value>)'
},
muted: {
DEFAULT: "hsl(var(--muted) / <alpha-value>)",
foreground: "hsl(var(--muted-foreground) / <alpha-value>)"
DEFAULT: 'hsl(var(--muted) / <alpha-value>)',
foreground: 'hsl(var(--muted-foreground) / <alpha-value>)'
},
accent: {
DEFAULT: "hsl(var(--accent) / <alpha-value>)",
foreground: "hsl(var(--accent-foreground) / <alpha-value>)"
DEFAULT: 'hsl(var(--accent) / <alpha-value>)',
foreground: 'hsl(var(--accent-foreground) / <alpha-value>)'
},
popover: {
DEFAULT: "hsl(var(--popover) / <alpha-value>)",
foreground: "hsl(var(--popover-foreground) / <alpha-value>)"
DEFAULT: 'hsl(var(--popover) / <alpha-value>)',
foreground: 'hsl(var(--popover-foreground) / <alpha-value>)'
},
card: {
DEFAULT: "hsl(var(--card) / <alpha-value>)",
foreground: "hsl(var(--card-foreground) / <alpha-value>)"
DEFAULT: 'hsl(var(--card) / <alpha-value>)',
foreground: 'hsl(var(--card-foreground) / <alpha-value>)'
},
sidebar: {
DEFAULT: "hsl(var(--sidebar-background))",
foreground: "hsl(var(--sidebar-foreground))",
primary: "hsl(var(--sidebar-primary))",
"primary-foreground": "hsl(var(--sidebar-primary-foreground))",
accent: "hsl(var(--sidebar-accent))",
"accent-foreground": "hsl(var(--sidebar-accent-foreground))",
border: "hsl(var(--sidebar-border))",
ring: "hsl(var(--sidebar-ring))",
},
DEFAULT: 'hsl(var(--sidebar-background))',
foreground: 'hsl(var(--sidebar-foreground))',
primary: 'hsl(var(--sidebar-primary))',
'primary-foreground': 'hsl(var(--sidebar-primary-foreground))',
accent: 'hsl(var(--sidebar-accent))',
'accent-foreground': 'hsl(var(--sidebar-accent-foreground))',
border: 'hsl(var(--sidebar-border))',
ring: 'hsl(var(--sidebar-ring))'
}
},
borderRadius: {
xl: "calc(var(--radius) + 4px)",
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)"
xl: 'calc(var(--radius) + 4px)',
lg: 'var(--radius)',
md: 'calc(var(--radius) - 2px)',
sm: 'calc(var(--radius) - 4px)'
},
fontFamily: {
sans: [...fontFamily.sans]
sans: [...fontFamily.sans],
title: ['Smooch Sans Variable', ...fontFamily.sans]
},
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--bits-accordion-content-height)" },
'accordion-down': {
from: { height: '0' },
to: { height: 'var(--bits-accordion-content-height)' }
},
"accordion-up": {
from: { height: "var(--bits-accordion-content-height)" },
to: { height: "0" },
},
"caret-blink": {
"0%,70%,100%": { opacity: "1" },
"20%,50%": { opacity: "0" },
'accordion-up': {
from: { height: 'var(--bits-accordion-content-height)' },
to: { height: '0' }
},
'caret-blink': {
'0%,70%,100%': { opacity: '1' },
'20%,50%': { opacity: '0' }
}
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
"caret-blink": "caret-blink 1.25s ease-out infinite",
},
},
'accordion-down': 'accordion-down 0.2s ease-out',
'accordion-up': 'accordion-up 0.2s ease-out',
'caret-blink': 'caret-blink 1.25s ease-out infinite'
}
}
},
plugins: [tailwindcssAnimate],
plugins: [tailwindcssAnimate]
};
export default config;