feat: final refactor of sections
All checks were successful
test-build / guarddog (push) Successful in 35s
test-build / build (push) Successful in 1m1s
renovate / renovate (push) Successful in 2m15s

This commit is contained in:
2026-02-15 23:38:55 -06:00
parent 5271be52a2
commit a74cc775d0
17 changed files with 232 additions and 245 deletions

View File

@@ -1,6 +1,6 @@
--- ---
import BrandLogo from '@components/ui/logos/BrandLogo.astro'; import BrandLogo from '@components/ui/logos/BrandLogo.astro';
import ThemeToggle from '@components/buttons/ThemeToggle.astro'; import ThemeToggleButton from '@components/buttons/ThemeToggleButton.astro';
import { NavigationLinks } from '@/config'; import { NavigationLinks } from '@/config';
const pathname = new URL(Astro.request.url).pathname; const pathname = new URL(Astro.request.url).pathname;
@@ -90,7 +90,7 @@ const currentPath = pathname.slice(1);
}) })
} }
<span class="md:inline-block"> <span class="md:inline-block">
<ThemeToggle /> <ThemeToggleButton />
</span> </span>
</div> </div>
</div> </div>

View File

@@ -1,5 +1,5 @@
--- ---
import GoLinkPrimary from '@components/buttons/GoLinkPrimary.astro'; import GoLinkPrimaryButton from '@components/buttons/GoLinkPrimaryButton.astro';
import Image from '@components/ui/images/Image.astro'; import Image from '@components/ui/images/Image.astro';
interface Props { interface Props {
@@ -39,6 +39,6 @@ const { title, subTitle, btnExists, btnTitle, btnURL, img, imgAlt } = Astro.prop
> >
{subTitle} {subTitle}
</p> </p>
{btnExists ? <GoLinkPrimary title={btnTitle} url={btnURL} /> : null} {btnExists ? <GoLinkPrimaryButton title={btnTitle} url={btnURL} /> : null}
</div> </div>
</section> </section>

View File

@@ -1,5 +1,5 @@
--- ---
import GoLinkPrimary from '@components/buttons/GoLinkPrimary.astro'; import GoLinkPrimaryButton from '@components/buttons/GoLinkPrimaryButton.astro';
import Image from '@components/ui/images/Image.astro'; import Image from '@components/ui/images/Image.astro';
interface Props { interface Props {
@@ -43,7 +43,7 @@ const {
> >
{subTitle} {subTitle}
</p> </p>
{btnExists ? <GoLinkPrimary title={btnTitle} url={btnURL} /> : null} {btnExists ? <GoLinkPrimaryButton title={btnTitle} url={btnURL} /> : null}
</div> </div>
{ {

View File

@@ -1,152 +0,0 @@
---
import { Icon } from 'astro-icon/components';
import { readItems } from '@directus/sdk';
import type { Experience } from '@lib/directusTypes';
import directus from '@lib/directus';
const experiences = await directus.request(
readItems('site_experience', {
fields: ['*'],
sort: ['-endDate'],
})
);
---
<section
class:list={['flex flex-col gap-8', Astro.props.className]}
>
<h3 class="relative flex w-full items-center gap-3 pb-10 text-5xl text-neutral-800 dark:text-neutral-200">Experience</h3>
<ul class="ml-8 w-full flex flex-col">
{
experiences.map(
(experience: Experience) => {
const startYear = new Date(experience.startDate).getFullYear();
const endYear = experience.endDate != null ? new Date(experience.endDate).getFullYear() : 'Present';
return (
<li class="relative">
<div class="group smooth-reveal relative grid pb-1 transition-all sm:grid-cols-18 sm:gap-8 md:gap-6 lg:hover:!opacity-100">
<header class="relative mt-1 text-lg font-semibold sm:col-span-3 text-neutral-800 dark:text-neutral-200">
<time datetime={experience.startDate} data-title={experience.startDate}>
{startYear}
</time>{' '}
-{' '}
<time datetime={experience.endDate} data-title={experience.endDate}>
{endYear}
</time>
</header>
<div class="relative flex flex-col pb-6 before:absolute before:mt-8 before:-ml-6 before:h-full before:w-px before:bg-stone-400 sm:col-span-12">
<div class="absolute mt-4 h-2 w-2 -translate-x-[1.71rem] rounded-full bg-stone-400" />
<h3>
<div
class="inline-flex items-center text-2xl leading-tight font-semibold"
aria-label="{position} - {company}"
>
<span class="text-neutral-800 dark:text-neutral-200">
{experience.position} <span>@</span>
{experience.url ? (
<a
class="hover:text-steel dark:hover:text-bermuda"
href={experience.url}
title={`Ver ${experience.name}`}
target="_blank"
>
{experience.name}
</a>
) : (
<span>{experience.name}</span>
)}
</span>
</div>
</h3>
{(experience.location || experience.location_type) && (
<div class="text-sm text-neutral-600 dark:text-neutral-400">
{experience.location} {experience.location && experience.location_type && '-'} {experience.location_type}
</div>
)}
<div class="text-md mt-4 flex flex-col gap-4" x-data="{ expanded: false }">
{experience.summary && (
<div class="flex flex-col gap-1">
<h4 class="font-semibold text-neutral-800 dark:text-neutral-200">Summary:</h4>
<ul class="flex list-disc flex-col gap-2 text-neutral-700 dark:text-neutral-400 [&>li]:ml-4">
{Array.isArray(experience.summary) ? (
experience.summary.map((item) => ({ item }))
) : (
<li class="marker:text-steel dark:marker:text-bermuda">{experience.summary}</li>
)}
</ul>
</div>
)}
{(experience.responsibilities || experience.achievements) && (
<div class="relative flex flex-col gap-4 max-sm:!h-auto md:after:absolute md:after:bottom-0 md:after:h-12 md:after:w-full md:after:bg-gradient-to-t md:after:from-neutral-200 dark:md:after:from-stone-700 md:after:content-[''] " :class="expanded ? 'after:hidden' : ''" x-show="expanded" x-collapse.min.50px>
{experience.responsibilities && (
<div class="flex flex-col gap-1">
<h4 class="font-semibold text-neutral-800 dark:text-neutral-200">Responsibilities:</h4>
<ul class="text-neutral-700 dark:text-neutral-400 [&>li]:ml-4 flex list-disc flex-col gap-2">
{experience.responsibilities.map(responsibility => (
<li class="marker:text-steel dark:marker:text-bermuda">{responsibility}</li>
))}
</ul>
</div>
)}
{experience.achievements && (
<div class="flex flex-col gap-1">
<h4 class="font-semibold text-neutral-800 dark:text-neutral-200">Achievements:</h4>
<ul class="text-neutral-700 dark:text-neutral-400 [&>li]:ml-4 flex list-disc flex-col gap-2">
{experience.achievements.map(achievement => (
<li class="marker:text-steel dark:marker:text-bermuda">{achievement}</li>
))}
</ul>
</div>
)}
</div>
<button @click="expanded = ! expanded" class="group/more w-fit cursor-pointer items-center justify-center gap-1.5 text-xs underline text-neutral-700 dark:text-neutral-300 hover:text-neutral-900 dark:hover:text-neutral-400 transition-all flex">
<span x-text="expanded ? 'Show less' : 'Show more'">Show more</span>
<svg
class="h-4 w-4 duration-200 ease-out group-hover/more:translate-y-0.5"
:class="{ 'rotate-180': expanded }"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="6 9 12 15 18 9" />
</svg>
</button>
<ul class="flex print:hidden flex-wrap gap-2" aria-label="Technologies used">
{experience.skills && experience.skills.map(skill => {
const iconName = skill.toLowerCase();
return (
<li class="bg-steel/20 border-steel/20 text-neutral-800 dark:bg-bermuda/20 dark:border-bermuda/20 dark:text-neutral-200 flex gap-1 items-center border-solid border rounded-md px-2 py-0.5 text-xs">
<Icon name={`mdi:${iconName}`} /> <span>{skill}</span>
</li>
)
})}
</ul>
)}
</div>
</div>
</div>
</li>
);
}
)
}
</ul>
</section>
<!-- Alpine Plugins -->
<script defer src="https://cdn.jsdelivr.net/npm/@alpinejs/collapse@3.x.x/dist/cdn.min.js"></script>
<!-- Alpine Core -->
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>

View File

@@ -0,0 +1,159 @@
---
import { Icon } from 'astro-icon/components';
import { readItems } from '@directus/sdk';
import type { Experience } from '@lib/directusTypes';
import directus from '@lib/directus';
const experiences = ((await directus.request(
readItems('site_experience'as any, {
fields: ['*'],
sort: ['-endDate'],
})
)) as unknown) as Experience[];
---
<section class:list={['flex flex-col gap-8', Astro.props.className]}>
<h3 class="smooth-reveal card-text-header flex relative items-center w-full gap-3 pb-10">
Experience
</h3>
<ul class="ml-8 w-full flex flex-col">
{experiences.map((experience: Experience) => {
const startYear = new Date(experience.startDate).getFullYear();
const endYear = experience.endDate != null ? new Date(experience.endDate).getFullYear() : 'Present';
return (
<li class="relative">
<div class="smooth-reveal group relative grid sm:grid-cols-18 sm:gap-8 md:gap-6 pb-16">
<header class="relative sm:col-span-3 text-header font-semibold text-lg mt-1">
<time datetime={experience.startDate} data-title={experience.startDate}>
{startYear}
</time>
{' '}-{' '}
<time datetime={experience.endDate} data-title={experience.endDate}>
{endYear}
</time>
</header>
<div class="relative flex flex-col sm:col-span-12 pb-6">
<div class="absolute bg-stone-400 -translate-x-[1.71rem] rounded-full h-2 w-2 mt-4"/>
<h3>
<div
class="inline-flex items-center text-2xl leading-tight font-semibold"
aria-label="{position} - {company}"
>
<span class="text-header">
{experience.position} <span>@</span>
{experience.url ? (
<a
class="hover:text-main"
href={experience.url}
title={`Ver ${experience.name}`}
target="_blank"
>
{experience.name}
</a>
) : (
<span>{experience.name}</span>
)}
</span>
</div>
</h3>
{(experience.location || experience.location_type) && (
<div class="text-secondary text-sm">
{experience.location} {experience.location && experience.location_type && '-'} {experience.location_type}
</div>
)}
<div class="text-md mt-4 flex flex-col gap-4" x-data="{ expanded: false }">
{experience.summary && (
<div class="flex flex-col gap-1">
<h4 class="text-header font-semibold">
Summary:
</h4>
<ul class="flex flex-col text-primary list-disc gap-2 [&>li]:ml-4">
<li class="marker:text-main">
{experience.summary}
</li>
</ul>
</div>
)}
{(experience.responsibilities || experience.achievements) && (
<div class="relative flex flex-col gap-4 max-sm:h-auto! md:after:absolute md:after:bottom-0 md:after:h-12 md:after:w-full md:after:bg-gradient-to-t md:after:from-neutral-200 dark:md:after:from-stone-700 md:after:content-[''] " :class="expanded ? 'after:hidden' : ''" x-show="expanded" x-collapse.min.50px>
{experience.responsibilities && (
<div class="flex flex-col gap-1">
<h4 class="text-header font-semibold">
Responsibilities:
</h4>
<ul class="flex flex-col text-primary list-disc gap-2 [&>li]:ml-4">
{experience.responsibilities.map(responsibility => (
<li class="marker:text-main">
{responsibility}
</li>
))}
</ul>
</div>
)}
{experience.achievements && (
<div class="flex flex-col gap-1">
<h4 class="text-header font-semibold">
Achievements:
</h4>
<ul class="flex flex-col text-primary list-disc gap-2 [&>li]:ml-4">
{experience.achievements.map(achievement => (
<li class="marker:text-main">
{achievement}
</li>
))}
</ul>
</div>
)}
</div>
<button @click="expanded = ! expanded" class="group/more flex items-center justify-center text-primary hover:text-primary-hover text-xs underline transition-all gap-1.5 w-fit cursor-pointer">
<span x-text="expanded ? 'Show less' : 'Show more'">
Show more
</span>
<svg
class="group-hover/more:translate-y-0.5 ease-out duration-300 h-4 w-4"
:class="{ 'rotate-180': expanded }"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="6 9 12 15 18 9" />
</svg>
</button>
<ul
class="flex print:hidden flex-wrap gap-2"
aria-label="Technologies used"
>
{experience.skills && experience.skills.map(skill => {
const iconName = skill.toLowerCase();
const skillName = skill.split(':')[1].replace(/^language-/, '').replace(/-/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase());
return (
<li class="flex items-center bg-steel/20 dark:bg-bermuda/20 text-neutral-800 dark:text-neutral-200 text-xs rounded-md border border-solid border-steel/20 dark:border-bermuda/20 gap-1 px-2 py-0.5">
<Icon name={`${iconName}`} class="h-4 w-4" /> <span>{skillName}</span>
</li>
)
})}
</ul>
)}
</div>
</div>
</div>
</li>
);
})}
</ul>
</section>
<!-- Alpine Plugins -->
<script defer src="https://cdn.jsdelivr.net/npm/@alpinejs/collapse@3.x.x/dist/cdn.min.js"></script>
<!-- Alpine Core -->
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>

View File

@@ -1,5 +1,5 @@
--- ---
import GoLinkPrimary from '@components/buttons/GoLinkPrimary.astro'; import GoLinkPrimaryButton from '@components/buttons/GoLinkPrimaryButton.astro';
interface Props { interface Props {
title: string; title: string;
@@ -23,7 +23,7 @@ const { title, subTitle, btnExists, btnTitle, btnURL } = Astro.props;
</p> </p>
{btnExists ? ( {btnExists ? (
<div class="smooth-reveal mt-4 md:mt-8"> <div class="smooth-reveal mt-4 md:mt-8">
<GoLinkPrimary title={btnTitle} url={btnURL}/> <GoLinkPrimaryButton title={btnTitle} url={btnURL}/>
</div> </div>
) : null} ) : null}
</div> </div>

View File

@@ -1,6 +1,6 @@
--- ---
import GoLinkPrimary from '@components/buttons/GoLinkPrimary.astro'; import GoLinkPrimaryButton from '@components/buttons/GoLinkPrimaryButton.astro';
import GoLinkSecondary from '@components/buttons/GoLinkSecondary.astro'; import GoLinkSecondaryButton from '@components/buttons/GoLinkSecondaryButton.astro';
import Image from '@components/ui/images/Image.astro'; import Image from '@components/ui/images/Image.astro';
interface Props { interface Props {
@@ -31,8 +31,8 @@ const roundedClasses = Astro.props.rounded ? "rounded-xl" : null;
</p> </p>
)} )}
<div class="smooth-reveal grid sm:inline-flex mt-7 w-full gap-3"> <div class="smooth-reveal grid sm:inline-flex mt-7 w-full gap-3">
{primaryBtn && <GoLinkPrimary title={primaryBtn} url={primaryBtnURL} />} {primaryBtn && <GoLinkPrimaryButton title={primaryBtn} url={primaryBtnURL} />}
{secondaryBtn && <GoLinkSecondary title={secondaryBtn} url={secondaryBtnURL} />} {secondaryBtn && <GoLinkSecondaryButton title={secondaryBtn} url={secondaryBtnURL} />}
</div> </div>
</div> </div>

View File

@@ -1,8 +1,9 @@
--- ---
import { readItems } from '@directus/sdk'; import { readItems } from '@directus/sdk';
import directus from '@lib/directus';
import type { Post } from '@lib/directusTypes'; import type { Post } from '@lib/directusTypes';
import directus from '@lib/directus';
import BlogCard from '@components/blog/BlogCard.astro'; import BlogCard from '@components/blog/BlogCard.astro';
const posts = await directus.request( const posts = await directus.request(
@@ -20,11 +21,14 @@ const recentPosts = posts
<section class="mx-auto mb-20 max-w-340 px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"> <section class="mx-auto mb-20 max-w-340 px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full">
<div class="mx-auto mb-10 max-w-2xl text-center lg:mb-14"> <div class="mx-auto mb-10 max-w-2xl text-center lg:mb-14">
<h1 <h1 class="smooth-reveal card-text-header block">
class="smooth-reveal block text-4xl font-bold text-neutral-800 md:text-5xl md:leading-tight lg:text-5xl dark:text-neutral-200"
>
Latest Posts Latest Posts
</h1> </h1>
<div class="smooth-reveal mx-auto mt-5 max-w-3xl text-center">
<span class="card-text-header-description">
Checkout my most recent thoughts here
</span>
</div>
</div> </div>
<div class="grid gap-6 sm:grid-cols-2 lg:grid-cols-3"> <div class="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
{recentPosts.map((b) => <BlogCard post={b} />)} {recentPosts.map((b) => <BlogCard post={b} />)}

View File

@@ -6,86 +6,63 @@ import type { Skill } from '@lib/directusTypes';
import directus from '@lib/directus'; import directus from '@lib/directus';
const skills = await directus.request( const skills = ((await directus.request(
readItems('site_skills', { readItems('site_skills' as any, {
fields: ['*'], fields: ['*'],
sort: ['-date_created'], sort: ['-date_created'],
}) })
); )) as unknown) as Skill[];
const baseClasses = 'mx-2 min-w-[220px] sm:mx-4 sm:min-w-[280px]';
const borderClasses =
'border border-neutral-100 hover:border-neutral-200 dark:border-stone-500/20 dark:hover:border-neutral-800';
const bgColorClasses = 'bg-neutral-100/80 dark:bg-neutral-800/60 dark:hover:bg-neutral-800/90';
const hoverClasses = 'hover:-translate-y-2 hover:scale-105 ';
const shadowClasses = 'shadow-xs hover:shadow-lg';
--- ---
<section class:list={['flex flex-col gap-4', Astro.props.className]}> <section class:list={['flex flex-col gap-4', Astro.props.className]}>
<h3 <h3 class="smooth-reveal card-text-header flex relative items-center w-full gap-3 pb-5">
class="relative flex w-full items-center gap-3 pb-4 text-5xl text-neutral-800 dark:text-neutral-200"
>
Skills Skills
</h3> </h3>
<div class=""> <div class="">
<div class="tech-stack-slider relative overflow-hidden py-4 sm:py-8"> <div class="tech-stack-slider relative overflow-hidden py-4 sm:py-8">
<!-- Main slider container --> <!-- Main slider container -->
<div class="slider-track animate-slide flex"> <div class="slider-track animate-slide flex">
{ {[...skills, ...skills, ...skills].map((skill: Skill) => {
[...skills, ...skills, ...skills].map((skill: Skill) => {
return ( return (
<div <div class="skill-card card-base transform hover:-translate-y-2 hover:scale-105 transition-all duration-300 mx-2 min-w-55 sm:mx-4 sm:min-w-70">
class={`skill-card transform rounded-xl transition-all duration-300 ${baseClasses} ${borderClasses} ${bgColorClasses} ${hoverClasses} ${shadowClasses}`}
>
<div class="p-4 sm:p-6"> <div class="p-4 sm:p-6">
<div class="mb-4 flex items-center justify-between sm:mb-6"> <div class="flex items-center justify-between mb-4 sm:mb-6">
<div class="flex items-center gap-2 sm:gap-4"> <div class="flex items-center gap-2 sm:gap-4">
<div class="flex transform items-center justify-center rounded-lg text-neutral-800 transition-transform group-hover:rotate-12 dark:text-neutral-200"> <div class="flex items-center justify-center rounded-lg text-primary">
<Icon name={skill.icon} class="h-8 w-8 sm:h-12 sm:w-12" /> <Icon name={skill.icon} class="h-8 w-8 sm:h-12 sm:w-12" />
</div> </div>
<h3 class="text-base font-semibold text-neutral-900 sm:text-xl dark:text-neutral-100"> <h3 class="text-neutral-900 dark:text-neutral-100 text-base font-semibold sm:text-xl">
{skill.title} {skill.title}
</h3> </h3>
</div> </div>
<span class="rounded-full bg-neutral-200 px-2 py-0.5 font-mono text-xs text-neutral-700 sm:px-2.5 sm:py-1 sm:text-sm dark:bg-neutral-800 dark:text-neutral-300"> <span class=" bg-neutral-200 dark:bg-neutral-800 text-neutral-700 dark:text-neutral-300 font-mono text-xs sm:text-sm rounded-full px-2 sm:px-2.5 py-0.5 sm:py-1">
{skill.level}% {skill.level}%
</span> </span>
</div> </div>
<div class="relative bg-stone-500/20 dark:bg-stone-500/20 rounded-full h-1.5 sm:h-2 w-full overflow-hidden">
<div class="relative h-1.5 w-full overflow-hidden rounded-full bg-stone-500/20 sm:h-2 dark:bg-stone-500/20">
<div <div
class="progress-bar-animate from-steel via-bermuda to-steel absolute top-0 left-0 h-full rounded-full bg-linear-to-r transition-all duration-1000" class="progress-bar-animate bg-linear-to-r from-steel via-bermuda to-steel absolute top-0 left-0 h-full rounded-full transition-all duration-1000"
style={`width: ${skill.level}%`} style={`width: ${skill.level}%`}
/> />
</div> </div>
<div class="flex justify-between text-secondary font-mono text-[10px] mt-1 sm:mt-2 sm:text-xs">
<div class="mt-1 flex justify-between font-mono text-[10px] text-neutral-600 sm:mt-2 sm:text-xs dark:text-neutral-400">
<span>Beginner</span> <span>Beginner</span>
<span>Advanced</span> <span>Advanced</span>
</div> </div>
</div> </div>
</div> </div>
); );
}) })}
}
</div> </div>
<!-- Gradient overlays --> <!-- Gradient overlays -->
<div <div class="bg-linear-to-r from-neutral-200 to-transparent dark:from-stone-700 absolute top-0 bottom-0 left-0 z-10 w-12 sm:w-24"/>
class="absolute top-0 bottom-0 left-0 z-10 w-12 bg-linear-to-r from-neutral-200 to-transparent sm:w-24 dark:from-stone-700" <div class="bg-linear-to-l from-neutral-200 to-transparent dark:from-stone-700 absolute top-0 bottom-0 right-0 z-10 w-12 sm:w-24"/>
>
</div>
<div
class="absolute top-0 right-0 bottom-0 z-10 w-12 bg-linear-to-l from-neutral-200 to-transparent sm:w-24 dark:from-stone-700"
>
</div>
</div> </div>
</div> </div>
</section> </section>
<script> <script>
document.addEventListener('astro:page-load', () => { document.addEventListener('astro:page-load', () => {
// Create infinite scrolling effect
function setupInfiniteScroll() { function setupInfiniteScroll() {
const cards = document.querySelectorAll('.skill-card'); const cards = document.querySelectorAll('.skill-card');
if (!cards.length) return; if (!cards.length) return;
@@ -93,7 +70,6 @@ const shadowClasses = 'shadow-xs hover:shadow-lg';
setupInfiniteScroll(); setupInfiniteScroll();
// Add hover effects to cards - only on non-touch devices
const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0; const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
const cards = document.querySelectorAll('.skill-card'); const cards = document.querySelectorAll('.skill-card');
@@ -144,7 +120,7 @@ const shadowClasses = 'shadow-xs hover:shadow-lg';
</script> </script>
<style> <style>
/* Tech Stack Slider */ /* Specific css to enable sliding effect */
.slider-track { .slider-track {
width: fit-content; width: fit-content;
animation: scroll 40s linear infinite; animation: scroll 40s linear infinite;
@@ -155,7 +131,7 @@ const shadowClasses = 'shadow-xs hover:shadow-lg';
transform: translateX(0); transform: translateX(0);
} }
100% { 100% {
transform: translateX(calc(-220px * 6 - 16px * 6)); /* Card width + margin for mobile */ transform: translateX(calc(-220px * 6 - 16px * 6));
} }
} }
@@ -169,7 +145,7 @@ const shadowClasses = 'shadow-xs hover:shadow-lg';
transform: translateX(0); transform: translateX(0);
} }
100% { 100% {
transform: translateX(calc(-280px * 6 - 32px * 6)); /* Card width + margin for desktop */ transform: translateX(calc(-280px * 6 - 32px * 6));
} }
} }
} }

View File

@@ -17,7 +17,6 @@ const { forecastDays, error } = await getFiveDayForecast(latitude, longitude, ti
</span> </span>
</div> </div>
</div> </div>
{error ? ( {error ? (
<div class="card-base p-10 text-accent text-center"> <div class="card-base p-10 text-accent text-center">
{error} {error}

View File

@@ -3,8 +3,8 @@ import { readSingleton } from '@directus/sdk';
import directus from '@lib/directus'; import directus from '@lib/directus';
import BaseLayout from '@layouts/BaseLayout.astro'; import BaseLayout from '@layouts/BaseLayout.astro';
import GoBack from '@/components/buttons/GoBack.astro'; import GoBackButton from '@/components/buttons/GoBackButton.astro';
import GoHome from '@/components/buttons/GoHome.astro'; import GoHomeButton from '@/components/buttons/GoHomeButton.astro';
const global = await directus.request(readSingleton('site_global')); const global = await directus.request(readSingleton('site_global'));
--- ---
@@ -61,8 +61,8 @@ const global = await directus.request(readSingleton('site_global'));
<div <div
class="smooth-reveal mt-10 flex flex-col items-center justify-center gap-4 sm:flex-row" class="smooth-reveal mt-10 flex flex-col items-center justify-center gap-4 sm:flex-row"
> >
<GoBack/> <GoBackButton/>
<GoHome url={global.site_url} /> <GoHomeButton url={global.site_url} />
</div> </div>
</div> </div>
</div> </div>

View File

@@ -4,10 +4,10 @@ import { readSingleton } from '@directus/sdk';
import directus from '@lib/directus'; import directus from '@lib/directus';
import BaseLayout from '@layouts/BaseLayout.astro'; import BaseLayout from '@layouts/BaseLayout.astro';
import HeroSection from '@components/sections/HeroSection.astro'; import HeroSection from '@components/sections/HeroSection.astro';
import Experience from '@components/sections/Experience.astro'; import ExperienceSection from '@components/sections/ExperienceSection.astro';
import EducationSection from '@components/sections/EducationSection.astro'; import EducationSection from '@components/sections/EducationSection.astro';
import ProjectSection from '@components/sections/ProjectSection.astro'; import ProjectSection from '@components/sections/ProjectSection.astro';
import SkillsSlider from '@components/sections/SkillsSlider.astro'; import SkillsSliderSection from '@components/sections/SkillsSliderSection.astro';
import portraitImg from '@images/portrait.avif'; import portraitImg from '@images/portrait.avif';
@@ -44,10 +44,10 @@ const global = await directus.request(readSingleton('site_global'));
<section class="mx-auto max-w-7xl px-4 py-10 sm:px-6 lg:px-8 lg:py-14"> <section class="mx-auto max-w-7xl px-4 py-10 sm:px-6 lg:px-8 lg:py-14">
<div class="flex flex-col gap-y-24 md:gap-y-32"> <div class="flex flex-col gap-y-24 md:gap-y-32">
<Experience className="smooth-reveal" /> <ExperienceSection className="smooth-reveal" />
<EducationSection className="smooth-reveal" /> <EducationSection className="smooth-reveal" />
<ProjectSection className="smooth-reveal" /> <ProjectSection className="smooth-reveal" />
<SkillsSlider className="smooth-reveal" /> <SkillsSliderSection className="smooth-reveal" />
</div> </div>
</section> </section>

View File

@@ -10,7 +10,7 @@ import { createHighlighter } from 'shiki';
import { getDirectusImageURL } from '@lib/directusFunctions'; import { getDirectusImageURL } from '@lib/directusFunctions';
import BaseLayout from '@layouts/BaseLayout.astro'; import BaseLayout from '@layouts/BaseLayout.astro';
import Image from '@components/ui/images/Image.astro'; import Image from '@components/ui/images/Image.astro';
import SocialShare from '@components/buttons/SocialShare.astro'; import SocialShareButton from '@components/buttons/SocialShareButton.astro';
import { formatDateTime } from '@support/time'; import { formatDateTime } from '@support/time';
export async function getStaticPaths() { export async function getStaticPaths() {
@@ -163,7 +163,7 @@ const content = marked.parse(post.content);
)) ))
} }
</div> </div>
<SocialShare <SocialShareButton
pageTitle={post.title} pageTitle={post.title}
/> />
</div> </div>

View File

@@ -6,7 +6,7 @@ import BaseLayout from '@layouts/BaseLayout.astro';
import HeroSection from '@components/sections/HeroSection.astro'; import HeroSection from '@components/sections/HeroSection.astro';
import FeaturesSection from '@components/sections/FeaturesSection.astro'; import FeaturesSection from '@components/sections/FeaturesSection.astro';
import WeatherSection from '@components/sections/WeatherSection.astro'; import WeatherSection from '@components/sections/WeatherSection.astro';
import LatestPosts from '@components/sections/LatestPosts.astro'; import LatestPostsSection from '@components/sections/LatestPostsSection.astro';
import GiteaSection from '@components/sections/GiteaSection.astro'; import GiteaSection from '@components/sections/GiteaSection.astro';
import homeImg from '@images/autumn_mountain.png'; import homeImg from '@images/autumn_mountain.png';
@@ -54,7 +54,7 @@ const weather = await directus.request(readSingleton('site_weather'));
> >
</WeatherSection> </WeatherSection>
<LatestPosts /> <LatestPostsSection />
<GiteaSection <GiteaSection
title="Follow me on Gitea" title="Follow me on Gitea"

View File

@@ -31,6 +31,7 @@
--color-header: light-dark(var(--color-neutral-800), var(--color-neutral-200)); --color-header: light-dark(var(--color-neutral-800), var(--color-neutral-200));
--color-primary: light-dark(var(--color-neutral-600), var(--color-neutral-200)); --color-primary: light-dark(var(--color-neutral-600), var(--color-neutral-200));
--color-primary-hover: light-dark(var(--color-neutral-800), var(--color-neutral-400));
--color-secondary: light-dark(var(--color-neutral-500), var(--color-neutral-400)); --color-secondary: light-dark(var(--color-neutral-500), var(--color-neutral-400));
} }