2025-04-26 23:21:07 -07:00
|
|
|
---
|
|
|
|
import { projects } from "../../lib/list";
|
|
|
|
import Section from "../../components/common/Section.astro";
|
|
|
|
import ProjectSnippet from "../../components/ProjectSnippet.astro";
|
2025-05-03 02:27:26 -07:00
|
|
|
import ProjectSnippetSkeleton from "../../components/ProjectSnippetSkeleton.astro";
|
2025-05-03 01:35:48 -07:00
|
|
|
import SearchBar from "../../components/common/SearchBar.astro";
|
2025-04-26 23:21:07 -07:00
|
|
|
import Layout from "../../layouts/Layout.astro";
|
|
|
|
import { GLOBAL } from "../../lib/variables";
|
2025-05-03 01:35:48 -07:00
|
|
|
import { initializeSearch } from "../../components/common/searchUtils.js";
|
2025-04-26 23:21:07 -07:00
|
|
|
---
|
|
|
|
|
|
|
|
<Layout>
|
|
|
|
<Fragment slot="head">
|
|
|
|
<title>{GLOBAL.projectTitle} • {GLOBAL.username}</title>
|
|
|
|
<meta
|
|
|
|
name="description"
|
|
|
|
content={GLOBAL.projectLongDescription}
|
|
|
|
/>
|
|
|
|
<meta property="og:title" content={`${GLOBAL.projectTitle} • ${GLOBAL.username}`} />
|
|
|
|
<meta
|
|
|
|
property="og:description"
|
|
|
|
content={GLOBAL.projectShortDescription}
|
|
|
|
/>
|
|
|
|
<meta property="og:image" content={`${GLOBAL.rootUrl}/${GLOBAL.profileImage}`} />
|
|
|
|
<meta property="og:url" content={`${GLOBAL.rootUrl}/projects`} />
|
|
|
|
<meta name="twitter:card" content="summary_large_image" />
|
|
|
|
<meta name="twitter:title" content={`${GLOBAL.projectTitle} • ${GLOBAL.username}`} />
|
|
|
|
<meta
|
|
|
|
name="twitter:description"
|
|
|
|
content={GLOBAL.projectShortDescription}
|
|
|
|
/>
|
|
|
|
<meta name="twitter:image" content={`${GLOBAL.rootUrl}/${GLOBAL.profileImage}`} />
|
|
|
|
<meta http-equiv="content-language" content="en" />
|
|
|
|
<meta name="language" content="English" />
|
|
|
|
<link rel="canonical" href={`${GLOBAL.rootUrl}/projects`} />
|
|
|
|
</Fragment>
|
2025-05-03 01:35:48 -07:00
|
|
|
|
|
|
|
<!-- Search functionality is provided by search-client.js -->
|
|
|
|
|
2025-04-26 23:21:07 -07:00
|
|
|
<Section class="py-4 my-8">
|
2025-05-03 02:27:26 -07:00
|
|
|
<div x-data="searchProjects" x-init="init()" x-cloak>
|
2025-05-03 01:35:48 -07:00
|
|
|
<!-- Search container - positioned at the top -->
|
|
|
|
<div class="mb-4 pt-0">
|
|
|
|
<div class="w-full">
|
|
|
|
<SearchBar
|
|
|
|
placeholder="Search projects..."
|
|
|
|
ariaLabel="Search projects"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="flex items-center gap-4 pt-8 pb-16">
|
|
|
|
<h1 class="font-display text-3xl sm:text-4xl leading-loose">{GLOBAL.projectsName}</h1>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<!-- No results message -->
|
|
|
|
<div
|
|
|
|
x-show="searchQuery !== '' && !hasResults"
|
|
|
|
x-transition
|
|
|
|
class="text-center py-8 my-4 border-2 border-dashed border-current zag-text rounded-lg"
|
|
|
|
>
|
|
|
|
<p class="text-xl font-semibold zag-text">No Projects Found</p>
|
|
|
|
</div>
|
|
|
|
|
2025-05-03 02:27:26 -07:00
|
|
|
<!-- Loading skeleton -->
|
|
|
|
<div
|
|
|
|
x-show="loading"
|
|
|
|
x-transition:enter="transition ease-out duration-300"
|
|
|
|
x-transition:enter-start="opacity-0"
|
|
|
|
x-transition:enter-end="opacity-100"
|
|
|
|
x-transition:leave="transition ease-in duration-200"
|
|
|
|
x-transition:leave-start="opacity-100"
|
|
|
|
x-transition:leave-end="opacity-0"
|
|
|
|
>
|
|
|
|
{Array.from({ length: 3 }).map((_, i) => (
|
|
|
|
<ProjectSnippetSkeleton />
|
|
|
|
))}
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<!-- Actual content -->
|
|
|
|
<ul
|
|
|
|
id="project-list"
|
|
|
|
x-show="!loading"
|
|
|
|
x-transition:enter="transition ease-out duration-300"
|
|
|
|
x-transition:enter-start="opacity-0"
|
|
|
|
x-transition:enter-end="opacity-100"
|
|
|
|
>
|
2025-05-03 01:35:48 -07:00
|
|
|
{
|
|
|
|
projects.map((project) => {
|
|
|
|
const projectTags = project.tags ? project.tags.join(' ').toLowerCase() : '';
|
|
|
|
const githubUrl = project.githubUrl || '';
|
|
|
|
const liveUrl = project.liveUrl || '';
|
|
|
|
|
|
|
|
return (
|
|
|
|
<li class="project-item"
|
|
|
|
data-title={project.title.toLowerCase()}
|
|
|
|
data-description={project.description.toLowerCase()}
|
|
|
|
data-tags={projectTags}
|
|
|
|
data-github={githubUrl.toLowerCase()}
|
|
|
|
data-live={liveUrl.toLowerCase()}>
|
|
|
|
<ProjectSnippet
|
|
|
|
title={project.title}
|
|
|
|
description={project.description}
|
|
|
|
url={project.filename}
|
|
|
|
githubUrl={project.githubUrl}
|
|
|
|
liveUrl={project.liveUrl}
|
|
|
|
tags={project.tags ?? []}
|
|
|
|
/>
|
|
|
|
</li>
|
|
|
|
);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
</ul>
|
2025-04-26 23:21:07 -07:00
|
|
|
</div>
|
|
|
|
</Section>
|
|
|
|
</Layout>
|