Compare commits
30 Commits
Author | SHA1 | Date | |
---|---|---|---|
03195017c5 | |||
fc3f4fdad4 | |||
fc42f31fb0 | |||
|
e56b3a001e | ||
|
13711618b7 | ||
04980a38af | |||
385ad20c82 | |||
761652f46d | |||
|
8f6b1af8ad | ||
|
90c8d30e3f | ||
|
ad9128acea | ||
|
5f9235c9dc | ||
|
3b2702af36 | ||
|
f999b9a92c | ||
|
35c940bef7 | ||
|
7aa6898a93 | ||
9d77c9db2a | |||
528eb8fb2e | |||
14e73d61ef | |||
|
d10fe280a5 | ||
|
5ea5774042 | ||
|
3c82fb43d8 | ||
|
c7071ab583 | ||
|
125d70d62e | ||
|
357634d3f0 | ||
|
bd4b85c874 | ||
7efa375427 | |||
358d6b91c6 | |||
92d4be91df | |||
0f5fc27371 |
@@ -1,2 +1,2 @@
|
||||
# This file is processed by Renovate bot so that it creates a PR on new major Renovate versions
|
||||
FROM renovate/renovate:38
|
||||
FROM renovate/renovate:39
|
4
.github/renovate.json
vendored
4
.github/renovate.json
vendored
@@ -15,7 +15,7 @@
|
||||
"packageRules": [
|
||||
{
|
||||
"description": "Disables for non major Renovate version",
|
||||
"matchPaths": [
|
||||
"matchFileNames": [
|
||||
".github/renovate-update-notification/Dockerfile"
|
||||
],
|
||||
"matchUpdateTypes": [
|
||||
@@ -29,7 +29,7 @@
|
||||
},
|
||||
{
|
||||
"description": "Generate for major Renovate version",
|
||||
"matchPaths": [
|
||||
"matchFileNames": [
|
||||
".github/renovate-update-notification/Dockerfile"
|
||||
],
|
||||
"matchUpdateTypes": [
|
||||
|
6
.github/workflows/release-image.yml
vendored
6
.github/workflows/release-image.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Log into the container registry
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
|
||||
- name: Extract metadata for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@60a0d343a0d8a18aedee9d34e62251f752153bdb
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
|
@@ -1,6 +1,6 @@
|
||||
FROM node:20.16.0-alpine3.20 AS base
|
||||
FROM node:22.14.0-alpine3.20 AS base
|
||||
|
||||
LABEL version="0.4.0"
|
||||
LABEL version="0.6.4"
|
||||
LABEL description="Astro based website to use as a profile"
|
||||
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
|
@@ -3,7 +3,7 @@ import { defineConfig } from 'astro/config';
|
||||
import node from "@astrojs/node";
|
||||
|
||||
export default defineConfig({
|
||||
output: "hybrid",
|
||||
output: "static",
|
||||
adapter: node({
|
||||
mode: "standalone"
|
||||
})
|
||||
|
50
lib/directus.ts
Normal file
50
lib/directus.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { createDirectus, rest, } from '@directus/sdk';
|
||||
|
||||
type Global = {
|
||||
title: string;
|
||||
description: string;
|
||||
name: string;
|
||||
tagline: string;
|
||||
email: string;
|
||||
portrait: string;
|
||||
about: string;
|
||||
}
|
||||
|
||||
type About = {
|
||||
background: string;
|
||||
experience: string;
|
||||
education: string;
|
||||
certifications: string;
|
||||
}
|
||||
|
||||
type Skills = {
|
||||
skill_1: string;
|
||||
skill_1_description: string;
|
||||
skill_2: string;
|
||||
skill_2_description: string;
|
||||
skill_3: string;
|
||||
skill_3_description: string;
|
||||
}
|
||||
|
||||
export type Post = {
|
||||
slug: string;
|
||||
title: string;
|
||||
content: string;
|
||||
image: string;
|
||||
published_date: string;
|
||||
tags: string[];
|
||||
image_alt: string;
|
||||
}
|
||||
|
||||
type Schema = {
|
||||
global: Global;
|
||||
about: About;
|
||||
skills: Skills;
|
||||
posts: Post[];
|
||||
}
|
||||
|
||||
export const directus_url = "https://directus.alexlebens.dev"
|
||||
|
||||
const directus = createDirectus<Schema>(directus_url).with(rest());
|
||||
|
||||
export default directus;
|
12
package.json
12
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "site-profile",
|
||||
"type": "module",
|
||||
"version": "0.4.0",
|
||||
"version": "0.6.4",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"start": "astro dev",
|
||||
@@ -10,10 +10,10 @@
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/check": "^0.9.3",
|
||||
"@astrojs/node": "^8.3.3",
|
||||
"@directus/sdk": "^17.0.0",
|
||||
"astro": "^4.14.2",
|
||||
"typescript": "^5.5.4"
|
||||
"@astrojs/check": "^0.9.4",
|
||||
"@astrojs/node": "^9.1.3",
|
||||
"@directus/sdk": "^19.0.0",
|
||||
"astro": "^5.5.2",
|
||||
"typescript": "^5.8.2"
|
||||
}
|
||||
}
|
2345
pnpm-lock.yaml
generated
2345
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 3.5 MiB |
Binary file not shown.
Before Width: | Height: | Size: 188 KiB |
Binary file not shown.
Before Width: | Height: | Size: 38 KiB |
Binary file not shown.
Before Width: | Height: | Size: 20 KiB |
Binary file not shown.
Before Width: | Height: | Size: 21 KiB |
Binary file not shown.
Before Width: | Height: | Size: 27 KiB |
@@ -1,11 +1,16 @@
|
||||
---
|
||||
import CallToAction from './CallToAction.astro';
|
||||
import Icon from './Icon.astro';
|
||||
|
||||
import directus from "../../lib/directus"
|
||||
import { readSingleton } from "@directus/sdk";
|
||||
|
||||
const global = await directus.request(readSingleton("global"));
|
||||
---
|
||||
|
||||
<aside>
|
||||
<h2>Interested in working together?</h2>
|
||||
<CallToAction href="mailto:alexander.lebens@gmail.com">
|
||||
<CallToAction href=`mailto:${global.email}`>
|
||||
Send Me a Message
|
||||
<Icon icon="paper-plane-tilt" size="1.2em" />
|
||||
</CallToAction>
|
||||
|
@@ -1,6 +1,11 @@
|
||||
---
|
||||
import Icon from './Icon.astro';
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
import directus from "../../lib/directus"
|
||||
import { readSingleton } from "@directus/sdk";
|
||||
|
||||
const global = await directus.request(readSingleton("global"));
|
||||
---
|
||||
|
||||
<footer>
|
||||
@@ -9,7 +14,7 @@ const currentYear = new Date().getFullYear();
|
||||
Designed & Developed in Minnesota with <a href="https://astro.build/">Astro</a>
|
||||
<Icon icon="rocket-launch" size="1.2em" />
|
||||
</p>
|
||||
<p>© {currentYear} Alex Lebens</p>
|
||||
<p>© {currentYear} {global.name}</p>
|
||||
</div>
|
||||
<p class="socials">
|
||||
<a href="https://github.com/alexlebens"> GitHub</a>
|
||||
|
@@ -1,14 +1,19 @@
|
||||
---
|
||||
import '../styles/global.css';
|
||||
|
||||
import directus from "../../lib/directus"
|
||||
import { readSingleton } from "@directus/sdk";
|
||||
|
||||
interface Props {
|
||||
title?: string | undefined;
|
||||
description?: string | undefined;
|
||||
}
|
||||
|
||||
const global = await directus.request(readSingleton("global"));
|
||||
|
||||
const {
|
||||
title = 'Alex Lebens',
|
||||
description = 'A profile of Alex Lebens',
|
||||
title = `${global.name}`,
|
||||
description = `A profile of ${global.name}`,
|
||||
} = Astro.props;
|
||||
---
|
||||
|
||||
|
@@ -3,6 +3,9 @@ import Icon from './Icon.astro';
|
||||
import ThemeToggle from './ThemeToggle.astro';
|
||||
import type { iconPaths } from './IconPaths';
|
||||
|
||||
import directus from "../../lib/directus"
|
||||
import { readSingleton } from "@directus/sdk";
|
||||
|
||||
const textLinks: { label: string; href: string }[] = [
|
||||
{ label: 'Home', href: '/' },
|
||||
{ label: 'Projects', href: '/projects/' },
|
||||
@@ -13,13 +16,15 @@ const iconLinks: { label: string; href: string; icon: keyof typeof iconPaths }[]
|
||||
{ label: 'GitHub', href: 'https://github.com/alexlebens', icon: 'github-logo' },
|
||||
{ label: 'LinkedIn', href: 'https://www.linkedin.com/in/alexanderlebens', icon: 'linkedin-logo' },
|
||||
];
|
||||
|
||||
const global = await directus.request(readSingleton("global"));
|
||||
---
|
||||
|
||||
<nav>
|
||||
<div class="menu-header">
|
||||
<a href="/" class="site-title">
|
||||
<Icon icon="terminal-window" color="var(--accent-regular)" size="1.6em" gradient />
|
||||
Alex Lebens
|
||||
{global.name}
|
||||
</a>
|
||||
<menu-button>
|
||||
<template>
|
||||
|
@@ -1,16 +1,17 @@
|
||||
---
|
||||
import type { CollectionEntry } from 'astro:content';
|
||||
import type { Post } from '../../lib/directus';
|
||||
import { directus_url } from '../../lib/directus';
|
||||
|
||||
interface Props {
|
||||
project: CollectionEntry<'projects'>;
|
||||
posts: Post;
|
||||
}
|
||||
|
||||
const { data, slug } = Astro.props.project;
|
||||
const post: Post = Astro.props.posts;
|
||||
---
|
||||
|
||||
<a class="card" href={`/projects/${slug}`}>
|
||||
<span class="title">{data.title}</span>
|
||||
<img src={data.img} alt={data.img_alt || ''} loading="lazy" decoding="async" />
|
||||
<a class="card" href={`/projects/${post.slug}`}>
|
||||
<span class="title">{post.title}</span>
|
||||
<img src={`${directus_url}/assets/${post.image}?width=500`} alt={post.image_alt || ''} loading="lazy" decoding="async" />
|
||||
</a>
|
||||
|
||||
<style>
|
||||
|
@@ -1,22 +1,27 @@
|
||||
---
|
||||
import Icon from './Icon.astro';
|
||||
|
||||
import directus from "../../lib/directus"
|
||||
import { readSingleton } from "@directus/sdk";
|
||||
|
||||
const skills = await directus.request(readSingleton("skills"));
|
||||
---
|
||||
|
||||
<section class="box skills">
|
||||
<div class="stack gap-2 lg:gap-4">
|
||||
<Icon icon="cloud" color="var(--accent-regular)" size="2.5rem" gradient />
|
||||
<h2>AWS</h2>
|
||||
<p>Certified DevOps Engineer and former AWS Cloud Engineer skilled in deploying, managing, and architecting a wide range of AWS services.</p>
|
||||
<h2 set:html={skills.skill_1}/>
|
||||
<p set:html={skills.skill_1_description}/>
|
||||
</div>
|
||||
<div class="stack gap-2 lg:gap-4">
|
||||
<Icon icon="network" color="var(--accent-regular)" size="2.5rem" gradient />
|
||||
<h2>Kubernetes</h2>
|
||||
<p>My skills encompass Kubernetes administration and application development, validated by my CKA and CKAD certifications.</p>
|
||||
<h2 set:html={skills.skill_2}/>
|
||||
<p set:html={skills.skill_2_description}/>
|
||||
</div>
|
||||
<div class="stack gap-2 lg:gap-4">
|
||||
<Icon icon="strategy" color="var(--accent-regular)" size="2.5rem" gradient />
|
||||
<h2>GitOps</h2>
|
||||
<p>Hands-on experience leveraging a variety of IaC tools such as CloudFormation, CDK, Helm, and ArgoCD to streamline infrastructure provisioning and management across multiple projects.</p>
|
||||
<h2 set:html={skills.skill_3}/>
|
||||
<p set:html={skills.skill_3_description}/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
@@ -1,15 +0,0 @@
|
||||
import { defineCollection, z } from 'astro:content';
|
||||
|
||||
export const collections = {
|
||||
projects: defineCollection({
|
||||
type: 'content',
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
description: z.string(),
|
||||
publishDate: z.coerce.date(),
|
||||
tags: z.array(z.string()),
|
||||
img: z.string(),
|
||||
img_alt: z.string().optional(),
|
||||
}),
|
||||
}),
|
||||
};
|
@@ -1,21 +0,0 @@
|
||||
---
|
||||
title: Placeholder
|
||||
publishDate: 2019-12-01 00:00:00
|
||||
img: /assets/stock-2.jpg
|
||||
img_alt: A bright pink sheet of paper used to wrap flowers curves in front of rich blue background
|
||||
description: |
|
||||
Placeholder
|
||||
tags:
|
||||
- Dev
|
||||
- Backend
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur posuere commodo venenatis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nam non ligula vel metus efficitur hendrerit. In hac habitasse platea dictumst. Praesent et mauris ut mi dapibus semper. Curabitur tortor justo, efficitur sit amet pretium cursus, porta eget odio. Cras ac venenatis dolor. Donec laoreet posuere malesuada. Curabitur nec mi tempor, placerat leo sit amet, tincidunt est. Quisque pellentesque venenatis magna, eget tristique nibh pulvinar in. Vestibulum vitae volutpat arcu. Aenean ut malesuada odio, sit amet pellentesque odio. Suspendisse nunc elit, blandit nec hendrerit non, aliquet at magna. Donec id leo ut nulla sagittis sodales.
|
||||
|
||||
Integer vitae nibh elit. Suspendisse eget urna eu neque bibendum pharetra. Sed interdum lectus sem, in pulvinar magna dignissim vel. Quisque maximus at urna nec laoreet. Suspendisse potenti. Vestibulum rhoncus sem ut mi pellentesque, in vestibulum erat blandit. Aliquam sodales dui ac maximus consectetur. Duis quis est vehicula, imperdiet nisl nec, fermentum erat. Duis tortor diam, pharetra eu euismod in, vehicula non eros. Curabitur facilisis dui at erat ultrices gravida. In at nunc ultricies, pulvinar mi vel, sagittis mauris. Praesent pharetra posuere purus ac imperdiet. Nulla facilisi.
|
||||
|
||||
Sed pulvinar porttitor mi in ultricies. Etiam non dolor gravida eros pulvinar pellentesque et dictum ex. Proin eu ornare ligula, sed condimentum dui. Vivamus tincidunt tellus mi, sed semper ipsum pharetra a. Suspendisse sollicitudin at sapien nec volutpat. Etiam justo urna, laoreet ac lacus sed, ultricies facilisis dolor. Integer posuere, metus vel viverra gravida, risus elit ornare magna, id feugiat erat risus ullamcorper libero. Proin vitae diam auctor, laoreet lorem vitae, varius tellus.
|
||||
|
||||
Mauris sed eros in ex maximus volutpat. Suspendisse potenti. Donec lacinia justo consectetur sagittis tempor. Proin ullamcorper nisi vitae auctor rhoncus. Sed tristique aliquam augue. Pellentesque vitae fringilla ligula. Nulla arcu elit, efficitur eu nunc malesuada, eleifend tincidunt orci. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer mattis orci in bibendum ultricies. Quisque a dui erat. Phasellus et vulputate ipsum. Proin metus ex, lobortis nec ornare eget, bibendum ut sapien. Aliquam in dolor lobortis, aliquam tellus a, congue augue. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
|
||||
Aenean pretium purus augue, ut bibendum erat convallis quis. Cras condimentum quis velit ac mollis. Suspendisse non purus fringilla, venenatis nisl porta, finibus odio. Curabitur aliquet metus faucibus libero interdum euismod. Morbi sed magna nisl. Morbi odio nibh, facilisis vel sapien eu, tempus tincidunt erat. Nullam erat velit, sagittis at purus quis, tristique scelerisque tortor. Pellentesque lacinia tortor id est aliquam viverra. Vestibulum et diam ac ipsum mollis fringilla.
|
@@ -3,9 +3,15 @@ import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
|
||||
import ContactCTA from '../components/ContactCTA.astro';
|
||||
import Hero from '../components/Hero.astro';
|
||||
|
||||
import directus, { directus_url } from "../../lib/directus"
|
||||
import { readSingleton } from "@directus/sdk";
|
||||
|
||||
const global = await directus.request(readSingleton("global"));
|
||||
const about = await directus.request(readSingleton("about"));
|
||||
---
|
||||
|
||||
<BaseLayout title="About | Alex Lebens" description="About Alex Lebens">
|
||||
<BaseLayout title=`About | ${global.name}` description=`About ${global.name}`>
|
||||
<div class="stack gap-20">
|
||||
<main class="wrapper about">
|
||||
<Hero
|
||||
@@ -15,51 +21,38 @@ import Hero from '../components/Hero.astro';
|
||||
<img
|
||||
width="1553"
|
||||
height="873"
|
||||
src="/assets/hiking.jpg"
|
||||
alt="Alex Lebens hiking in Texas"
|
||||
src=`${directus_url}/assets/${global.about}`
|
||||
alt=`${global.name} hiking in Texas`
|
||||
/>
|
||||
</Hero>
|
||||
|
||||
<section>
|
||||
<h2 class="section-title">Background</h2>
|
||||
<div class="content">
|
||||
<p>
|
||||
Grew up exploring the outdoors just north of the Twin Cities. Now, my passions include tinkering with my homelab,
|
||||
camping adventures in my Jeep, and hitting the slopes or trails for skiing and hiking. I've also been fortunate
|
||||
enough to travel extensively, visiting nearly every continent, including Antarctica!
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="content"
|
||||
set:html={about.background}
|
||||
/>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title">Expierence</h2>
|
||||
<div class="content">
|
||||
<p>
|
||||
Proudly served 6 years in the US Air Force, gaining valuable experience in Cyber Operations and Reconnaissance
|
||||
while stationed in Japan, Korea, and Texas.
|
||||
</p>
|
||||
<p>
|
||||
Gained valuable experience working in the heart of Washington, D.C. for several years, including time at AWS.
|
||||
Relocated to Denver in late 2020 to enjoy the outdoor opportunities Colorado has to offer.
|
||||
</p>
|
||||
<p>
|
||||
Recently returned to my roots in Minnesota and eager to embrace new opportunities and challenges in my home state.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
<h2 class="section-title">Experience</h2>
|
||||
<div
|
||||
class="content"
|
||||
set:html={about.experience}
|
||||
/>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title">Education</h2>
|
||||
<div class="content">
|
||||
<p>Currently completing my B.S. in Cloud Computing at Western Governors University. Excited to graduate in 2025!</p>
|
||||
</div>
|
||||
<div
|
||||
class="content"
|
||||
set:html={about.education}
|
||||
/>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title">Certifications</h2>
|
||||
<div class="content">
|
||||
<p>AWS DevOps Engineer</p>
|
||||
<p>Certified Kubernetes Administrator</p>
|
||||
<p>Certified Kubernetes Application Developer</p>
|
||||
<p>CompTIA Cloud+</p>
|
||||
</div>
|
||||
<div
|
||||
class="content"
|
||||
set:html={about.certifications}
|
||||
/>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
|
@@ -1,6 +1,4 @@
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
|
||||
import CallToAction from '../components/CallToAction.astro';
|
||||
@@ -13,35 +11,43 @@ import PortfolioPreview from '../components/PortfolioPreview.astro';
|
||||
import ContactCTA from '../components/ContactCTA.astro';
|
||||
import Skills from '../components/Skills.astro';
|
||||
|
||||
const projects = (await getCollection('projects'))
|
||||
.sort((a, b) => b.data.publishDate.valueOf() - a.data.publishDate.valueOf())
|
||||
.slice(0, 4);
|
||||
import directus, { directus_url } from "../../lib/directus"
|
||||
import { readItems,readSingleton } from "@directus/sdk";
|
||||
|
||||
const global = await directus.request(readSingleton("global"));
|
||||
|
||||
const posts = await directus.request(
|
||||
readItems("posts", {
|
||||
fields: ['*'],
|
||||
sort: ["-published_date"],
|
||||
})
|
||||
);
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title="Home | Alex Lebens"
|
||||
title=`Home | ${global.name}`
|
||||
description=""
|
||||
>
|
||||
<div class="stack gap-20 lg:gap-48">
|
||||
<div class="wrapper stack gap-8 lg:gap-20">
|
||||
<header class="hero">
|
||||
<Hero
|
||||
title="Hello, my name is Alex Lebens"
|
||||
tagline="I am a Cloud Engineer who is currently based in St. Paul, Minnesota."
|
||||
title=`Hello, my name is ${global.name}`
|
||||
tagline={global.tagline}
|
||||
align="start"
|
||||
>
|
||||
<div class="roles">
|
||||
<Pill><Icon icon="hard-drives" size="1.33em" /> Engineer</Pill>
|
||||
<Pill><Icon icon="hard-drives" size="1.33em" /> Engineer</Pill>
|
||||
<Pill><Icon icon="code" size="1.33em" /> Developer</Pill>
|
||||
<Pill><Icon icon="pencil-line" size="1.33em" /> Writer</Pill>
|
||||
</div>
|
||||
</Hero>
|
||||
|
||||
<img
|
||||
alt="Alex Lebens in Antarctica"
|
||||
alt=`${global.name} in Antarctica`
|
||||
width="480"
|
||||
height="620"
|
||||
src="/assets/portrait.jpg"
|
||||
src=`${directus_url}/assets/${global.portrait}`
|
||||
/>
|
||||
</header>
|
||||
|
||||
@@ -57,13 +63,13 @@ const projects = (await getCollection('projects'))
|
||||
|
||||
<div class="gallery">
|
||||
<Grid variant="offset">
|
||||
{
|
||||
projects.map((project) => (
|
||||
<li>
|
||||
<PortfolioPreview project={project} />
|
||||
</li>
|
||||
))
|
||||
}
|
||||
{
|
||||
posts.map((post) => (
|
||||
<li>
|
||||
<PortfolioPreview posts={post} />
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</Grid>
|
||||
</div>
|
||||
|
||||
|
@@ -1,6 +1,4 @@
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
|
||||
import ContactCTA from '../components/ContactCTA.astro';
|
||||
@@ -8,14 +6,22 @@ import PortfolioPreview from '../components/PortfolioPreview.astro';
|
||||
import Hero from '../components/Hero.astro';
|
||||
import Grid from '../components/Grid.astro';
|
||||
|
||||
const projects = (await getCollection('projects')).sort(
|
||||
(a, b) => b.data.publishDate.valueOf() - a.data.publishDate.valueOf(),
|
||||
import directus from "../../lib/directus"
|
||||
import { readItems,readSingleton } from "@directus/sdk";
|
||||
|
||||
const global = await directus.request(readSingleton("global"));
|
||||
|
||||
const posts = await directus.request(
|
||||
readItems("posts", {
|
||||
fields: ['*'],
|
||||
sort: ["-published_date"],
|
||||
})
|
||||
);
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title="My Projects | Alex Lebens"
|
||||
description="Learn about Alex Lebens's most recent projects"
|
||||
title=`My Projects | ${global.name}`
|
||||
description=`Learn about ${global.name}'s most recent projects`
|
||||
>
|
||||
<div class="stack gap-20">
|
||||
<main class="wrapper stack gap-8">
|
||||
@@ -25,13 +31,13 @@ const projects = (await getCollection('projects')).sort(
|
||||
align="start"
|
||||
/>
|
||||
<Grid variant="offset">
|
||||
{
|
||||
projects.map((project) => (
|
||||
<li>
|
||||
<PortfolioPreview project={project} />
|
||||
</li>
|
||||
))
|
||||
}
|
||||
{
|
||||
posts.map((post) => (
|
||||
<li>
|
||||
<PortfolioPreview posts={post} />
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</Grid>
|
||||
</main>
|
||||
<ContactCTA />
|
||||
|
@@ -1,6 +1,4 @@
|
||||
---
|
||||
import { type CollectionEntry, getCollection } from 'astro:content';
|
||||
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
|
||||
import ContactCTA from '../../components/ContactCTA.astro';
|
||||
@@ -8,43 +6,44 @@ import Hero from '../../components/Hero.astro';
|
||||
import Icon from '../../components/Icon.astro';
|
||||
import Pill from '../../components/Pill.astro';
|
||||
|
||||
interface Props {
|
||||
entry: CollectionEntry<'projects'>;
|
||||
}
|
||||
import directus, { directus_url } from "../../../lib/directus";
|
||||
import { readItems } from "@directus/sdk";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const projects = await getCollection('projects');
|
||||
return projects.map((entry) => ({
|
||||
params: { slug: entry.slug },
|
||||
props: { entry },
|
||||
}));
|
||||
const posts = await directus.request(readItems("posts", {
|
||||
fields: ['*'],
|
||||
}));
|
||||
return posts.map((post) => ({ params: { slug: post.slug }, props: post }));
|
||||
}
|
||||
|
||||
const { entry } = Astro.props;
|
||||
const { Content } = await entry.render();
|
||||
const post = Astro.props;
|
||||
const published_date: string = new Date(post.published_date).toLocaleDateString();
|
||||
---
|
||||
|
||||
<BaseLayout title={entry.data.title} description={entry.data.description}>
|
||||
<BaseLayout title={post.title}>
|
||||
<div class="stack gap-20">
|
||||
<div class="stack gap-15">
|
||||
<header>
|
||||
<div class="wrapper stack gap-2">
|
||||
<a class="back-link" href="/projects/"><Icon icon="arrow-left" /> Projects</a>
|
||||
<Hero title={entry.data.title} align="start">
|
||||
<Hero
|
||||
title={post.title}
|
||||
tagline=`Published on ${published_date}`
|
||||
align="start"
|
||||
>
|
||||
<div class="details">
|
||||
<div class="tags">
|
||||
{entry.data.tags.map((t) => <Pill>{t}</Pill>)}
|
||||
{post.tags.map((t) => <Pill>{t}</Pill>)}
|
||||
</div>
|
||||
<p class="description">{entry.data.description}</p>
|
||||
</div>
|
||||
</Hero>
|
||||
</div>
|
||||
</header>
|
||||
<main class="wrapper">
|
||||
<div class="stack gap-10 content">
|
||||
{entry.data.img && <img src={entry.data.img} alt={entry.data.img_alt || ''} />}
|
||||
{post.image && <img src={`${directus_url}/assets/${post.image}?width=500`} alt={post.image_alt || ''} />}
|
||||
<div class="content">
|
||||
<Content />
|
||||
<div set:html={post.content} />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
Reference in New Issue
Block a user