filtering working

This commit is contained in:
Justin Deal 2025-05-02 23:16:34 -07:00
parent 780b06b9cf
commit aa66156388

View File

@ -8,6 +8,11 @@ import { services } from "./services.ts";
<Layout>
<Fragment slot="head">
<script is:inline>
document.addEventListener('alpine:init', () => {
// No global store needed
});
</script>
<title>{GLOBAL.username} • {GLOBAL.shortDescription}</title>
<meta name="description" content={GLOBAL.longDescription} />
<meta property="og:title" content={`${GLOBAL.username} • ${GLOBAL.shortDescription}`} />
@ -24,47 +29,82 @@ import { services } from "./services.ts";
</Fragment>
<Section class="my-8">
<div class="flex items-center gap-4 pt-8 pb-4">
<h1 class="font-display text-3xl sm:text-4xl leading-loose">Homelab</h1>
</div>
{Object.entries(services).map(([category, apps], index) => (
<div class="mb-8" x-data="{ open: true }" key={index}>
<button
@click="open = !open"
class="text-xl font-semibold mb-4 w-full text-left flex items-center justify-between"
>
{category}
<svg
:class="{ 'rotate-180': open }"
class="w-5 h-5 transform transition-transform duration-300"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
<div x-data="{ searchQuery: '' }" x-init="
$watch('searchQuery', (query) => {
query = query.toLowerCase();
document.querySelectorAll('.app-card').forEach(card => {
const appName = card.getAttribute('data-app-name').toLowerCase();
if (query === '' || appName.includes(query)) {
card.style.display = '';
} else {
card.style.display = 'none';
}
});
})
">
<div class="flex items-center gap-4 pt-8 pb-4">
<h1 class="font-display text-3xl sm:text-4xl leading-loose">Homelab</h1>
</div>
<div class="mb-6">
<div class="relative">
<input
type="text"
x-model="searchQuery"
placeholder="Search apps..."
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 zag-bg zag-text"
/>
<button
x-show="searchQuery"
@click="searchQuery = ''"
class="absolute right-3 top-1/2 transform -translate-y-1/2"
>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</button>
<div x-show="open" x-transition>
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4">
{apps.length > 0 ? (
apps.map(app => (
<ServiceCard
name={app.name}
href={app.link}
img={app.icon}
alt={app.name}
key={app.link}
/>
))
) : (
<p class="text-center col-span-full">Coming soon...</p>
)}
</div>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
))}
{Object.entries(services).map(([category, apps], index) => (
<div class="mb-8" x-data="{ open: true }">
<button
@click="open = !open"
class="text-xl font-semibold mb-4 w-full text-left flex items-center justify-between"
>
{category}
<svg
:class="{ 'rotate-180': open }"
class="w-5 h-5 transform transition-transform duration-300"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</button>
<div x-show="open" x-transition>
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4">
{apps.length > 0 ? (
apps.map(app => (
<div class="app-card" data-app-name={app.name.toLowerCase()}>
<ServiceCard
name={app.name}
href={app.link}
img={app.icon}
alt={app.name}
/>
</div>
))
) : (
<p class="text-center col-span-full">Coming soon...</p>
)}
</div>
</div>
</div>
))}
</div>
</Section>
</Layout>