Private
Public Access
1
0

feat: add project entry component

- update css
- update some styles
This commit is contained in:
2026-01-25 19:25:57 +01:00
parent 8ce5bb4fb5
commit 3f5a3c2a7c
6 changed files with 283 additions and 37 deletions

View File

@@ -33,10 +33,10 @@
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 1rem; gap: 1rem;
margin-top: 5rem; margin-top: 5rem;
padding: 2rem; padding: 2rem;
background-color: var(--color-footer-background); background-color: var(--color-footer-background);
} }
@@ -64,19 +64,23 @@
padding: 0.5rem; padding: 0.5rem;
text-decoration: none; text-decoration: none;
&:visited { &:hover {
color: inherit; color: var(--color-header-hover);
} }
&:visited:not(:hover){
color: inherit;
}
} }
.icon { .icon {
width: 1em; width: 1em;
height: 1em; height: 1em;
} }
div { div {
font-size: 0.875rem; font-size: 0.875rem;
color: var(--color-text-tertiary); color: var(--color-text-tertiary);
text-align: center; text-align: center;
} }
</style> </style>

View File

@@ -80,7 +80,7 @@
transition: ease-in-out 0.2s; transition: ease-in-out 0.2s;
&:hover { &:hover {
color: var(--color-accent-primary); color: var(--color-header-hover);
} }
} }
</style> </style>

View File

@@ -22,7 +22,7 @@
text-align: center; text-align: center;
background-image: linear-gradient( background-image: linear-gradient(
var(--color-body-background) 0%, var(--color-body-background) 0%,
var(--color-intro-background-secondary) 100% var(--color-profile-background-secondary) 100%
); );
@media (min-width: 768px) { @media (min-width: 768px) {
@@ -49,8 +49,8 @@
border-radius: 100%; border-radius: 100%;
background-image: linear-gradient( background-image: linear-gradient(
to right, to right,
var(--color-intro-image-background-primary) 0%, var(--color-profile-image-background-primary) 0%,
var(--color-intro-image-background-secondary) 100% var(--color-profile-image-background-secondary) 100%
); );
} }
@@ -77,7 +77,7 @@
margin: unset; margin: unset;
margin-bottom: 1rem; margin-bottom: 1rem;
color: var(--color-intro-title-text); color: var(--color-profile-title-text);
font-size: 1.25rem; font-size: 1.25rem;
@media (min-width: 768px) { @media (min-width: 768px) {
@@ -87,7 +87,7 @@
.text { .text {
margin: unset; margin: unset;
color: var(--color-intro-text); color: var(--color-profile-text);
font-size: 1.125rem; font-size: 1.125rem;
line-height: 1.625; line-height: 1.625;

View File

@@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import type { ProjectEntry } from '$lib/types/data'; import type { ProjectEntry } from '$lib/types/data';
import { MousePointerClick } from '@lucide/svelte';
let { let {
title, title,
@@ -9,12 +10,227 @@
toolsHeadline, toolsHeadline,
tools tools
}: ProjectEntry = $props(); }: ProjectEntry = $props();
function inViewOnce(node: HTMLElement) {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
node.classList.add('in-view');
observer.disconnect();
}
});
}, { threshold: 1.0 });
observer.observe(node);
return {
destroy() {
observer.disconnect();
}
};
}
</script> </script>
<article> <article use:inViewOnce>
<div class="content">
<div class="front">
<span class="icon">
<MousePointerClick class="icon" />
</span>
<span class="title">{title}</span>
<span class="description">{description}</span>
</div>
<div class="back">
<div class="tasks">
<span class="task-headline">{taskHeadline}</span>
<span class="task-description">{tasks}</span>
</div>
<div class="tools">
<span class="tools-headline">{toolsHeadline}</span>
<ul class="tools-tags">
{#each tools as tool, i (i)}
<li class="tools-tags-tag">{tool}</li>
{/each}
</ul>
</div>
</div>
</div>
</article> </article>
<style> <style>
article {
display: block;
border-radius: 1rem;
transition: box-shadow ease-in-out 0.1s, transform ease-in-out 0.3s 0s;
will-change: rotate;
perspective: 1000px;
&:hover {
transition: box-shadow ease-in-out 0.1s, transform ease-in-out 0.3s 0.5s;
transform: translateY(-0.5rem);
box-shadow: var(--color-project-card-box-shadow);
}
}
:global(article.in-view) {
animation: shake 0.4s ease-in-out;
}
@keyframes shake {
0%, 100% {
rotate: 0;
}
30%, 70% {
rotate: 2deg;
}
40%, 80% {
rotate: -2deg;
}
}
.content {
display: grid;
width: 100%;
height: 100%;
border-radius: 1rem;
text-align: center;
transition: transform 0.5s;
transform-style: preserve-3d;
}
article:hover .content {
transform: rotateY(180deg);
}
.front, .back {
grid-column: 1;
grid-row: 1;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
padding: 1.5rem;
border-radius: 1rem;
backface-visibility: hidden;
@media (min-width: 768px) {
padding: 2rem;
}
}
.front {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2rem;
color: white;
background-image: linear-gradient(
to right bottom,
var(--color-project-card-front-background-primary) 0%,
var(--color-project-card-front-background-secondary) 100%
);
}
.icon {
position: absolute;
top: 1rem;
right: 1rem;
font-size: 1.5rem;
}
.title {
color: var(--color-profile-title-text);
font-size: 1rem;
line-height: 1.4;
font-weight: bold;
@media (min-width: 768px) {
font-size: 1.25rem;
}
}
.description {
font-size: 1rem;
line-height: 1.5;
}
.back {
display: flex;
flex-direction: column;
align-content: center;
justify-content: center;
gap: 2rem;
color: white;
background-image: linear-gradient(
to right bottom,
var(--color-project-card-back-background-primary) 0%,
var(--color-project-card-back-background-secondary) 100%
);
transform: rotateY(180deg);
}
.tasks {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 1rem;
}
.task-headline {
font-size: 1.25rem;
font-weight: bold;
}
.task-description {
font-size: 1rem;
line-height: 1.5;
}
.tools {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 1rem;
}
.tools-headline {
font-size: 1rem;
font-weight: bold;
}
.tools-tags {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: 0.5rem;
margin: unset;
padding: unset;
list-style: none;
}
.tools-tags-tag {
padding: 0.25rem 0.75rem;
border-radius: 1rem;
background-color: var(--color-header-border);
font-size: 0.875rem;
}
</style> </style>

View File

@@ -60,4 +60,20 @@
font-size: 1.25rem; font-size: 1.25rem;
} }
} }
div {
display: grid;
grid-template-columns: 1fr;
grid-auto-rows: auto;
gap: 2rem;
justify-content: center;
@media (min-width: 768px) {
grid-template-columns: repeat(2, minmax(0, 25rem));
}
@media (min-width: 1024px) {
grid-template-columns: repeat(3, minmax(0, 25rem));
}
}
</style> </style>

