feat: add project entry component
- update css - update some styles
This commit is contained in:
@@ -64,7 +64,11 @@
|
||||
padding: 0.5rem;
|
||||
text-decoration: none;
|
||||
|
||||
&:visited {
|
||||
&:hover {
|
||||
color: var(--color-header-hover);
|
||||
}
|
||||
|
||||
&:visited:not(:hover){
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
transition: ease-in-out 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: var(--color-accent-primary);
|
||||
color: var(--color-header-hover);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -22,7 +22,7 @@
|
||||
text-align: center;
|
||||
background-image: linear-gradient(
|
||||
var(--color-body-background) 0%,
|
||||
var(--color-intro-background-secondary) 100%
|
||||
var(--color-profile-background-secondary) 100%
|
||||
);
|
||||
|
||||
@media (min-width: 768px) {
|
||||
@@ -49,8 +49,8 @@
|
||||
border-radius: 100%;
|
||||
background-image: linear-gradient(
|
||||
to right,
|
||||
var(--color-intro-image-background-primary) 0%,
|
||||
var(--color-intro-image-background-secondary) 100%
|
||||
var(--color-profile-image-background-primary) 0%,
|
||||
var(--color-profile-image-background-secondary) 100%
|
||||
);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
|
||||
margin: unset;
|
||||
margin-bottom: 1rem;
|
||||
color: var(--color-intro-title-text);
|
||||
color: var(--color-profile-title-text);
|
||||
font-size: 1.25rem;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
@@ -87,7 +87,7 @@
|
||||
|
||||
.text {
|
||||
margin: unset;
|
||||
color: var(--color-intro-text);
|
||||
color: var(--color-profile-text);
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.625;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { ProjectEntry } from '$lib/types/data';
|
||||
import { MousePointerClick } from '@lucide/svelte';
|
||||
|
||||
let {
|
||||
title,
|
||||
@@ -9,12 +10,227 @@
|
||||
toolsHeadline,
|
||||
tools
|
||||
}: 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>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
@@ -60,4 +60,20 @@
|
||||
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>
|
||||
@@ -5,20 +5,6 @@
|
||||
--color-text-secondary: oklch(0.707 0.022 261.325);
|
||||
--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-secondary: oklch(0.673 0.182 276.935);
|
||||
--color-headline-tertiary: oklch(0.714 0.203 305.504);
|
||||
@@ -28,6 +14,25 @@
|
||||
var(--color-headline-secondary) 60%,
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -47,3 +52,8 @@ html, body {
|
||||
font-family: 'AdwaitaSans', 'AdwaitaMono', sans-serif;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
Reference in New Issue
Block a user