feat: add support for multiple links in projects
Projects now support multiple links (source code, demo, etc) each with a label. Migrated all projects to use the new schema.
This commit is contained in:
@@ -24,7 +24,10 @@ const projects = defineCollection({
|
|||||||
description: z.string(),
|
description: z.string(),
|
||||||
tags: z.array(z.string()),
|
tags: z.array(z.string()),
|
||||||
image: image(),
|
image: image(),
|
||||||
link: z.url().optional(),
|
links: z.array(z.object({
|
||||||
|
label: z.string(),
|
||||||
|
url: z.url()
|
||||||
|
})).optional(),
|
||||||
order: z.number().optional(),
|
order: z.number().optional(),
|
||||||
startDate: z.coerce.date().optional(),
|
startDate: z.coerce.date().optional(),
|
||||||
endDate: z.coerce.date().optional(),
|
endDate: z.coerce.date().optional(),
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ name: 'Bullseye'
|
|||||||
description: 'Bullseye is a self-hosted offline-first personal utilities app with habit tracking, tasks, and notes.'
|
description: 'Bullseye is a self-hosted offline-first personal utilities app with habit tracking, tasks, and notes.'
|
||||||
tags: ['typescript', 'svelte', 'sqlite']
|
tags: ['typescript', 'svelte', 'sqlite']
|
||||||
image: '../../../public/static/bullseye.webp'
|
image: '../../../public/static/bullseye.webp'
|
||||||
link: 'https://git.jaroszew.ski/patrick/bullseye-app'
|
links:
|
||||||
|
- label: 'Source Code'
|
||||||
|
url: 'https://git.jaroszew.ski/patrick/bullseye-app'
|
||||||
order: 6
|
order: 6
|
||||||
startDate: '2025-03-30'
|
startDate: '2025-03-30'
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ name: 'Chitai'
|
|||||||
description: 'Chitai is a self-hosted eBook management application'
|
description: 'Chitai is a self-hosted eBook management application'
|
||||||
tags: ['python', 'typescript', 'postgresql', 'svelte', 'open-source']
|
tags: ['python', 'typescript', 'postgresql', 'svelte', 'open-source']
|
||||||
image: '../../../public/static/chitai.webp'
|
image: '../../../public/static/chitai.webp'
|
||||||
link: 'https://git.jaroszew.ski/patrick/chitai'
|
links:
|
||||||
|
- label: 'Source Code'
|
||||||
|
url: 'https://git.jaroszew.ski/patrick/chitai'
|
||||||
order: 2
|
order: 2
|
||||||
startDate: '2025-03-30'
|
startDate: '2025-03-30'
|
||||||
---
|
---
|
||||||
|
|||||||
Vendored
+1
-1
@@ -8,7 +8,7 @@ startDate: '2025-09-23'
|
|||||||
---
|
---
|
||||||
|
|
||||||
<div class="flex flex-wrap gap-2 my-0! [&>img]:my-0! [&>img]:mt-2!" >
|
<div class="flex flex-wrap gap-2 my-0! [&>img]:my-0! [&>img]:mt-2!" >
|
||||||
<img src="https://img.shields.io/badge/Python-3776AB?style=for-the-badge&logo=python&logoColor=white" alt="Python" />
|
<img src="https://img.shields.io/badge/Python-3776AB?style=for-the-badge&logo=python&logoColor=FFD43B" alt="Python" />
|
||||||
<img src="https://img.shields.io/badge/PostgreSQL-336791?style=for-the-badge&logo=postgresql&logoColor=white" alt="PostgreSQL" />
|
<img src="https://img.shields.io/badge/PostgreSQL-336791?style=for-the-badge&logo=postgresql&logoColor=white" alt="PostgreSQL" />
|
||||||
<img src="https://img.shields.io/badge/TypeScript-007ACC?style=for-the-badge&logo=typescript&logoColor=white" alt="TypeScript" />
|
<img src="https://img.shields.io/badge/TypeScript-007ACC?style=for-the-badge&logo=typescript&logoColor=white" alt="TypeScript" />
|
||||||
<img src="https://img.shields.io/badge/Svelte-FF3E00?style=for-the-badge&logo=svelte&logoColor=white" alt="Svelte" />
|
<img src="https://img.shields.io/badge/Svelte-FF3E00?style=for-the-badge&logo=svelte&logoColor=white" alt="Svelte" />
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ name: 'Marketing Site'
|
|||||||
description: 'A simple marketing site built for a small business.'
|
description: 'A simple marketing site built for a small business.'
|
||||||
tags: ['astro', 'tailwindcss']
|
tags: ['astro', 'tailwindcss']
|
||||||
image: '../../../public/static/druksubli.webp'
|
image: '../../../public/static/druksubli.webp'
|
||||||
link: 'https://druksubli.pl'
|
links:
|
||||||
|
- label: 'Live Site'
|
||||||
|
url: 'https://druksubli.pl'
|
||||||
order: 5
|
order: 5
|
||||||
startDate: '2025-04-16'
|
startDate: '2025-04-16'
|
||||||
endDate: '2025-05-29'
|
endDate: '2025-05-29'
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ name: 'Homelab'
|
|||||||
description: 'My homelab is where I tinker and learn new technologies.'
|
description: 'My homelab is where I tinker and learn new technologies.'
|
||||||
tags: ['proxmox', 'networking', 'hardware']
|
tags: ['proxmox', 'networking', 'hardware']
|
||||||
image: '../../../public/static/homelab.webp'
|
image: '../../../public/static/homelab.webp'
|
||||||
link: 'https://git.jaroszew.ski/ansible'
|
links:
|
||||||
|
- label: 'Ansible Configs'
|
||||||
|
url: 'https://git.jaroszew.ski/ansible'
|
||||||
order: 1
|
order: 1
|
||||||
startDate: '2023-05-15'
|
startDate: '2023-05-15'
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -3,7 +3,11 @@ name: 'Personal Portfolio'
|
|||||||
description: 'Personal Portfolio is a personal website that showcases my work and projects. It is built with Astro.js and styled with Tailwind CSS, providing a fast and responsive user experience. The website features a clean design, easy navigation, and a focus on showcasing my skills and projects.'
|
description: 'Personal Portfolio is a personal website that showcases my work and projects. It is built with Astro.js and styled with Tailwind CSS, providing a fast and responsive user experience. The website features a clean design, easy navigation, and a focus on showcasing my skills and projects.'
|
||||||
tags: ['astro', 'tailwindcss', 'typescript', 'svelte']
|
tags: ['astro', 'tailwindcss', 'typescript', 'svelte']
|
||||||
image: '../../../public/static/portfolio.webp'
|
image: '../../../public/static/portfolio.webp'
|
||||||
link: 'https://patrick.jaroszew.ski'
|
links:
|
||||||
|
- label: 'Live Site'
|
||||||
|
url: 'https://patrick.jaroszew.ski'
|
||||||
|
- label: 'Source Code'
|
||||||
|
url: 'https://git.jaroszew.ski/patrick/portfolio'
|
||||||
order: 4
|
order: 4
|
||||||
startDate: '2026-03-10'
|
startDate: '2026-03-10'
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -126,18 +126,28 @@ const currentUrl = Astro.url;
|
|||||||
<p>{project.data.description}</p>
|
<p>{project.data.description}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{project.data.link && (
|
{(project.data.links || project.data.link) && (
|
||||||
<>
|
<>
|
||||||
<hr class="my-4 border-t" />
|
<hr class="my-4 border-t" />
|
||||||
|
|
||||||
<div class="flex flex-col gap-2 text-sm text-muted-foreground">
|
<div class="flex flex-col gap-2 text-sm text-muted-foreground">
|
||||||
<h3 class="text-base font-semibold">Project Links</h3>
|
<h3 class="text-base font-semibold">Project Links</h3>
|
||||||
<ul class="list-disc pl-4">
|
<ul class="list-disc pl-4">
|
||||||
|
{project.data.links ? (
|
||||||
|
project.data.links.map((link) => (
|
||||||
|
<li>
|
||||||
|
<a href={link.url} target="_blank" rel="noopener noreferrer" aria-label={link.label}>
|
||||||
|
{link.label}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))
|
||||||
|
) : project.data.link ? (
|
||||||
<li>
|
<li>
|
||||||
<a href={project.data.link} target="_blank" rel="noopener noreferrer" aria-label="Project link">
|
<a href={project.data.link} target="_blank" rel="noopener noreferrer" aria-label="Project link">
|
||||||
{project.data.link}
|
{project.data.link}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
) : null}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
@@ -155,18 +165,28 @@ const currentUrl = Astro.url;
|
|||||||
<p>{project.data.description}</p>
|
<p>{project.data.description}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{project.data.link && (
|
{(project.data.links || project.data.link) && (
|
||||||
<>
|
<>
|
||||||
<hr class="my-4 border-t" />
|
<hr class="my-4 border-t" />
|
||||||
|
|
||||||
<div class="flex flex-col gap-2 text-sm text-muted-foreground">
|
<div class="flex flex-col gap-2 text-sm text-muted-foreground">
|
||||||
<h3 class="text-base font-semibold">Project Links</h3>
|
<h3 class="text-base font-semibold">Project Links</h3>
|
||||||
<ul class="list-disc pl-4">
|
<ul class="list-disc pl-4">
|
||||||
|
{project.data.links ? (
|
||||||
|
project.data.links.map((link) => (
|
||||||
|
<li>
|
||||||
|
<a href={link.url} target="_blank" rel="noopener noreferrer" aria-label={link.label}>
|
||||||
|
{link.label}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))
|
||||||
|
) : project.data.link ? (
|
||||||
<li>
|
<li>
|
||||||
<a href={project.data.link} target="_blank" rel="noopener noreferrer" aria-label="Project link">
|
<a href={project.data.link} target="_blank" rel="noopener noreferrer" aria-label="Project link">
|
||||||
{project.data.link}
|
{project.data.link}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
) : null}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
Reference in New Issue
Block a user