Compare commits
3 commits
7de8638796
...
fd0e12b665
Author | SHA1 | Date | |
---|---|---|---|
![]() |
fd0e12b665 | ||
![]() |
cd9cd98008 | ||
![]() |
ba34242475 |
26 changed files with 827 additions and 1007 deletions
25
package.json
25
package.json
|
@ -13,41 +13,42 @@
|
|||
"lint": "prettier --check . && eslint ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/compat": "^1.2.5",
|
||||
"@eslint/js": "^9.18.0",
|
||||
"@eslint/compat": "^1.2.6",
|
||||
"@eslint/js": "^9.19.0",
|
||||
"@sveltejs/adapter-node": "^5.2.12",
|
||||
"@sveltejs/enhanced-img": "^0.4.4",
|
||||
"@sveltejs/kit": "^2.16.1",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||
"@tailwindcss/container-queries": "^0.1.1",
|
||||
"@tailwindcss/forms": "^0.5.10",
|
||||
"@tailwindcss/postcss": "^4.0.1",
|
||||
"@tailwindcss/vite": "^4.0.1",
|
||||
"@types/spotify-web-api-node": "^5.0.11",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"bits-ui": "1.0.0-next.80",
|
||||
"clsx": "^2.1.1",
|
||||
"eslint": "^9.18.0",
|
||||
"eslint": "^9.19.0",
|
||||
"eslint-config-prettier": "^10.0.1",
|
||||
"eslint-plugin-svelte": "^2.46.1",
|
||||
"globals": "^15.14.0",
|
||||
"lucide-svelte": "^0.473.0",
|
||||
"lucide-svelte": "^0.474.0",
|
||||
"prettier": "^3.4.2",
|
||||
"prettier-plugin-svelte": "^3.3.3",
|
||||
"prettier-plugin-tailwindcss": "^0.6.10",
|
||||
"svelte": "^5.19.1",
|
||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||
"svelte": "^5.19.6",
|
||||
"svelte-check": "^4.1.4",
|
||||
"svelte-dnd-action": "^0.9.55",
|
||||
"tailwind-merge": "^2.6.0",
|
||||
"svelte-dnd-action": "^0.9.56",
|
||||
"tailwind-merge": "^3.0.1",
|
||||
"tailwind-variants": "^0.3.1",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"tailwindcss": "^4.0.1",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"typescript": "^5.7.3",
|
||||
"typescript-eslint": "^8.21.0",
|
||||
"typescript-eslint": "^8.22.0",
|
||||
"vite": "^6.0.11"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource-variable/kode-mono": "^5.1.1",
|
||||
"@fontsource-variable/smooch-sans": "^5.1.1",
|
||||
"mode-watcher": "^0.5.0",
|
||||
"mode-watcher": "^0.5.1",
|
||||
"nanoid": "^5.0.9",
|
||||
"spotify-web-api-node": "^5.0.2",
|
||||
"svelte-kit-sessions": "^0.4.0"
|
||||
|
|
1195
pnpm-lock.yaml
generated
1195
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,5 @@
|
|||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {}
|
||||
'@tailwindcss/postcss': {}
|
||||
}
|
||||
};
|
||||
|
|
59
src/app.css
59
src/app.css
|
@ -1,6 +1,42 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@import 'tailwindcss';
|
||||
|
||||
@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 {
|
||||
:root {
|
||||
|
@ -73,20 +109,3 @@
|
|||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<Link class={className} />
|
||||
{/if}
|
||||
|
||||
<span>
|
||||
<span class="underline underline-offset-4">
|
||||
{author}
|
||||
</span>
|
||||
{/snippet}
|
||||
|
@ -49,7 +49,10 @@
|
|||
{#each tags as { name, description }}
|
||||
<HoverCard.Root>
|
||||
<HoverCard.Trigger>
|
||||
<Badge class="transition-none" variant={badgeVariant}>{name}</Badge>
|
||||
<Badge
|
||||
class="font-title text-base font-semibold leading-relaxed tracking-wide"
|
||||
variant={badgeVariant}>{name}</Badge
|
||||
>
|
||||
</HoverCard.Trigger>
|
||||
<HoverCard.Content>
|
||||
{description}
|
||||
|
@ -65,7 +68,7 @@
|
|||
class="flex items-center justify-center px-4 py-2 font-mono text-xs font-semibold text-secondary/80 dark:text-primary/80"
|
||||
>
|
||||
{#if image.credit.href}
|
||||
<a class="w-full transition-colors hover:text-white" href={image.credit.href}>
|
||||
<a class="w-full" href={image.credit.href}>
|
||||
{@render creditText(
|
||||
image.credit.author,
|
||||
image.credit.type,
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<AlertDialogPrimitive.Content
|
||||
bind:ref
|
||||
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
|
||||
)}
|
||||
{...restProps}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
<script lang="ts" module>
|
||||
import { type VariantProps, tv } from 'tailwind-variants';
|
||||
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: {
|
||||
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:
|
||||
'bg-secondary text-secondary-foreground hover:bg-secondary/80 border-transparent',
|
||||
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'
|
||||
}
|
||||
},
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
import { type VariantProps, tv } from 'tailwind-variants';
|
||||
|
||||
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: {
|
||||
variant: {
|
||||
default: 'bg-primary text-primary-foreground hover:bg-primary/90 shadow',
|
||||
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90 shadow-sm',
|
||||
default: 'bg-primary text-primary-foreground hover:bg-primary/90 shadow-sm',
|
||||
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90 shadow-xs',
|
||||
outline:
|
||||
'border-input bg-background hover:bg-accent hover:text-accent-foreground border shadow-sm',
|
||||
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80 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-xs',
|
||||
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
||||
link: 'text-primary underline-offset-4 hover:underline'
|
||||
},
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
<div
|
||||
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}
|
||||
>
|
||||
{@render children?.()}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
{sideOffset}
|
||||
{align}
|
||||
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
|
||||
)}
|
||||
{...restProps}
|
||||
|
|
|
@ -1,34 +1,16 @@
|
|||
import type { GamesObj, TagsObj } from './types';
|
||||
|
||||
export const site = {
|
||||
name: 'Stuff.Kasterpalu',
|
||||
name: 'Mihkel Martin Kasterpalu',
|
||||
author: 'Mihkel Martin Kasterpalu',
|
||||
description: 'Minimängud ja muud huvitavat.',
|
||||
description: 'Portfoolio - Arendaja, Disainer, Muusik, DJ, Ettevõtja.',
|
||||
image: '/web-app-manifest-512x512.png'
|
||||
};
|
||||
|
||||
export const baseURL = 'https://stuff.kasterpalu.ee';
|
||||
|
||||
export const games: GamesObj = {
|
||||
'/epochalypse': {
|
||||
name: 'Epochalypse',
|
||||
image: '',
|
||||
description: 'Varsti veel üks Y2K. Kui nostalgiline!'
|
||||
},
|
||||
'/pakubiiti': {
|
||||
name: 'Paku biiti',
|
||||
image: '',
|
||||
description: 'Sorteeri kolme suvalise muusika albumi pealkiri, artistid ja pilt.'
|
||||
},
|
||||
'': {
|
||||
name: 'Rohkem mänge soon™',
|
||||
image: '',
|
||||
description: ''
|
||||
}
|
||||
export const stuffSite = {
|
||||
name: 'Kasterpalu Stuff',
|
||||
author: 'Mihkel Martin Kasterpalu',
|
||||
description:
|
||||
'Minimängud ja muud huvitavat. Kui mul tekkis lahe idee ja suutsin sellest midagi lahedat arendada siis näed seda ka siin.',
|
||||
image: '/web-app-manifest-512x512.png'
|
||||
};
|
||||
|
||||
export const badges: TagsObj = {
|
||||
muusika: { name: 'Muusika', description: 'Tegelen siin muusikaga' },
|
||||
veeb: { name: 'Veebileht', description: 'Disainisin/kirjutasin veebilehe' },
|
||||
asutaja: { name: 'Asutaja', description: 'Olin osa selle loomisest' }
|
||||
};
|
||||
export const baseURL = 'https://kasterpalu.ee';
|
||||
|
|
9
src/lib/data/badges.ts
Normal file
9
src/lib/data/badges.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import type { TagsObj } from '$lib/types';
|
||||
|
||||
const badges: TagsObj = {
|
||||
muusika: { name: 'Muusika', description: 'Tegelen siin muusikaga' },
|
||||
veeb: { name: 'Veebileht', description: 'Disainisin/kirjutasin veebilehe' },
|
||||
asutaja: { name: 'Asutaja', description: 'Olin osa selle loomisest' }
|
||||
};
|
||||
|
||||
export default badges;
|
21
src/lib/data/games.ts
Normal file
21
src/lib/data/games.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import type { GamesObj } from '$lib/types';
|
||||
|
||||
const games: GamesObj = {
|
||||
epochalypse: {
|
||||
name: 'Epochalypse',
|
||||
image: '',
|
||||
description: 'Varsti veel üks Y2K. Kui nostalgiline!'
|
||||
},
|
||||
pakubiiti: {
|
||||
name: 'Paku biiti',
|
||||
image: '',
|
||||
description: 'Sorteeri kolme suvalise muusika albumi pealkiri, artistid ja pilt.'
|
||||
},
|
||||
'': {
|
||||
name: 'Rohkem mänge soon™',
|
||||
image: '',
|
||||
description: ''
|
||||
}
|
||||
};
|
||||
|
||||
export default games;
|
82
src/lib/data/projects.ts
Normal file
82
src/lib/data/projects.ts
Normal file
|
@ -0,0 +1,82 @@
|
|||
import type { Project } from '$lib/types';
|
||||
import badges from './badges';
|
||||
|
||||
import skpImg from '$lib/assets/skp.jpg?enhanced';
|
||||
import dysasterImg from '$lib/assets/dysaster.jpg?enhanced';
|
||||
import monospaceeImg from '$lib/assets/monospacee.jpg?enhanced';
|
||||
import saueauguImg from '$lib/assets/saueaugu.jpg?enhanced';
|
||||
|
||||
const projects: Project[] = [
|
||||
{
|
||||
name: 'SUPIKÖÖGIPOSID',
|
||||
image: {
|
||||
src: skpImg,
|
||||
credit: {
|
||||
type: 'instagram',
|
||||
author: 'Mimmu',
|
||||
href: 'https://www.instagram.com/musamimmu/'
|
||||
},
|
||||
alt: 'Pilt neljaliikmeliseslt räpibändist SUPIKÖÖGIPOISID. Pilt on tehtud pilves ilmaga õues. Pildil on 4 mees valgete triiksärkide, mustade lipsude ja mustade tagidega.'
|
||||
},
|
||||
description: 'Räpikollektiiv. Alustasime 2019.',
|
||||
link: 'https://skpoisid.bandcamp.com/',
|
||||
tags: [badges['muusika']]
|
||||
},
|
||||
{
|
||||
name: 'Dysaster Collective',
|
||||
image: {
|
||||
src: dysasterImg,
|
||||
credit: {
|
||||
type: 'instagram',
|
||||
author: 'Mattias Mägi',
|
||||
href: 'https://www.instagram.com/mattias.mix/'
|
||||
},
|
||||
alt: 'Sinakas digitaalne kollaž Dysaster Collective liigetest.'
|
||||
},
|
||||
description: '2022 asutatud mitmekülgne loomekollektiiv.',
|
||||
link: 'https://dysaster.ee',
|
||||
tags: [badges['asutaja'], badges['veeb']]
|
||||
},
|
||||
{
|
||||
name: 'monospac.ee',
|
||||
image: {
|
||||
src: monospaceeImg,
|
||||
credit: {
|
||||
type: 'instagram',
|
||||
author: 'Liisa Jõhvik',
|
||||
href: 'https://www.instagram.com/liisajohvik.photo/'
|
||||
},
|
||||
alt: 'DJ duo monospacee nende Silent Disco setil Tartu Uus Teater saalis aastal 2024. Pilt on külje pealt, esiplaanil DJ Mimmu ja ta tagant paistab DJ Rx. Nad on valgustatud punasesega, taustal häguselt näha siniselt valgustatud kolmandat DJd.'
|
||||
},
|
||||
description: 'DJ duo kaasliikmega Rx.',
|
||||
link: 'https://monospac.ee',
|
||||
tags: [badges['muusika'], badges['veeb']]
|
||||
},
|
||||
{
|
||||
name: 'Saueagu Teatritalu',
|
||||
image: {
|
||||
src: saueauguImg,
|
||||
alt: 'Suvine Saueaugu teatrihoone. All paistab roheline muru ja katuse tagant paistab paari pilvega sinine taevas.'
|
||||
},
|
||||
description: 'Taluteater Läänemaal. Tegin veebilehe.',
|
||||
link: 'https://saueaugu.ee',
|
||||
tags: [badges['veeb']]
|
||||
},
|
||||
{
|
||||
name: 'Tartu Häkkerikoda',
|
||||
image: {
|
||||
src: '/assets/hakkerikoda.svg',
|
||||
credit: {
|
||||
type: 'web',
|
||||
author: 'treierxyz',
|
||||
href: 'https://treier.xyz'
|
||||
},
|
||||
alt: 'Tartu Häkkerikoda logo'
|
||||
},
|
||||
description: 'Makerspace Tartus. Liige ning osa veebilehe loojatest.',
|
||||
link: 'https://hakkerikoda.ee',
|
||||
tags: [badges['veeb']]
|
||||
}
|
||||
];
|
||||
|
||||
export default projects;
|
|
@ -1,23 +0,0 @@
|
|||
<script lang="ts">
|
||||
import { baseURL, site } from '$lib/config.js';
|
||||
|
||||
let { children, data } = $props();
|
||||
|
||||
const title = data?.name ? `${data.name} | ${site.name}` : site.name;
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{title}</title>
|
||||
<meta property="og:title" content={title} />
|
||||
|
||||
{#if data?.description}
|
||||
<meta name="description" content={data.description} />
|
||||
<meta property="og:description" content={data.description} />
|
||||
{/if}
|
||||
|
||||
{#if data?.image}
|
||||
<meta property="og:image" content={baseURL + data.image} />
|
||||
{/if}
|
||||
</svelte:head>
|
||||
|
||||
{@render children()}
|
|
@ -40,20 +40,23 @@
|
|||
<a href="/">
|
||||
<img src="/favicon.svg" alt="Mihkel Martin Kasterpalu logo" class="h-9" />
|
||||
</a>
|
||||
|
||||
<a class="font-mono font-medium underline underline-offset-4" href="/vinge"> vinge värk </a>
|
||||
|
||||
<Button onclick={() => cycleTheme()} variant="ghost" size="icon" class="h-12 w-12">
|
||||
{#if theme === 'dark'}
|
||||
<Moon class="!h-6 !w-6" />
|
||||
<Moon class="h-6! w-6!" />
|
||||
{:else if theme === 'light'}
|
||||
<Sun class="!h-6 !w-6" />
|
||||
<Sun class="h-6! w-6!" />
|
||||
{:else}
|
||||
<LaptopMinimal class="!h-6 !w-6" />
|
||||
<LaptopMinimal class="h-6! w-6!" />
|
||||
{/if}
|
||||
|
||||
<span class="sr-only">Toggle theme</span>
|
||||
</Button>
|
||||
</header>
|
||||
|
||||
<div class="container relative flex flex-col items-center">
|
||||
<div class="container relative mt-8 flex flex-col items-center">
|
||||
{@render children()}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,7 +1,35 @@
|
|||
<script lang="ts">
|
||||
import { site, baseURL, games } from '$lib/config';
|
||||
import type { EnhancedImage, Tag } from '$lib/types';
|
||||
import { site, baseURL } from '$lib/config';
|
||||
|
||||
import SquareArrowOutUpRight from 'lucide-svelte/icons/square-arrow-out-up-right';
|
||||
|
||||
import { Button } from '$lib/components/ui/button/index.js';
|
||||
import Image from '$lib/components/Image.svelte';
|
||||
import projects from '$lib/data/projects';
|
||||
</script>
|
||||
|
||||
{#snippet projectCard(
|
||||
name: string,
|
||||
description: string,
|
||||
image: EnhancedImage,
|
||||
tags: Tag[],
|
||||
link: string
|
||||
)}
|
||||
<div class="mb-16 w-80 space-y-3 md:w-64">
|
||||
<Image {image} {tags} class="aspect-4/5 object-cover" />
|
||||
<div class="grid grid-cols-[1fr_auto] items-center text-sm">
|
||||
<div class="mt-1 pr-4">
|
||||
<h3 class="text-lg font-medium leading-none">{name}</h3>
|
||||
<p class="mt-1.5 text-sm leading-5 text-muted-foreground">{description}</p>
|
||||
</div>
|
||||
<Button target="_blank" href={link} variant="secondary" size="icon">
|
||||
<SquareArrowOutUpRight />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
<svelte:head>
|
||||
<title>{site.name}</title>
|
||||
<meta property="og:title" content={site.name} />
|
||||
|
@ -16,31 +44,13 @@
|
|||
<h1 class="mb-1 scroll-m-20 text-5xl font-extrabold tracking-tight lg:text-6xl">
|
||||
Hei! Mina olen Mihkel
|
||||
</h1>
|
||||
<p class="text-xl font-semibold text-muted-foreground">
|
||||
Siin saidil on mu loodud minimängud ja muud huvitavat. Aitäh <a
|
||||
href="https://neal.fun"
|
||||
class="font-medium underline underline-offset-4">neal.fun</a
|
||||
> inspo eest :]
|
||||
</p>
|
||||
<p class="text-xl font-semibold text-muted-foreground">
|
||||
Vaata ka mu
|
||||
<a href="/projektid" class="text-primary underline underline-offset-4">teisi projekte</a>.
|
||||
<p class="font-sans text-base text-muted-foreground">
|
||||
Peale selle toreda saidi on mul veel palju hobisid
|
||||
</p>
|
||||
</header>
|
||||
<main class="grid w-full max-w-4xl justify-items-center gap-y-8 lg:grid-cols-2">
|
||||
{#each Object.entries(games) as [href, { image, name }]}
|
||||
<a
|
||||
class="shadow-sharp flex aspect-[4/1] w-full 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'
|
||||
: ''}"
|
||||
style="background-image: url('{image}')"
|
||||
draggable="false"
|
||||
{href}
|
||||
>
|
||||
<span class="relative block select-none rounded font-mono text-2xl font-semibold lg:text-3xl">
|
||||
{name}
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<main class="flex w-full flex-wrap justify-center gap-x-8">
|
||||
{#each projects as { name, description, image, tags, link }}
|
||||
{@render projectCard(name, description, image, tags, link)}
|
||||
{/each}
|
||||
</main>
|
||||
|
|
|
@ -1,139 +0,0 @@
|
|||
<script lang="ts">
|
||||
import type { EnhancedImage, Project, Tag } from '$lib/types';
|
||||
import { site, baseURL, badges } from '$lib/config';
|
||||
|
||||
import SquareArrowOutUpRight from 'lucide-svelte/icons/square-arrow-out-up-right';
|
||||
|
||||
import { Button } from '$lib/components/ui/button/index.js';
|
||||
import Image from '$lib/components/Image.svelte';
|
||||
|
||||
import skpImg from '$lib/assets/skp.jpg?enhanced';
|
||||
import dysasterImg from '$lib/assets/dysaster.jpg?enhanced';
|
||||
import monospaceeImg from '$lib/assets/monospacee.jpg?enhanced';
|
||||
import saueauguImg from '$lib/assets/saueaugu.jpg?enhanced';
|
||||
|
||||
export const projects: Project[] = [
|
||||
{
|
||||
name: 'SUPIKÖÖGIPOSID',
|
||||
image: {
|
||||
src: skpImg,
|
||||
credit: {
|
||||
type: 'instagram',
|
||||
author: 'Mimmu',
|
||||
href: 'https://www.instagram.com/musamimmu/'
|
||||
},
|
||||
alt: 'Pilt neljaliikmeliseslt räpibändist SUPIKÖÖGIPOISID. Pilt on tehtud pilves ilmaga õues. Pildil on 4 mees valgete triiksärkide, mustade lipsude ja mustade tagidega.'
|
||||
},
|
||||
description: 'Räpikollektiiv. Alustasime 2019.',
|
||||
link: 'https://skpoisid.bandcamp.com/',
|
||||
tags: [badges['muusika']]
|
||||
},
|
||||
{
|
||||
name: 'Dysaster Collective',
|
||||
image: {
|
||||
src: dysasterImg,
|
||||
credit: {
|
||||
type: 'instagram',
|
||||
author: 'Mattias Mägi',
|
||||
href: 'https://www.instagram.com/mattias.mix/'
|
||||
},
|
||||
alt: 'Sinakas digitaalne kollaž Dysaster Collective liigetest.'
|
||||
},
|
||||
description: '2022 asutatud mitmekülgne loomekollektiiv.',
|
||||
link: 'https://dysaster.ee',
|
||||
tags: [badges['asutaja'], badges['veeb']]
|
||||
},
|
||||
{
|
||||
name: 'monospac.ee',
|
||||
image: {
|
||||
src: monospaceeImg,
|
||||
credit: {
|
||||
type: 'instagram',
|
||||
author: 'Liisa Jõhvik',
|
||||
href: 'https://www.instagram.com/liisajohvik.photo/'
|
||||
},
|
||||
alt: 'DJ duo monospacee nende Silent Disco setil Tartu Uus Teater saalis aastal 2024. Pilt on külje pealt, esiplaanil DJ Mimmu ja ta tagant paistab DJ Rx. Nad on valgustatud punasesega, taustal häguselt näha siniselt valgustatud kolmandat DJd.'
|
||||
},
|
||||
description: 'DJ duo kaasliikmega Rx.',
|
||||
link: 'https://monospac.ee',
|
||||
tags: [badges['muusika'], badges['veeb']]
|
||||
},
|
||||
{
|
||||
name: 'Saueagu Teatritalu',
|
||||
image: {
|
||||
src: saueauguImg,
|
||||
alt: 'Suvine Saueaugu teatrihoone. All paistab roheline muru ja katuse tagant paistab paari pilvega sinine taevas.'
|
||||
},
|
||||
description: 'Taluteater Läänemaal. Tegin veebilehe.',
|
||||
link: 'https://saueaugu.ee',
|
||||
tags: [badges['veeb']]
|
||||
},
|
||||
{
|
||||
name: 'Tartu Häkkerikoda',
|
||||
image: {
|
||||
src: '/assets/hakkerikoda.svg',
|
||||
credit: {
|
||||
type: 'web',
|
||||
author: 'treierxyz',
|
||||
href: 'https://treier.xyz'
|
||||
},
|
||||
alt: 'Tartu Häkkerikoda logo'
|
||||
},
|
||||
description: 'Makerspace Tartus. Liige ning osa veebilehe loojatest.',
|
||||
link: 'https://hakkerikoda.ee',
|
||||
tags: [badges['veeb']]
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
||||
{#snippet projectCard(
|
||||
name: string,
|
||||
description: string,
|
||||
image: EnhancedImage,
|
||||
tags: Tag[],
|
||||
link: string
|
||||
)}
|
||||
<div class="mb-16 w-80 space-y-3 md:w-64">
|
||||
<Image {image} {tags} class="aspect-[4/5] object-cover" />
|
||||
<div class="grid grid-cols-[1fr_auto] items-center text-sm">
|
||||
<div class="mt-2 pr-4">
|
||||
<h3 class="font-medium leading-none">{name}</h3>
|
||||
<p class="mt-2 text-xs leading-5 text-muted-foreground">{description}</p>
|
||||
</div>
|
||||
<Button target="_blank" href={link} variant="secondary" size="icon">
|
||||
<SquareArrowOutUpRight />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
<svelte:head>
|
||||
<title>Projektid | {site.name}</title>
|
||||
<meta property="og:title" content={'Projektid | ' + site.name} />
|
||||
|
||||
<meta
|
||||
name="description"
|
||||
content="Projektid millega tegelenud, asjad mida teinud - tule uudista."
|
||||
/>
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Projektid millega tegelenud, asjad mida teinud - tule uudista."
|
||||
/>
|
||||
|
||||
<meta property="og:image" content={baseURL + site.image} />
|
||||
</svelte:head>
|
||||
|
||||
<header class="mb-24 flex flex-col items-center text-center font-title">
|
||||
<h1 class="mb-1 scroll-m-20 text-5xl font-extrabold tracking-tight lg:text-6xl">
|
||||
Muud projektid
|
||||
</h1>
|
||||
<p class="text-xl font-semibold text-muted-foreground">
|
||||
Peale selle toreda saidi on mul veel palju hobisid
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<main class="flex w-full max-w-4xl flex-wrap justify-center gap-x-8">
|
||||
{#each projects as { name, description, image, tags, link }}
|
||||
{@render projectCard(name, description, image, tags, link)}
|
||||
{/each}
|
||||
</main>
|
|
@ -1,12 +1,15 @@
|
|||
import type { LayoutServerData } from './$types';
|
||||
import { games, site } from '$lib/config';
|
||||
import { site } from '$lib/config';
|
||||
import games from '$lib/data/games';
|
||||
|
||||
export const load: LayoutServerData = async ({ url }) => {
|
||||
if (!url?.pathname) {
|
||||
return;
|
||||
}
|
||||
|
||||
const game = games[url.pathname];
|
||||
const gameSlug = url.pathname.split('/').at(-1);
|
||||
|
||||
const game = games[gameSlug];
|
||||
|
||||
if (!game) {
|
||||
return;
|
21
src/routes/vinge/+layout.svelte
Normal file
21
src/routes/vinge/+layout.svelte
Normal file
|
@ -0,0 +1,21 @@
|
|||
<script lang="ts">
|
||||
import { baseURL, stuffSite } from '$lib/config.js';
|
||||
|
||||
let { children, data } = $props();
|
||||
|
||||
const title = data?.name ? `${data.name} | ${stuffSite.name}` : stuffSite.name;
|
||||
const description = data?.description || stuffSite.description;
|
||||
const ogImage = data?.image || stuffSite.image;
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{title}</title>
|
||||
<meta property="og:title" content={title} />
|
||||
|
||||
<meta name="description" content={description} />
|
||||
<meta property="og:description" content={description} />
|
||||
|
||||
<meta property="og:image" content={baseURL + ogImage} />
|
||||
</svelte:head>
|
||||
|
||||
{@render children()}
|
49
src/routes/vinge/+page.svelte
Normal file
49
src/routes/vinge/+page.svelte
Normal file
|
@ -0,0 +1,49 @@
|
|||
<script lang="ts">
|
||||
import { site, baseURL } from '$lib/config';
|
||||
import games from '$lib/data/games';
|
||||
|
||||
let { data } = $props();
|
||||
$inspect(data);
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{site.name}</title>
|
||||
<meta property="og:title" content={site.name} />
|
||||
|
||||
<meta name="description" content={site.description} />
|
||||
<meta property="og:description" content={site.description} />
|
||||
|
||||
<meta property="og:image" content={baseURL + site.image} />
|
||||
</svelte:head>
|
||||
|
||||
<header class="mb-24 flex flex-col items-center text-center font-title">
|
||||
<h1 class="mb-1 scroll-m-20 text-5xl font-extrabold tracking-tight lg:text-6xl">Vinge värk</h1>
|
||||
<p class="font-sans text-base leading-7 text-muted-foreground">
|
||||
Minu loodud minimängud ja muud huvitavat.
|
||||
</p>
|
||||
<p class="font-sans text-base leading-7 text-muted-foreground">
|
||||
Aitäh
|
||||
<a href="https://neal.fun" class="font-medium underline underline-offset-4">neal.fun</a> inspo eest
|
||||
:)
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<div
|
||||
class="mx-auto mb-24 flex w-full flex-wrap items-center justify-center justify-items-center gap-4 gap-x-8 gap-y-8 lg:grid-cols-2"
|
||||
>
|
||||
{#each Object.entries(games) as [href, { image, name }]}
|
||||
<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 ===
|
||||
''
|
||||
? 'pressed pointer-events-none'
|
||||
: ''}"
|
||||
style="background-image: url('{image}')"
|
||||
draggable="false"
|
||||
href="/vinge/{href}"
|
||||
>
|
||||
<span class="relative block select-none rounded font-mono text-lg font-semibold lg:text-xl">
|
||||
{name}
|
||||
</span>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
|
@ -22,14 +22,13 @@
|
|||
{#snippet clockStage(count: number, index: number, title: string, divider = true)}
|
||||
<div class="flex flex-col items-center gap-2">
|
||||
<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
|
||||
style="translate: 0 calc({index} * -2rem); transition-timing-function: cubic-bezier(.65,.01,.04,.97); transition-duration: {index ===
|
||||
count - 1
|
||||
style="translate: 0 calc({index} * -2rem); transition-duration: {index === count - 1
|
||||
? '600ms'
|
||||
: '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}
|
||||
{@render clockDigit(i)}
|
||||
|
@ -37,24 +36,24 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-sm text-muted-foreground">{title}</p>
|
||||
<p class="text-muted-foreground text-sm">{title}</p>
|
||||
</div>
|
||||
{#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}
|
||||
<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>
|
||||
{/if}
|
||||
{/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>
|
||||
<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>
|
||||
<main class="w-full max-w-4xl">
|
||||
<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.months, 'kuud', false)}
|
||||
|
@ -68,45 +67,45 @@
|
|||
<Accordion.Item value="item-1">
|
||||
<Accordion.Trigger>Mis asi see on??</Accordion.Trigger>
|
||||
<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
|
||||
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 />
|
||||
Laialdaselt kasutatud süsteem aja ja kuupäeva märkimiseks <strong>saab otsa.</strong>
|
||||
</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
|
||||
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.
|
||||
</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
|
||||
väärtus on
|
||||
<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
|
||||
>. 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
|
||||
>) on 03:14:07 19.01.2038 UTC.
|
||||
</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
|
||||
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
|
||||
<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
|
||||
>. <br />
|
||||
Arvutid loevad seda kui 20:45:52 13.12.1901 UTC, ehk varaseim võimalik aeg
|
||||
<a
|
||||
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.
|
||||
</p>
|
||||
</Accordion.Content>
|
|
@ -41,7 +41,7 @@
|
|||
>
|
||||
{#each { length: 3 }}
|
||||
{#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}
|
||||
<Skeleton class="aspect-square h-auto max-w-full rounded-xl object-cover" />
|
||||
{/if}
|
||||
|
@ -86,9 +86,9 @@
|
|||
</AlertDialog.Content>
|
||||
</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>
|
||||
<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>,
|
||||
<span class="text-purple-600 dark:text-purple-400">artistid</span> ja
|
||||
<span class="text-blue-600 dark:text-blue-400">pildid</span>.
|
|
@ -3,17 +3,9 @@ import type { Config } from 'tailwindcss';
|
|||
import tailwindcssAnimate from 'tailwindcss-animate';
|
||||
|
||||
const config: Config = {
|
||||
darkMode: ['class'],
|
||||
darkMode: ['class', 'dark'],
|
||||
content: ['./src/**/*.{html,js,svelte,ts}'],
|
||||
safelist: ['dark'],
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
padding: '2rem',
|
||||
screens: {
|
||||
'2xl': '1400px'
|
||||
}
|
||||
},
|
||||
extend: {
|
||||
colors: {
|
||||
border: 'hsl(var(--border) / <alpha-value>)',
|
||||
|
@ -91,7 +83,11 @@ const config: Config = {
|
|||
'caret-blink': 'caret-blink 1.25s ease-out infinite'
|
||||
},
|
||||
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)'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
Loading…
Add table
Reference in a new issue