Bump packages, migrate to tailwind 4

This commit is contained in:
Mihkel Martin Kasterpalu 2025-01-31 19:37:17 +02:00
parent cd9cd98008
commit fd0e12b665
15 changed files with 588 additions and 789 deletions

View file

@ -13,41 +13,42 @@
"lint": "prettier --check . && eslint ." "lint": "prettier --check . && eslint ."
}, },
"devDependencies": { "devDependencies": {
"@eslint/compat": "^1.2.5", "@eslint/compat": "^1.2.6",
"@eslint/js": "^9.18.0", "@eslint/js": "^9.19.0",
"@sveltejs/adapter-node": "^5.2.12", "@sveltejs/adapter-node": "^5.2.12",
"@sveltejs/enhanced-img": "^0.4.4", "@sveltejs/enhanced-img": "^0.4.4",
"@sveltejs/kit": "^2.16.1", "@sveltejs/kit": "^2.16.1",
"@sveltejs/vite-plugin-svelte": "^5.0.3", "@sveltejs/vite-plugin-svelte": "^5.0.3",
"@tailwindcss/container-queries": "^0.1.1", "@tailwindcss/container-queries": "^0.1.1",
"@tailwindcss/forms": "^0.5.10", "@tailwindcss/forms": "^0.5.10",
"@tailwindcss/postcss": "^4.0.1",
"@tailwindcss/vite": "^4.0.1",
"@types/spotify-web-api-node": "^5.0.11", "@types/spotify-web-api-node": "^5.0.11",
"autoprefixer": "^10.4.20",
"bits-ui": "1.0.0-next.80", "bits-ui": "1.0.0-next.80",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"eslint": "^9.18.0", "eslint": "^9.19.0",
"eslint-config-prettier": "^10.0.1", "eslint-config-prettier": "^10.0.1",
"eslint-plugin-svelte": "^2.46.1", "eslint-plugin-svelte": "^2.46.1",
"globals": "^15.14.0", "globals": "^15.14.0",
"lucide-svelte": "^0.473.0", "lucide-svelte": "^0.474.0",
"prettier": "^3.4.2", "prettier": "^3.4.2",
"prettier-plugin-svelte": "^3.3.3", "prettier-plugin-svelte": "^3.3.3",
"prettier-plugin-tailwindcss": "^0.6.10", "prettier-plugin-tailwindcss": "^0.6.11",
"svelte": "^5.19.1", "svelte": "^5.19.6",
"svelte-check": "^4.1.4", "svelte-check": "^4.1.4",
"svelte-dnd-action": "^0.9.55", "svelte-dnd-action": "^0.9.56",
"tailwind-merge": "^2.6.0", "tailwind-merge": "^3.0.1",
"tailwind-variants": "^0.3.1", "tailwind-variants": "^0.3.1",
"tailwindcss": "^3.4.17", "tailwindcss": "^4.0.1",
"tailwindcss-animate": "^1.0.7", "tailwindcss-animate": "^1.0.7",
"typescript": "^5.7.3", "typescript": "^5.7.3",
"typescript-eslint": "^8.21.0", "typescript-eslint": "^8.22.0",
"vite": "^6.0.11" "vite": "^6.0.11"
}, },
"dependencies": { "dependencies": {
"@fontsource-variable/kode-mono": "^5.1.1", "@fontsource-variable/kode-mono": "^5.1.1",
"@fontsource-variable/smooch-sans": "^5.1.1", "@fontsource-variable/smooch-sans": "^5.1.1",
"mode-watcher": "^0.5.0", "mode-watcher": "^0.5.1",
"nanoid": "^5.0.9", "nanoid": "^5.0.9",
"spotify-web-api-node": "^5.0.2", "spotify-web-api-node": "^5.0.2",
"svelte-kit-sessions": "^0.4.0" "svelte-kit-sessions": "^0.4.0"

1195
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,5 @@
export default { export default {
plugins: { plugins: {
tailwindcss: {}, '@tailwindcss/postcss': {}
autoprefixer: {}
} }
}; };

View file

@ -1,6 +1,42 @@
@tailwind base; @import 'tailwindcss';
@tailwind components;
@tailwind utilities; @config '../tailwind.config.ts';
/*
The default border color has changed to `currentColor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
}
@utility shadow-sharp {
box-shadow: hsl(var(--primary)) 4px 3px 0px;
&:hover {
box-shadow: hsl(var(--primary)) 2px 1px 0px;
translate: 2px 1px;
}
&.pressed {
box-shadow: hsl(var(--primary)) 2px 1px 0px;
translate: 2px 1px;
}
}
@utility container {
margin-inline: auto;
padding-inline: 2rem;
}
@layer base { @layer base {
:root { :root {
@ -73,20 +109,3 @@
@apply bg-background text-foreground; @apply bg-background text-foreground;
} }
} }
@layer components {
.shadow-sharp {
box-shadow: hsl(var(--primary)) 4px 3px 0px;
}
button.shadow-sharp,
a.shadow-sharp {
&:hover {
box-shadow: hsl(var(--primary)) 2px 1px 0px;
translate: 2px 1px;
}
&.pressed {
box-shadow: hsl(var(--primary)) 2px 1px 0px;
translate: 2px 1px;
}
}
}

View file

@ -18,7 +18,7 @@
<AlertDialogPrimitive.Content <AlertDialogPrimitive.Content
bind:ref bind:ref
class={cn( class={cn(
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg', 'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 sm:rounded-lg',
className className
)} )}
{...restProps} {...restProps}

View file

@ -1,14 +1,14 @@
<script lang="ts" module> <script lang="ts" module>
import { type VariantProps, tv } from 'tailwind-variants'; import { type VariantProps, tv } from 'tailwind-variants';
export const badgeVariants = tv({ export const badgeVariants = tv({
base: 'focus:ring-ring inline-flex select-none items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2', base: 'focus:ring-ring inline-flex select-none items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-hidden focus:ring-2 focus:ring-offset-2',
variants: { variants: {
variant: { variant: {
default: 'bg-primary text-primary-foreground hover:bg-primary/80 border-transparent shadow', default: 'bg-primary text-primary-foreground hover:bg-primary/80 border-transparent shadow-sm',
secondary: secondary:
'bg-secondary text-secondary-foreground hover:bg-secondary/80 border-transparent', 'bg-secondary text-secondary-foreground hover:bg-secondary/80 border-transparent',
destructive: destructive:
'bg-destructive text-destructive-foreground hover:bg-destructive/80 border-transparent shadow', 'bg-destructive text-destructive-foreground hover:bg-destructive/80 border-transparent shadow-sm',
outline: 'text-foreground' outline: 'text-foreground'
} }
}, },

View file

@ -4,14 +4,14 @@
import { type VariantProps, tv } from 'tailwind-variants'; import { type VariantProps, tv } from 'tailwind-variants';
export const buttonVariants = tv({ export const buttonVariants = tv({
base: 'focus-visible:ring-ring inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', base: 'focus-visible:ring-ring inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-1 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
variants: { variants: {
variant: { variant: {
default: 'bg-primary text-primary-foreground hover:bg-primary/90 shadow', default: 'bg-primary text-primary-foreground hover:bg-primary/90 shadow-sm',
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90 shadow-sm', destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90 shadow-xs',
outline: outline:
'border-input bg-background hover:bg-accent hover:text-accent-foreground border shadow-sm', 'border-input bg-background hover:bg-accent hover:text-accent-foreground border shadow-xs',
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80 shadow-sm', secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80 shadow-xs',
ghost: 'hover:bg-accent hover:text-accent-foreground', ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline' link: 'text-primary underline-offset-4 hover:underline'
}, },

View file

@ -13,7 +13,7 @@
<div <div
bind:this={ref} bind:this={ref}
class={cn('rounded-xl border bg-card text-card-foreground shadow', className)} class={cn('rounded-xl border bg-card text-card-foreground shadow-sm', className)}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}

View file

@ -20,7 +20,7 @@
{sideOffset} {sideOffset}
{align} {align}
class={cn( class={cn(
"bg-popover text-popover-foreground z-50 w-64 rounded-md border p-4 shadow-md outline-none", "bg-popover text-popover-foreground z-50 w-64 rounded-md border p-4 shadow-md outline-hidden",
className className
)} )}
{...restProps} {...restProps}

View file

@ -45,11 +45,11 @@
<Button onclick={() => cycleTheme()} variant="ghost" size="icon" class="h-12 w-12"> <Button onclick={() => cycleTheme()} variant="ghost" size="icon" class="h-12 w-12">
{#if theme === 'dark'} {#if theme === 'dark'}
<Moon class="!h-6 !w-6" /> <Moon class="h-6! w-6!" />
{:else if theme === 'light'} {:else if theme === 'light'}
<Sun class="!h-6 !w-6" /> <Sun class="h-6! w-6!" />
{:else} {:else}
<LaptopMinimal class="!h-6 !w-6" /> <LaptopMinimal class="h-6! w-6!" />
{/if} {/if}
<span class="sr-only">Toggle theme</span> <span class="sr-only">Toggle theme</span>

View file

@ -17,7 +17,7 @@
link: string link: string
)} )}
<div class="mb-16 w-80 space-y-3 md:w-64"> <div class="mb-16 w-80 space-y-3 md:w-64">
<Image {image} {tags} class="aspect-[4/5] object-cover" /> <Image {image} {tags} class="aspect-4/5 object-cover" />
<div class="grid grid-cols-[1fr_auto] items-center text-sm"> <div class="grid grid-cols-[1fr_auto] items-center text-sm">
<div class="mt-1 pr-4"> <div class="mt-1 pr-4">
<h3 class="text-lg font-medium leading-none">{name}</h3> <h3 class="text-lg font-medium leading-none">{name}</h3>

View file

@ -33,7 +33,7 @@
> >
{#each Object.entries(games) as [href, { image, name }]} {#each Object.entries(games) as [href, { image, name }]}
<a <a
class="shadow-sharp flex aspect-[4/1] min-h-20 max-w-sm items-center justify-center rounded-xl border-2 border-current bg-contain bg-no-repeat transition-all {href === class="shadow-sharp flex aspect-4/1 min-h-20 max-w-sm items-center justify-center rounded-xl border-2 border-current bg-contain bg-no-repeat transition-all {href ===
'' ''
? 'pressed pointer-events-none' ? 'pressed pointer-events-none'
: ''}" : ''}"

View file

@ -22,14 +22,13 @@
{#snippet clockStage(count: number, index: number, title: string, divider = true)} {#snippet clockStage(count: number, index: number, title: string, divider = true)}
<div class="flex flex-col items-center gap-2"> <div class="flex flex-col items-center gap-2">
<div <div
class="card h-[2.75rem] overflow-hidden rounded-xl bg-muted font-mono text-xl ring ring-foreground/25 drop-shadow-md" class="card bg-muted ring-foreground/25 h-[2.75rem] overflow-hidden rounded-xl font-mono text-xl ring-3 drop-shadow-md"
> >
<div <div
style="translate: 0 calc({index} * -2rem); transition-timing-function: cubic-bezier(.65,.01,.04,.97); transition-duration: {index === style="translate: 0 calc({index} * -2rem); transition-duration: {index === count - 1
count - 1
? '600ms' ? '600ms'
: '300ms'};" : '300ms'};"
class="flex flex-col gap-1 px-4 py-2 transition-all" class="ease-bouncy flex flex-col gap-1 px-4 py-2 transition-transform"
> >
{#each { length: count } as _, i} {#each { length: count } as _, i}
{@render clockDigit(i)} {@render clockDigit(i)}
@ -37,24 +36,24 @@
</div> </div>
</div> </div>
<p class="text-sm text-muted-foreground">{title}</p> <p class="text-muted-foreground text-sm">{title}</p>
</div> </div>
{#if divider} {#if divider}
<p class="mb-7 block text-center text-lg font-semibold text-muted-foreground">:</p> <p class="text-muted-foreground mb-7 block text-center text-lg font-semibold">:</p>
{:else} {:else}
<p <p
class="invisible hidden text-center text-lg font-semibold text-muted-foreground md:visible md:block" class="text-muted-foreground invisible hidden text-center text-lg font-semibold md:visible md:block"
></p> ></p>
{/if} {/if}
{/snippet} {/snippet}
<header class="mb-24 flex flex-col items-center text-center font-title"> <header class="font-title mb-24 flex flex-col items-center text-center">
<h1 class="mb-1 scroll-m-20 text-5xl font-extrabold tracking-tight lg:text-6xl">Epochalypse</h1> <h1 class="mb-1 scroll-m-20 text-5xl font-extrabold tracking-tight lg:text-6xl">Epochalypse</h1>
<p class="text-xl font-semibold text-muted-foreground">Ära muretse! Sul on veel aega:</p> <p class="text-muted-foreground text-xl font-semibold">Ära muretse! Sul on veel aega:</p>
</header> </header>
<main class="w-full max-w-4xl"> <main class="w-full max-w-4xl">
<div <div
class="mx-auto grid w-full grid-cols-[auto_auto_auto] items-center justify-center gap-4 rounded-md bg-muted p-12 md:flex" class="bg-muted mx-auto grid w-full grid-cols-[auto_auto_auto] items-center justify-center gap-4 rounded-md p-12 md:flex"
> >
{@render clockStage(13, timeUntil.years, 'aastat')} {@render clockStage(13, timeUntil.years, 'aastat')}
{@render clockStage(13, timeUntil.months, 'kuud', false)} {@render clockStage(13, timeUntil.months, 'kuud', false)}
@ -68,45 +67,45 @@
<Accordion.Item value="item-1"> <Accordion.Item value="item-1">
<Accordion.Trigger>Mis asi see on??</Accordion.Trigger> <Accordion.Trigger>Mis asi see on??</Accordion.Trigger>
<Accordion.Content class="text-md"> <Accordion.Content class="text-md">
<p class="leading-7 [&:not(:first-child)]:mt-6"> <p class="leading-7 not-first:mt-6">
Epochalypse nimeline probleem on sarnane 1990 lõpus toimunud <a Epochalypse nimeline probleem on sarnane 1990 lõpus toimunud <a
href="https://en.wikipedia.org/wiki/Year_2000_problem" href="https://en.wikipedia.org/wiki/Year_2000_problem"
class="font-medium text-primary underline underline-offset-4">Y2K</a class="text-primary font-medium underline underline-offset-4">Y2K</a
>-le <br /> >-le <br />
Laialdaselt kasutatud süsteem aja ja kuupäeva märkimiseks <strong>saab otsa.</strong> Laialdaselt kasutatud süsteem aja ja kuupäeva märkimiseks <strong>saab otsa.</strong>
</p> </p>
<p class="leading-7 [&:not(:first-child)]:mt-6"> <p class="leading-7 not-first:mt-6">
Enamus Linuxi baasiga Operatsioonisüsteeme kasutab aja märkimiseks <a Enamus Linuxi baasiga Operatsioonisüsteeme kasutab aja märkimiseks <a
href="https://en.wikipedia.org/wiki/Unix_time" href="https://en.wikipedia.org/wiki/Unix_time"
class="font-medium text-primary underline underline-offset-4">UNIX aega</a class="text-primary font-medium underline underline-offset-4">UNIX aega</a
> >
- mitu sekundit on möödunud UNIX <i>epoch</i>-ist 00:00:00 19.01.1970 UTC. - mitu sekundit on möödunud UNIX <i>epoch</i>-ist 00:00:00 19.01.1970 UTC.
</p> </p>
<p class="leading-7 [&:not(:first-child)]:mt-6"> <p class="leading-7 not-first:mt-6">
Neid sekundeid hoitaks <i>signed 32-bit</i> täisarvuna. Selle andmetüübi maksimaalne Neid sekundeid hoitaks <i>signed 32-bit</i> täisarvuna. Selle andmetüübi maksimaalne
väärtus on väärtus on
<code <code
class="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold" class="bg-muted relative rounded px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold"
>2<sup>31</sup>-1</code >2<sup>31</sup>-1</code
>. Viimane kuupäev (<code >. Viimane kuupäev (<code
class="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold" class="bg-muted relative rounded px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold"
>UNIX epoch + 2<sup>31</sup>-1</code >UNIX epoch + 2<sup>31</sup>-1</code
>) on 03:14:07 19.01.2038 UTC. >) on 03:14:07 19.01.2038 UTC.
</p> </p>
<p class="leading-7 [&:not(:first-child)]:mt-6"> <p class="leading-7 not-first:mt-6">
Sekund pärast seda, kui arvutid lisavad ajale sekundi juurde, juhtub <a Sekund pärast seda, kui arvutid lisavad ajale sekundi juurde, juhtub <a
href="https://en.wikipedia.org/wiki/Integer_overflow" href="https://en.wikipedia.org/wiki/Integer_overflow"
class="font-medium text-primary underline underline-offset-4">täisarvu ületäitumine</a class="text-primary font-medium underline underline-offset-4">täisarvu ületäitumine</a
> >
ja aja väärtuseks saab ja aja väärtuseks saab
<code <code
class="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold" class="bg-muted relative rounded px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold"
>-2<sup>31</sup></code >-2<sup>31</sup></code
>. <br /> >. <br />
Arvutid loevad seda kui 20:45:52 13.12.1901 UTC, ehk varaseim võimalik aeg Arvutid loevad seda kui 20:45:52 13.12.1901 UTC, ehk varaseim võimalik aeg
<a <a
href="https://en.wikipedia.org/wiki/Unix_time" href="https://en.wikipedia.org/wiki/Unix_time"
class="font-medium text-primary underline underline-offset-4">UNIX aja</a class="text-primary font-medium underline underline-offset-4">UNIX aja</a
> järgi. > järgi.
</p> </p>
</Accordion.Content> </Accordion.Content>

View file

@ -41,7 +41,7 @@
> >
{#each { length: 3 }} {#each { length: 3 }}
{#if i < 2} {#if i < 2}
<Skeleton class="h-[5rem] w-full rounded-xl border border-primary/5" /> <Skeleton class="border-primary/5 h-[5rem] w-full rounded-xl border" />
{:else} {:else}
<Skeleton class="aspect-square h-auto max-w-full rounded-xl object-cover" /> <Skeleton class="aspect-square h-auto max-w-full rounded-xl object-cover" />
{/if} {/if}
@ -86,9 +86,9 @@
</AlertDialog.Content> </AlertDialog.Content>
</AlertDialog.Root> </AlertDialog.Root>
<header class="mb-12 flex flex-col items-center text-center font-title"> <header class="font-title mb-12 flex flex-col items-center text-center">
<h1 class="mb-1 scroll-m-20 text-5xl font-extrabold tracking-tight lg:text-6xl">Paku biiti</h1> <h1 class="mb-1 scroll-m-20 text-5xl font-extrabold tracking-tight lg:text-6xl">Paku biiti</h1>
<p class="text-xl font-semibold text-muted-foreground"> <p class="text-muted-foreground text-xl font-semibold">
Lohista kokku õiged albumi <span class="text-red-600 dark:text-red-400">nimed</span>, 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-purple-600 dark:text-purple-400">artistid</span> ja
<span class="text-blue-600 dark:text-blue-400">pildid</span>. <span class="text-blue-600 dark:text-blue-400">pildid</span>.

View file

@ -3,17 +3,9 @@ import type { Config } from 'tailwindcss';
import tailwindcssAnimate from 'tailwindcss-animate'; import tailwindcssAnimate from 'tailwindcss-animate';
const config: Config = { const config: Config = {
darkMode: ['class'], darkMode: ['class', 'dark'],
content: ['./src/**/*.{html,js,svelte,ts}'], content: ['./src/**/*.{html,js,svelte,ts}'],
safelist: ['dark'],
theme: { theme: {
container: {
center: true,
padding: '2rem',
screens: {
'2xl': '1400px'
}
},
extend: { extend: {
colors: { colors: {
border: 'hsl(var(--border) / <alpha-value>)', border: 'hsl(var(--border) / <alpha-value>)',
@ -91,7 +83,11 @@ const config: Config = {
'caret-blink': 'caret-blink 1.25s ease-out infinite' 'caret-blink': 'caret-blink 1.25s ease-out infinite'
}, },
transitionTimingFunction: { transitionTimingFunction: {
default: 'cubic-bezier(0.16, 1, 0.3, 1)' default: 'cubic-bezier(0.16, 1, 0.3, 1)',
in: 'cubic-bezier(0.7, 0, 0.84, 0)',
out: 'cubic-bezier(0.16, 1, 0.3, 1)',
'in-out': 'cubic-bezier(0.87, 0, 0.13, 1)',
bouncy: 'cubic-bezier(.65,.01,.04,.97)'
} }
} }
}, },