Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e91ffd8686 | |||
| 00a86b1206 | |||
| 7327795d39 | |||
| ae57c60935 | |||
| 245e0f0624 | |||
|
082afca9da
|
|||
| 16e14f63ef |
@@ -26,7 +26,18 @@ jobs:
|
|||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: pnpm install
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Cache Astro Build Cache
|
||||||
|
uses: actions/cache@v5
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
node_modules/.cache
|
||||||
|
.astro/cache
|
||||||
|
key: ${{ runner.os }}-astro-cache-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.sha }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-astro-cache-${{ hashFiles('**/pnpm-lock.yaml') }}-
|
||||||
|
${{ runner.os }}-astro-cache-
|
||||||
|
|
||||||
- name: Lint Code
|
- name: Lint Code
|
||||||
run: pnpm lint
|
run: pnpm lint
|
||||||
@@ -113,6 +124,8 @@ jobs:
|
|||||||
COMMIT_SHA=${{ steps.version.outputs.commit }}
|
COMMIT_SHA=${{ steps.version.outputs.commit }}
|
||||||
IS_RELEASE=${{ steps.version.outputs.is_release }}
|
IS_RELEASE=${{ steps.version.outputs.is_release }}
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
- name: ntfy Success
|
- name: ntfy Success
|
||||||
uses: niniyas/ntfy-action@master
|
uses: niniyas/ntfy-action@master
|
||||||
|
|||||||
@@ -26,7 +26,18 @@ jobs:
|
|||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: pnpm install
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Cache Astro Build Cache
|
||||||
|
uses: actions/cache@v5
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
node_modules/.cache
|
||||||
|
.astro/cache
|
||||||
|
key: ${{ runner.os }}-astro-cache-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.sha }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-astro-cache-${{ hashFiles('**/pnpm-lock.yaml') }}-
|
||||||
|
${{ runner.os }}-astro-cache-
|
||||||
|
|
||||||
- name: Lint Code
|
- name: Lint Code
|
||||||
run: pnpm lint
|
run: pnpm lint
|
||||||
@@ -113,6 +124,8 @@ jobs:
|
|||||||
COMMIT_SHA=${{ steps.version.outputs.commit }}
|
COMMIT_SHA=${{ steps.version.outputs.commit }}
|
||||||
IS_RELEASE=${{ steps.version.outputs.is_release }}
|
IS_RELEASE=${{ steps.version.outputs.is_release }}
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
- name: ntfy Success
|
- name: ntfy Success
|
||||||
uses: niniyas/ntfy-action@master
|
uses: niniyas/ntfy-action@master
|
||||||
|
|||||||
@@ -28,7 +28,18 @@ jobs:
|
|||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: pnpm install
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Cache Astro Build Cache
|
||||||
|
uses: actions/cache@v5
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
node_modules/.cache
|
||||||
|
.astro/cache
|
||||||
|
key: ${{ runner.os }}-astro-cache-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.sha }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-astro-cache-${{ hashFiles('**/pnpm-lock.yaml') }}-
|
||||||
|
${{ runner.os }}-astro-cache-
|
||||||
|
|
||||||
- name: Lint Code
|
- name: Lint Code
|
||||||
run: pnpm lint
|
run: pnpm lint
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ WORKDIR /app
|
|||||||
COPY --from=prod-deps /app/node_modules /app/node_modules
|
COPY --from=prod-deps /app/node_modules /app/node_modules
|
||||||
COPY --from=build /app/dist /app/dist
|
COPY --from=build /app/dist /app/dist
|
||||||
|
|
||||||
LABEL version="2.24.0"
|
LABEL version="2.25.0"
|
||||||
LABEL description="Astro based personal website"
|
LABEL description="Astro based personal website"
|
||||||
|
|
||||||
ENV HOST=0.0.0.0
|
ENV HOST=0.0.0.0
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "site-profile",
|
"name": "site-profile",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "2.24.0",
|
"version": "2.25.0",
|
||||||
"homepage": "https://www.alexlebens.dev",
|
"homepage": "https://www.alexlebens.dev",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://gitea.alexlebens.dev/alexlebens/site-profile/issues",
|
"url": "https://gitea.alexlebens.dev/alexlebens/site-profile/issues",
|
||||||
@@ -49,6 +49,7 @@
|
|||||||
"marked": "^17.0.4",
|
"marked": "^17.0.4",
|
||||||
"marked-shiki": "^1.2.1",
|
"marked-shiki": "^1.2.1",
|
||||||
"mdast-util-to-string": "^4.0.0",
|
"mdast-util-to-string": "^4.0.0",
|
||||||
|
"photoswipe": "^5.4.4",
|
||||||
"preline": "^4.1.2",
|
"preline": "^4.1.2",
|
||||||
"react": "^19.2.4",
|
"react": "^19.2.4",
|
||||||
"react-dom": "^19.2.4",
|
"react-dom": "^19.2.4",
|
||||||
|
|||||||
9
pnpm-lock.yaml
generated
9
pnpm-lock.yaml
generated
@@ -74,6 +74,9 @@ importers:
|
|||||||
mdast-util-to-string:
|
mdast-util-to-string:
|
||||||
specifier: ^4.0.0
|
specifier: ^4.0.0
|
||||||
version: 4.0.0
|
version: 4.0.0
|
||||||
|
photoswipe:
|
||||||
|
specifier: ^5.4.4
|
||||||
|
version: 5.4.4
|
||||||
preline:
|
preline:
|
||||||
specifier: ^4.1.2
|
specifier: ^4.1.2
|
||||||
version: 4.1.2
|
version: 4.1.2
|
||||||
@@ -4463,6 +4466,10 @@ packages:
|
|||||||
pend@1.2.0:
|
pend@1.2.0:
|
||||||
resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
|
resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
|
||||||
|
|
||||||
|
photoswipe@5.4.4:
|
||||||
|
resolution: {integrity: sha512-WNFHoKrkZNnvFFhbHL93WDkW3ifwVOXSW3w1UuZZelSmgXpIGiZSNlZJq37rR8YejqME2rHs9EhH9ZvlvFH2NA==}
|
||||||
|
engines: {node: '>= 0.12.0'}
|
||||||
|
|
||||||
piccolore@0.1.3:
|
piccolore@0.1.3:
|
||||||
resolution: {integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==}
|
resolution: {integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==}
|
||||||
|
|
||||||
@@ -11073,6 +11080,8 @@ snapshots:
|
|||||||
|
|
||||||
pend@1.2.0: {}
|
pend@1.2.0: {}
|
||||||
|
|
||||||
|
photoswipe@5.4.4: {}
|
||||||
|
|
||||||
piccolore@0.1.3: {}
|
piccolore@0.1.3: {}
|
||||||
|
|
||||||
picocolors@1.1.1: {}
|
picocolors@1.1.1: {}
|
||||||
|
|||||||
BIN
public/i.jpg
BIN
public/i.jpg
Binary file not shown.
|
Before Width: | Height: | Size: 381 KiB |
77
src/components/cards/LargeCategoryCard.astro
Normal file
77
src/components/cards/LargeCategoryCard.astro
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
---
|
||||||
|
import Logo from '@components/images/Logo.astro';
|
||||||
|
import { getDirectusImageURL } from '@/support/url';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
url: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
logoLight: string;
|
||||||
|
logoDark?: string;
|
||||||
|
count: number;
|
||||||
|
publishDate: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { url, title, description, logoLight, logoDark, count, publishDate } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="smooth-reveal flex flex-col mx-auto w-full">
|
||||||
|
<a
|
||||||
|
class="card-base flex flex-col h-full min-h-55"
|
||||||
|
href={url}
|
||||||
|
data-astro-prefetch
|
||||||
|
>
|
||||||
|
<div class="relative grow overflow-hidden">
|
||||||
|
<div class="absolute inset-1 flex flex-col p-3 md:p-4 lg:p-5">
|
||||||
|
<div class="flex flex-row items-center mb-4">
|
||||||
|
<div class="card-hover-icon-scale shrink-0 mr-3">
|
||||||
|
<Logo
|
||||||
|
srcLight={getDirectusImageURL(logoLight)}
|
||||||
|
srcDark={getDirectusImageURL(logoDark!)}
|
||||||
|
alt={`Logo of ${title}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<h3 class="card-text-title-major card-hover-text-title whitespace-nowrap">
|
||||||
|
{title}
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="card-text-description mb-4">
|
||||||
|
{description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="card-text-description flex items-center justify-between text-xs mt-auto pt-1 md:pt-2">
|
||||||
|
<span class="inline-flex items-center">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
class="mr-1"
|
||||||
|
>
|
||||||
|
<path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H20v20H6.5a2.5 2.5 0 0 1 0-5H20"></path>
|
||||||
|
</svg>
|
||||||
|
{count}
|
||||||
|
</span>
|
||||||
|
<span class="inline-flex items-center">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
class="mr-1"
|
||||||
|
>
|
||||||
|
<circle cx="12" cy="12" r="10"></circle>
|
||||||
|
<polyline points="12 6 12 12 16 14"></polyline>
|
||||||
|
</svg>
|
||||||
|
{publishDate}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
59
src/components/cards/LargeInvisibleCard.astro
Normal file
59
src/components/cards/LargeInvisibleCard.astro
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
---
|
||||||
|
import { Icon } from 'astro-icon/components';
|
||||||
|
import { Image } from 'astro:assets';
|
||||||
|
|
||||||
|
import { getDirectusImageURL } from '@/support/url';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
title: string;
|
||||||
|
subTitle: string;
|
||||||
|
url: string;
|
||||||
|
img?: string;
|
||||||
|
imgAlt?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { title, subTitle, url, img, imgAlt } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="smooth-reveal flex flex-col mx-auto w-full">
|
||||||
|
<a
|
||||||
|
class="md:card-base-hidden group items-center md:grid md:grid-cols-2 lg:grid lg:grid-cols-2 gap-8 xl:gap-16 w-full md:px-8 md:py-8"
|
||||||
|
href={url}
|
||||||
|
data-astro-prefetch
|
||||||
|
>
|
||||||
|
{img && (
|
||||||
|
<div>
|
||||||
|
<Image
|
||||||
|
class="rounded-2xl rounded-b-none md:rounded-2xl md:shadow-2xl w-full h-full sm:max-h-80 md:max-h-90 object-cover"
|
||||||
|
src={getDirectusImageURL(img)}
|
||||||
|
alt={imgAlt}
|
||||||
|
draggable="false"
|
||||||
|
loading="lazy"
|
||||||
|
width="850"
|
||||||
|
height="420"
|
||||||
|
inferSize={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div class="bg-background-card md:bg-transparent group-hover:bg-neutral-100 md:group-hover:bg-transparent dark:group-hover:bg-neutral-800/90 md:dark:group-hover:bg-transparent rounded-b-2xl transition-all duration-300 p-6">
|
||||||
|
<h2 class="card-text-header mb-2">
|
||||||
|
{title}
|
||||||
|
</h2>
|
||||||
|
<p class="card-text-title font-light text-pretty sm:text-lg max-w-prose mb-8">
|
||||||
|
{subTitle}
|
||||||
|
</p>
|
||||||
|
<div class="flex items-center justify-between w-full">
|
||||||
|
<div class="button-base button-bg-teal inline-flex rounded-lg gap-x-2">
|
||||||
|
<div class="button-text-title flex relative items-center text-center">
|
||||||
|
<span class="mr-2">
|
||||||
|
Read More
|
||||||
|
</span>
|
||||||
|
<Icon
|
||||||
|
name="mdi:keyboard-arrow-right"
|
||||||
|
class="button-hover-arrow"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
31
src/components/sections/AllCategoriesSection.astro
Normal file
31
src/components/sections/AllCategoriesSection.astro
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
import { readItems, readSingleton } from '@directus/sdk';
|
||||||
|
|
||||||
|
import LargeCategoryCard from '@components/cards/LargeCategoryCard.astro';
|
||||||
|
import directus from '@lib/directus';
|
||||||
|
import { timeago } from '@support/time';
|
||||||
|
|
||||||
|
const global = await directus.request(readSingleton('site_global'));
|
||||||
|
|
||||||
|
const posts = await directus.request(
|
||||||
|
readItems('posts', {
|
||||||
|
filter: { published: { _eq: true } },
|
||||||
|
fields: ['*'],
|
||||||
|
sort: ['-published_date'],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
---
|
||||||
|
|
||||||
|
<section class:list={['mx-auto px-4 py-10 sm:px-6 lg:px-8 lg:py-14 lg:pt-10 2xl:max-w-full', Astro.props.className]}>
|
||||||
|
<div class="grid grid-cols-1">
|
||||||
|
<LargeCategoryCard
|
||||||
|
title="All Categories"
|
||||||
|
description="Here you can forgoe the organization and just look at everything I have posted"
|
||||||
|
url="/all"
|
||||||
|
logoLight={global.all_logoLight}
|
||||||
|
logoDark={global.all_logoDark}
|
||||||
|
count={posts.length}
|
||||||
|
publishDate={timeago(posts[0]?.published_date)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
20
src/components/sections/AllPostsSection.astro
Normal file
20
src/components/sections/AllPostsSection.astro
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
import { readSingleton } from '@directus/sdk';
|
||||||
|
|
||||||
|
import LargeInvisibleCard from '@components/cards/LargeInvisibleCard.astro';
|
||||||
|
import directus from '@lib/directus';
|
||||||
|
|
||||||
|
const global = await directus.request(readSingleton('site_global'));
|
||||||
|
---
|
||||||
|
|
||||||
|
<section class:list={['mx-auto px-4 py-10 sm:px-6 lg:px-8 lg:py-14 lg:pt-10 2xl:max-w-full', Astro.props.className]}>
|
||||||
|
<div class="grid grid-cols-1">
|
||||||
|
<LargeInvisibleCard
|
||||||
|
title="All Posts"
|
||||||
|
subTitle="Browse all articles from every category"
|
||||||
|
url="/all"
|
||||||
|
img={global.all_image}
|
||||||
|
imgAlt={global.all_image_alt}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
import { readItems } from '@directus/sdk';
|
import { readItems } from '@directus/sdk';
|
||||||
|
|
||||||
import type { Post, Category } from '@lib/directusTypes';
|
import type { Post } from '@lib/directusTypes';
|
||||||
|
|
||||||
import CategoryCard from '@components/cards/CategoryCard.astro';
|
import CategoryCard from '@components/cards/CategoryCard.astro';
|
||||||
import directus from '@lib/directus';
|
import directus from '@lib/directus';
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ export type Global = {
|
|||||||
portrait_alt: string;
|
portrait_alt: string;
|
||||||
home_image: string;
|
home_image: string;
|
||||||
home_image_alt: string;
|
home_image_alt: string;
|
||||||
|
all_image: string;
|
||||||
|
all_image_alt: string;
|
||||||
|
all_logoLight: string;
|
||||||
|
all_logoDark: string;
|
||||||
blog_image: string;
|
blog_image: string;
|
||||||
blog_image_alt: string;
|
blog_image_alt: string;
|
||||||
categories_image: string;
|
categories_image: string;
|
||||||
|
|||||||
109
src/pages/all.astro
Normal file
109
src/pages/all.astro
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
---
|
||||||
|
import { readItems, readSingleton } from '@directus/sdk';
|
||||||
|
|
||||||
|
import HeaderSection from '@components/sections/HeaderSection.astro';
|
||||||
|
import BlogCard from '@components/cards/BlogCard.astro';
|
||||||
|
import BaseLayout from '@layouts/BaseLayout.astro';
|
||||||
|
import directus from '@lib/directus';
|
||||||
|
|
||||||
|
const global = await directus.request(readSingleton('site_global'));
|
||||||
|
const posts = await directus.request(
|
||||||
|
readItems('posts', {
|
||||||
|
filter: { published: { _eq: true } },
|
||||||
|
fields: ['*'],
|
||||||
|
sort: ['-published_date'],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
---
|
||||||
|
|
||||||
|
<BaseLayout
|
||||||
|
title="All Posts"
|
||||||
|
description="Browse all articles from every category."
|
||||||
|
structuredData={{
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'WebPage',
|
||||||
|
inLanguage: 'en-US',
|
||||||
|
'@id': Astro.url.href,
|
||||||
|
url: Astro.url.href,
|
||||||
|
name: `All Posts | ${global.name}`,
|
||||||
|
description: "Browse all articles from every category.",
|
||||||
|
isPartOf: {
|
||||||
|
url: `${global.site_url}`,
|
||||||
|
name: global.name,
|
||||||
|
description: global.about,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
|
||||||
|
<HeaderSection
|
||||||
|
title="All Posts"
|
||||||
|
subTitle="Browse all articles from every category."
|
||||||
|
btnExists
|
||||||
|
btnTitle="To Categories"
|
||||||
|
btnURL="/categories"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<section class="max-w-340 2xl:max-w-full mb-10 px-4 sm:px-6 lg:px-8 py-8 mx-auto mt-10">
|
||||||
|
<div class="columns-1 sm:columns-2 lg:columns-3 gap-6">
|
||||||
|
{posts.map((b) =>
|
||||||
|
<div class="break-inside-avoid mb-6">
|
||||||
|
<BlogCard post={b} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</BaseLayout>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Add smooth reveal animations for content after loading
|
||||||
|
document.addEventListener('astro:page-load', () => {
|
||||||
|
const animateContent = () => {
|
||||||
|
// Animate group 1
|
||||||
|
const smoothReveal = document.querySelectorAll('.smooth-reveal');
|
||||||
|
smoothReveal.forEach((el, index) => {
|
||||||
|
setTimeout(
|
||||||
|
() => {
|
||||||
|
el.classList.add('animate-reveal');
|
||||||
|
},
|
||||||
|
50 + index * 100
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Animate group 2
|
||||||
|
const smoothReveal2 = document.querySelectorAll('.smooth-reveal-2');
|
||||||
|
smoothReveal2.forEach((el, index) => {
|
||||||
|
setTimeout(
|
||||||
|
() => {
|
||||||
|
el.classList.add('animate-reveal');
|
||||||
|
},
|
||||||
|
200 + index * 150
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Animate topic cards with staggered delay
|
||||||
|
const smoothRevealCards = document.querySelectorAll('.smooth-reveal-cards');
|
||||||
|
smoothRevealCards.forEach((el, index) => {
|
||||||
|
setTimeout(
|
||||||
|
() => {
|
||||||
|
el.classList.add('animate-reveal');
|
||||||
|
},
|
||||||
|
500 + index * 100
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Animate with just fade in with staggered delay
|
||||||
|
const smoothRevealFade = document.querySelectorAll('.smooth-reveal-fade');
|
||||||
|
smoothRevealFade.forEach((el, index) => {
|
||||||
|
setTimeout(
|
||||||
|
() => {
|
||||||
|
el.classList.add('animate-reveal-fade');
|
||||||
|
},
|
||||||
|
100 + index * 250
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
animateContent();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -6,6 +6,7 @@ import { marked } from 'marked';
|
|||||||
import markedShiki from 'marked-shiki';
|
import markedShiki from 'marked-shiki';
|
||||||
import { createHighlighter } from 'shiki';
|
import { createHighlighter } from 'shiki';
|
||||||
import { readItems, readSingleton } from '@directus/sdk';
|
import { readItems, readSingleton } from '@directus/sdk';
|
||||||
|
import 'photoswipe/style.css';
|
||||||
|
|
||||||
import SocialShareButton from '@components/buttons/SocialShareButton.astro';
|
import SocialShareButton from '@components/buttons/SocialShareButton.astro';
|
||||||
import Logo from '@components/images/Logo.astro';
|
import Logo from '@components/images/Logo.astro';
|
||||||
@@ -179,6 +180,40 @@ const content = marked.parse(post.content || '');
|
|||||||
</BaseLayout>
|
</BaseLayout>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import PhotoSwipeLightbox from 'photoswipe/lightbox';
|
||||||
|
const prose = document.querySelector('.prose');
|
||||||
|
if (prose) {
|
||||||
|
const images = prose.querySelectorAll('img');
|
||||||
|
images.forEach((img) => {
|
||||||
|
if (img.closest('a')) return;
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = img.src;
|
||||||
|
link.dataset.pswpSrc = img.src;
|
||||||
|
link.dataset.pswpWidth = img.naturalWidth.toString();
|
||||||
|
link.dataset.pswpHeight = img.naturalHeight.toString();
|
||||||
|
link.target = '_blank';
|
||||||
|
link.classList.add('pswp-link');
|
||||||
|
|
||||||
|
img.parentNode?.insertBefore(link, img);
|
||||||
|
link.appendChild(img);
|
||||||
|
|
||||||
|
if (!img.complete) {
|
||||||
|
img.onload = () => {
|
||||||
|
link.dataset.pswpWidth = img.naturalWidth.toString();
|
||||||
|
link.dataset.pswpHeight = img.naturalHeight.toString();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const lightbox = new PhotoSwipeLightbox({
|
||||||
|
gallery: prose,
|
||||||
|
children: 'a.pswp-link',
|
||||||
|
pswpModule: () => import('photoswipe'),
|
||||||
|
});
|
||||||
|
|
||||||
|
lightbox.init();
|
||||||
|
}
|
||||||
|
|
||||||
// Add smooth reveal animations for content after loading
|
// Add smooth reveal animations for content after loading
|
||||||
document.addEventListener('astro:page-load', () => {
|
document.addEventListener('astro:page-load', () => {
|
||||||
const animateContent = () => {
|
const animateContent = () => {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import type { Post } from '@lib/directusTypes';
|
|||||||
import HeroSection from '@components/sections/HeroSection.astro';
|
import HeroSection from '@components/sections/HeroSection.astro';
|
||||||
import SelectedPostsSection from '@components/sections/SelectedPostsSection.astro';
|
import SelectedPostsSection from '@components/sections/SelectedPostsSection.astro';
|
||||||
import RecentPostsSection from '@components/sections/RecentPostsSection.astro';
|
import RecentPostsSection from '@components/sections/RecentPostsSection.astro';
|
||||||
|
import AllPostsSection from '@components/sections/AllPostsSection.astro';
|
||||||
import BaseLayout from '@layouts/BaseLayout.astro';
|
import BaseLayout from '@layouts/BaseLayout.astro';
|
||||||
import directus from '@lib/directus';
|
import directus from '@lib/directus';
|
||||||
|
|
||||||
@@ -60,6 +61,8 @@ const recentPosts: Post[] = posts.filter(
|
|||||||
title="Recent Posts"
|
title="Recent Posts"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<AllPostsSection />
|
||||||
|
|
||||||
</BaseLayout>
|
</BaseLayout>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -65,11 +65,66 @@ const categoriesPosts = posts
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<section class="max-w-340 2xl:max-w-full mb-10 px-4 sm:px-6 lg:px-8 py-8 mx-auto mt-10">
|
<section class="max-w-340 2xl:max-w-full mb-10 px-4 sm:px-6 lg:px-8 py-8 mx-auto mt-10">
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
<div class="columns-1 sm:columns-2 lg:columns-3 gap-6">
|
||||||
{categoriesPosts.map((b) =>
|
{categoriesPosts.map((b) =>
|
||||||
|
<div class="break-inside-avoid mb-6">
|
||||||
<BlogCard post={b} />
|
<BlogCard post={b} />
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
</BaseLayout>
|
</BaseLayout>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Add smooth reveal animations for content after loading
|
||||||
|
document.addEventListener('astro:page-load', () => {
|
||||||
|
const animateContent = () => {
|
||||||
|
// Animate group 1
|
||||||
|
const smoothReveal = document.querySelectorAll('.smooth-reveal');
|
||||||
|
smoothReveal.forEach((el, index) => {
|
||||||
|
setTimeout(
|
||||||
|
() => {
|
||||||
|
el.classList.add('animate-reveal');
|
||||||
|
},
|
||||||
|
50 + index * 100
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Animate group 2
|
||||||
|
const smoothReveal2 = document.querySelectorAll('.smooth-reveal-2');
|
||||||
|
smoothReveal2.forEach((el, index) => {
|
||||||
|
setTimeout(
|
||||||
|
() => {
|
||||||
|
el.classList.add('animate-reveal');
|
||||||
|
},
|
||||||
|
200 + index * 150
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Animate topic cards with staggered delay
|
||||||
|
const smoothRevealCards = document.querySelectorAll('.smooth-reveal-cards');
|
||||||
|
smoothRevealCards.forEach((el, index) => {
|
||||||
|
setTimeout(
|
||||||
|
() => {
|
||||||
|
el.classList.add('animate-reveal');
|
||||||
|
},
|
||||||
|
500 + index * 100
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Animate with just fade in with staggered delay
|
||||||
|
const smoothRevealFade = document.querySelectorAll('.smooth-reveal-fade');
|
||||||
|
smoothRevealFade.forEach((el, index) => {
|
||||||
|
setTimeout(
|
||||||
|
() => {
|
||||||
|
el.classList.add('animate-reveal-fade');
|
||||||
|
},
|
||||||
|
100 + index * 250
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
animateContent();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { readSingleton } from '@directus/sdk';
|
|||||||
|
|
||||||
import HeroSection from '@components/sections/HeroSection.astro';
|
import HeroSection from '@components/sections/HeroSection.astro';
|
||||||
import CategorySection from '@components/sections/CategorySection.astro';
|
import CategorySection from '@components/sections/CategorySection.astro';
|
||||||
|
import AllCategoriesSection from '@components/sections/AllCategoriesSection.astro';
|
||||||
import BaseLayout from '@layouts/BaseLayout.astro';
|
import BaseLayout from '@layouts/BaseLayout.astro';
|
||||||
import directus from '@lib/directus';
|
import directus from '@lib/directus';
|
||||||
|
|
||||||
@@ -40,6 +41,8 @@ const global = await directus.request(readSingleton('site_global'));
|
|||||||
|
|
||||||
<CategorySection />
|
<CategorySection />
|
||||||
|
|
||||||
|
<AllCategoriesSection />
|
||||||
|
|
||||||
</BaseLayout>
|
</BaseLayout>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import HeroSection from '@components/sections/HeroSection.astro';
|
|||||||
import FeatureSection from '@components/sections/FeatureSection.astro';
|
import FeatureSection from '@components/sections/FeatureSection.astro';
|
||||||
import WeatherSection from '@components/sections/WeatherSection.astro';
|
import WeatherSection from '@components/sections/WeatherSection.astro';
|
||||||
import RecentPostsSection from '@components/sections/RecentPostsSection.astro';
|
import RecentPostsSection from '@components/sections/RecentPostsSection.astro';
|
||||||
|
import AllPostsSection from '@components/sections/AllPostsSection.astro';
|
||||||
import GiteaSection from '@components/sections/GiteaSection.astro';
|
import GiteaSection from '@components/sections/GiteaSection.astro';
|
||||||
import BaseLayout from '@layouts/BaseLayout.astro';
|
import BaseLayout from '@layouts/BaseLayout.astro';
|
||||||
import directus from '@lib/directus';
|
import directus from '@lib/directus';
|
||||||
@@ -73,6 +74,8 @@ const recentPosts = posts
|
|||||||
subTitle="Checkout my most recent thoughts here"
|
subTitle="Checkout my most recent thoughts here"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<AllPostsSection />
|
||||||
|
|
||||||
<GiteaSection
|
<GiteaSection
|
||||||
title="Follow me on Gitea"
|
title="Follow me on Gitea"
|
||||||
subTitle="I love open source and have my code availabile on my Gitea server."
|
subTitle="I love open source and have my code availabile on my Gitea server."
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
import { join } from 'node:path';
|
|
||||||
|
|
||||||
function resolveFilePath(path: string) {
|
|
||||||
if (path.startsWith('/')) {
|
|
||||||
return resolveFilePathPublic(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolveFilePathInternal(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
function resolveFilePathPublic(path: string) {
|
|
||||||
return join(process.cwd(), path);
|
|
||||||
}
|
|
||||||
|
|
||||||
function resolveFilePathInternal(path: string) {
|
|
||||||
const normalizePath = path.startsWith('@') ? path.replace('@', '') : path;
|
|
||||||
|
|
||||||
return join(process.cwd(), 'src/', normalizePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
export { resolveFilePath, resolveFilePathPublic, resolveFilePathInternal };
|
|
||||||
Reference in New Issue
Block a user