View File

@@ -5,20 +5,6 @@
--color-text-secondary: oklch(0.707 0.022 261.325); --color-text-secondary: oklch(0.707 0.022 261.325);
--color-text-tertiary: oklch(0.551 0.027 264.364); --color-text-tertiary: oklch(0.551 0.027 264.364);
--color-header-border: oklab(0.623 -0.0378409 -0.210628 / 0.3);
--color-header-background: oklab(0.21 -0.00316128 -0.0338527 / 0.95);
--color-header-hover: oklch(70.7% 0.165 254.624);
--color-footer-background: oklch(0.13 0.028 261.692);
--color-intro-background-primary: oklab(0.379 -0.0113992 -0.145554 / 0.2);
--color-intro-background-secondary: oklab(0.379 -0.0113992 -0.145554 / 0.2);
--color-intro-image-background-primary: oklch(0.623 0.214 259.815);
--color-intro-image-background-secondary: oklch(0.511 0.262 276.966);
--color-intro-text: oklch(0.967 0.003 264.542);
--color-intro-title-text: oklch(0.809 0.105 251.813);
--color-headline-primary: oklch(0.707 0.165 254.624); --color-headline-primary: oklch(0.707 0.165 254.624);
--color-headline-secondary: oklch(0.673 0.182 276.935); --color-headline-secondary: oklch(0.673 0.182 276.935);
--color-headline-tertiary: oklch(0.714 0.203 305.504); --color-headline-tertiary: oklch(0.714 0.203 305.504);
@@ -28,6 +14,25 @@
var(--color-headline-secondary) 60%, var(--color-headline-secondary) 60%,
var(--color-headline-tertiary) 100%); var(--color-headline-tertiary) 100%);
--color-header-border: oklab(0.623 -0.0378409 -0.210628 / 0.3);
--color-header-background: oklab(0.21 -0.00316128 -0.0338527 / 0.95);
--color-header-hover: oklch(70.7% 0.165 254.624);
--color-footer-background: oklch(0.13 0.028 261.692);
--color-profile-background-primary: oklab(0.379 -0.0113992 -0.145554 / 0.2);
--color-profile-background-secondary: oklab(0.379 -0.0113992 -0.145554 / 0.2);
--color-profile-image-background-primary: oklch(0.623 0.214 259.815);
--color-profile-image-background-secondary: oklch(0.511 0.262 276.966);
--color-profile-text: oklch(0.967 0.003 264.542);
--color-profile-title-text: oklch(0.809 0.105 251.813);
--color-project-card-front-background-primary: oklch(0.278 0.033 256.848);
--color-project-card-front-background-secondary: oklch(0.373 0.034 259.733);
--color-project-card-back-background-primary: oklch(0.379 0.146 265.522);
--color-project-card-back-background-secondary: oklch(0.359 0.144 278.697);
--color-project-card-box-shadow: 0 0 0 0 rgba(0,0,0,0), oklab(0.623 -0.0378409 -0.210628 / 0.5) 0 25px 50px -12px;
--z-index-header: 50; --z-index-header: 50;
} }
@@ -46,4 +51,9 @@ html, body {
background-color: var(--color-body-background); background-color: var(--color-body-background);
font-family: 'AdwaitaSans', 'AdwaitaMono', sans-serif; font-family: 'AdwaitaSans', 'AdwaitaMono', sans-serif;
scroll-behavior: smooth; scroll-behavior: smooth;
}
.icon {
width: 1em;
height: 1em;
} }