bonfire/src/routes/project.svelte

199 lines
5.4 KiB
Svelte
Raw Normal View History

2025-10-18 22:43:18 +03:30
<script context="module">
</script>
2025-10-11 22:53:08 +03:30
<script lang="ts">
2025-10-19 23:40:22 +03:30
import { ChevronDown, ChevronUp, BookText, Github, Gitlab, Code, GitBranch } from 'lucide-svelte';
2025-10-18 22:43:18 +03:30
interface ProjectData {
title: string | undefined;
2025-10-19 23:40:22 +03:30
icon: string;
headline: string;
2025-10-20 16:53:59 +03:30
description: string;
2025-10-18 22:43:18 +03:30
forge: string | undefined;
codeberg: string | undefined;
github: string | undefined;
gitlab: string | undefined;
2025-10-19 23:40:22 +03:30
docs: string | undefined;
gallery: string[] | undefined;
2025-10-18 22:43:18 +03:30
}
2025-10-13 22:18:43 +03:30
import LanguageStats from './languages.svelte';
2025-10-11 22:53:08 +03:30
import TiltCard from './tiltcard.svelte';
2025-10-19 23:40:22 +03:30
export let data: ProjectData = {
title: '',
icon: '',
headline: '',
2025-10-20 16:53:59 +03:30
description: '',
2025-10-19 23:40:22 +03:30
forge: '',
codeberg: '',
github: '',
gitlab: '',
docs: '',
gallery: undefined
};
2025-10-18 22:43:18 +03:30
2025-10-20 16:53:59 +03:30
let expanded = false;
2025-10-11 22:53:08 +03:30
import { slide } from 'svelte/transition';
2025-10-13 22:18:43 +03:30
let tiltX = 0;
let tiltY = 0;
function handleMouseMove(event: MouseEvent) {
const card = event.currentTarget as HTMLElement;
const rect = card.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
const centerX = rect.width / 2;
const centerY = rect.height / 2;
const percentX = (x - centerX) / centerX;
const percentY = (centerY - y) / centerY; // Invert Y for natural tilt
const maxTilt = 2;
tiltX = percentY * maxTilt;
tiltY = percentX * maxTilt;
}
function handleMouseLeave() {
tiltX = 0;
tiltY = 0;
}
2025-10-11 22:53:08 +03:30
</script>
2025-10-13 22:18:43 +03:30
<!-- svelte-ignore a11y_no_static_element_interactions -->
2025-10-11 22:53:08 +03:30
<div
class="bg-card border-border relative mx-auto w-full max-w-2xl rounded-lg border transition-all duration-300 ease-out hover:scale-[1.01] hover:shadow-[5px_5px_5px_#000000]"
2025-10-13 22:18:43 +03:30
style="transform: perspective(1000px) rotateX({tiltX}deg) rotateY({tiltY}deg);"
on:mousemove={handleMouseMove}
on:mouseleave={handleMouseLeave}
2025-10-11 22:53:08 +03:30
>
<div class="p-6">
2025-10-19 23:40:22 +03:30
<div class="mb-4 flex items-center gap-4">
<div class="flex-shrink-0">
<TiltCard imageSrc={data.icon} imageAlt="{data.title} icon" width="256px" height="256px" />
2025-10-13 22:18:43 +03:30
</div>
<div class="m-4 min-w-0 flex-1">
<div>
2025-10-19 23:40:22 +03:30
<h1 class="font-mono text-4xl uppercase">{data.title}</h1>
2025-10-11 22:53:08 +03:30
2025-10-13 22:18:43 +03:30
<div class="border-border w-full self-center border-t p-1"></div>
<p class="text-muted-foreground leading-relaxed">
2025-10-19 23:40:22 +03:30
{data.headline}
2025-10-13 22:18:43 +03:30
</p>
</div>
2025-10-11 22:53:08 +03:30
</div>
2025-10-19 23:40:22 +03:30
</div>
{#if expanded}
<div transition:slide={{ duration: 150 }} class="ease-in">
2025-10-13 22:18:43 +03:30
<p class="text-muted-foreground pb-8 leading-relaxed">
2025-10-20 16:53:59 +03:30
{data.description}
2025-10-13 22:18:43 +03:30
</p>
2025-10-19 23:40:22 +03:30
{#if data.gallery}
<h3 class="text-muted-foreground mb-3 text-sm font-semibold uppercase tracking-wide">
Gallery
</h3>
2025-10-13 22:18:43 +03:30
2025-10-19 23:40:22 +03:30
<div class="mb-4 grid grid-cols-3 gap-2">
{#each data.gallery as img}
<img src={img} alt="{data.title} screenshot" class="rounded object-cover" />
{/each}
</div>
{/if}
2025-10-11 22:53:08 +03:30
2025-10-13 22:18:43 +03:30
<div class="flex items-start justify-start gap-0">
<div class="flex-none">
<h3 class="text-muted-foreground mb-2 text-sm font-semibold uppercase tracking-wide">
Source
</h3>
<div class="flex flex-wrap gap-3">
<a
2025-10-19 23:40:22 +03:30
href={data.forge}
2025-10-13 22:18:43 +03:30
target="_blank"
rel="noopener noreferrer"
class="text-accent-foreground flex items-center gap-1 transition-colors duration-200 hover:underline"
>
2025-10-19 23:40:22 +03:30
<GitBranch />
Forge
2025-10-13 22:18:43 +03:30
</a>
2025-10-19 23:40:22 +03:30
{#if data.docs}
<a
href={data.docs}
target="_blank"
rel="noopener noreferrer"
class="text-accent-foreground flex items-center gap-1 transition-colors duration-200 hover:underline"
>
<BookText class="h-4 w-4" />
Documentation
</a>
{/if}
2025-10-13 22:18:43 +03:30
</div>
</div>
<div class="border-border mx-4 h-8 self-center border-l"></div>
<div class="flex-none">
<h3 class="text-muted-foreground mb-2 text-sm font-semibold uppercase tracking-wide">
Mirrors
</h3>
<div class="flex flex-wrap gap-3">
2025-10-19 23:40:22 +03:30
<a
href={data.github}
target="_blank"
rel="noopener noreferrer"
class="text-accent-foreground flex items-center gap-1 transition-colors duration-200 hover:underline"
>
<Github class="h-4 w-4" />
Github
</a>
2025-10-18 22:43:18 +03:30
<a
href={data.gitlab}
target="_blank"
rel="noopener noreferrer"
class="text-accent-foreground flex items-center gap-1 transition-colors duration-200 hover:underline"
>
<Gitlab class="h-4 w-4" />
2025-10-19 23:40:22 +03:30
Gitlab
</a>
<a
href={data.gitlab}
target="_blank"
rel="noopener noreferrer"
class="text-accent-foreground flex items-center gap-1 transition-colors duration-200 hover:underline"
>
<Code class="h-4 w-4" />
Codeberg
2025-10-18 22:43:18 +03:30
</a>
2025-10-11 22:53:08 +03:30
</div>
</div>
</div>
</div>
{/if}
</div>
<button
2025-10-19 23:40:22 +03:30
on:click={function () {
expanded = !expanded;
}}
2025-10-11 22:53:08 +03:30
class="bg-muted/50 hover:bg-muted text-muted-foreground hover:text-foreground border-border group flex w-full items-center justify-center gap-2 rounded-b-lg border-t px-6 py-3 transition-colors duration-200"
>
2025-10-19 23:40:22 +03:30
{#if expanded}
2025-10-11 22:53:08 +03:30
<ChevronUp
class="h-4 w-16 transition-transform duration-200 group-hover:translate-y-[-2px]"
/>
{:else}
<ChevronDown
class="h-30 w-30 transition-transform duration-200 group-hover:translate-y-[2px]"
/>
<span class="font-bold">
2025-10-19 23:40:22 +03:30
{#if !expanded}
2025-10-13 22:18:43 +03:30
DETAILS
2025-10-11 22:53:08 +03:30
{/if}
</span>
<ChevronDown
class="h-30 w-30 transition-transform duration-200 group-hover:translate-y-[2px]"
/>
{/if}
</button>
</div>