Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 159 additions & 13 deletions src/lib/components/SiteHeader.svelte
Original file line number Diff line number Diff line change
@@ -1,17 +1,39 @@
<script lang="ts">
import { page } from '$app/state';

let open = $state(false);
let purposeOpen = $state(false);
let contributingOpen = $state(false);
let purposeDropdown: HTMLElement;
let contributingDropdown: HTMLElement;

// Close dropdown when clicking outside
let pathname = $derived(page.url.pathname);

function isActive(href: string): boolean {
if (href === '/') return pathname === '/';
return pathname === href || pathname.startsWith(href + '/');
}

function isPurposeActive(): boolean {
return isActive('/mission') || isActive('/vision');
}

function isContributingActive(): boolean {
return isActive('/email');
}

// Close dropdowns when clicking outside
$effect(() => {
function handleClickOutside(event: MouseEvent) {
if (purposeDropdown && !purposeDropdown.contains(event.target as Node)) {
purposeOpen = false;
}
if (contributingDropdown && !contributingDropdown.contains(event.target as Node)) {
contributingOpen = false;
}
}

if (contributingOpen) {
if (purposeOpen || contributingOpen) {
document.addEventListener('click', handleClickOutside);
return () => document.removeEventListener('click', handleClickOutside);
}
Expand Down Expand Up @@ -40,12 +62,64 @@

<nav class="hidden sm:block">
<ul class="flex items-center gap-6 text-sm">
<li><a class="hover:underline" href="/directory">Directory</a></li>
<li><a class="hover:underline" href="/mission">Mission</a></li>
<li><a class="hover:underline" href="/vision">Vision</a></li>
<li>
<a
class="border-b-2 pb-0.5 transition-colors {isActive('/directory')
? 'border-[--color-brand] font-medium text-[--color-brand]'
: 'border-transparent hover:border-gray-300 hover:text-gray-900'}"
href="/directory"
aria-current={isActive('/directory') ? 'page' : undefined}
>
Directory
</a>
</li>
<li class="relative" bind:this={purposeDropdown}>
<button
class="flex items-center gap-1 border-b-2 pb-0.5 transition-colors {isPurposeActive()
? 'border-[--color-brand] font-medium text-[--color-brand]'
: 'border-transparent hover:border-gray-300 hover:text-gray-900'}"
onclick={() => (purposeOpen = !purposeOpen)}
aria-expanded={purposeOpen}
>
Purpose
<svg
class="h-4 w-4 transition-transform {purposeOpen ? 'rotate-180' : ''}"
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"
></path>
</svg>
</button>
{#if purposeOpen}
<div
class="absolute top-full left-0 z-50 mt-1 min-w-48 border border-gray-300 bg-white py-1 shadow-lg"
>
<a
href="/mission"
onclick={() => (purposeOpen = false)}
class="block border-b border-gray-100 px-4 py-3 text-sm text-gray-700 hover:bg-gray-100"
>Mission</a
>
<a
href="/vision"
onclick={() => (purposeOpen = false)}
class="block px-4 py-3 text-sm text-gray-700 hover:bg-gray-100"
>Vision</a
>
</div>
{/if}
</li>
<li class="relative" bind:this={contributingDropdown}>
<button
class="flex items-center gap-1 hover:underline"
class="flex items-center gap-1 border-b-2 pb-0.5 transition-colors {isContributingActive()
? 'border-[--color-brand] font-medium text-[--color-brand]'
: 'border-transparent hover:border-gray-300 hover:text-gray-900'}"
onclick={() => (contributingOpen = !contributingOpen)}
aria-expanded={contributingOpen}
>
Expand Down Expand Up @@ -121,23 +195,95 @@
onclick={() => (open = !open)}
>
<span class="sr-only">Menu</span>
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
{#if open}
<path d="M18 6 6 18"></path>
<path d="m6 6 12 12"></path>
{:else}
<path d="M4 6h16"></path>
<path d="M4 12h16"></path>
<path d="M4 18h16"></path>
{/if}
</svg>
</button>
</div>
</div>

<nav class={open ? 'block sm:hidden' : 'hidden'}>
<ul class="space-y-2 px-4 pb-4 text-sm">
<li><a class="block py-1" href="/directory" onclick={() => (open = false)}>Directory</a></li>
<li><a class="block py-1" href="/mission" onclick={() => (open = false)}>Mission</a></li>
<li><a class="block py-1" href="/vision" onclick={() => (open = false)}>Vision</a></li>
<li>
<a
class="block py-1 {isActive('/directory')
? 'font-medium text-[--color-brand]'
: 'text-gray-900'}"
href="/directory"
onclick={() => (open = false)}
aria-current={isActive('/directory') ? 'page' : undefined}
>
Directory
</a>
</li>
<li>
<div class="py-1">
<div class="mb-2 font-medium text-gray-900">Contributing</div>
<div
class="mb-2 font-medium {isPurposeActive() ? 'text-[--color-brand]' : 'text-gray-900'}"
>
Purpose
</div>
<div class="space-y-1 pl-3">
<a
class="block py-1 {isActive('/mission')
? 'font-medium text-[--color-brand]'
: 'text-gray-600'}"
href="/mission"
onclick={() => (open = false)}
aria-current={isActive('/mission') ? 'page' : undefined}
>
Mission
</a>
<a
class="block py-1 {isActive('/vision')
? 'font-medium text-[--color-brand]'
: 'text-gray-600'}"
href="/vision"
onclick={() => (open = false)}
aria-current={isActive('/vision') ? 'page' : undefined}
>
Vision
</a>
</div>
</div>
</li>
<li>
<div class="py-1">
<div
class="mb-2 font-medium {isContributingActive()
? 'text-[--color-brand]'
: 'text-gray-900'}"
>
Contributing
</div>
<div class="space-y-1 pl-3">
<a class="block py-1 text-gray-600" href="/email" onclick={() => (open = false)}
>Email activation</a
<a
class="block py-1 {isActive('/email')
? 'font-medium text-[--color-brand]'
: 'text-gray-600'}"
href="/email"
onclick={() => (open = false)}
aria-current={isActive('/email') ? 'page' : undefined}
>
Email activation
</a>
<a
class="block py-1 text-gray-600"
href="https://github.com/openbayan/openbayan.org/issues"
Expand Down
118 changes: 37 additions & 81 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import type { ProjectMeta } from '$lib/content/projects';
import Meta from '$lib/components/Meta.svelte';

let { data } = $props<{ data: { featured: ProjectMeta[] } }>();
let { data } = $props<{ data: { recent: ProjectMeta[] } }>();
</script>

<svelte:head>
Expand Down Expand Up @@ -59,52 +59,8 @@
</div>
</section>

<!-- About Section -->
<section class="bg-white py-16">
<div class="mx-auto max-w-screen-xl px-4">
<div class="grid items-start gap-12 lg:grid-cols-2">
<div>
<h2 class="mb-6 text-2xl font-bold text-gray-900">Our mission</h2>
<p class="mb-6 leading-relaxed text-gray-700">
We act as a consolidated hub for community‑led initiatives and open source projects that
aim to improve public services, transparency, and digital infrastructure across the
Philippines.
</p>
<p class="mb-6 leading-relaxed text-gray-700">
Our mission is to make it easy to discover, support, and contribute to impactful
technology projects.
</p>
<a
href="/mission"
class="inline-flex items-center font-medium text-blue-600 transition-colors hover:text-blue-800 hover:underline"
>
Read our full mission →
</a>
</div>

<div>
<h2 class="mb-6 text-2xl font-bold text-gray-900">Our vision</h2>
<p class="mb-6 leading-relaxed text-gray-700">
A Philippines where open source technology is trusted, widely adopted, and sustainably
maintained by a collaborative community of contributors, public servants, and
organizations.
</p>
<p class="mb-6 leading-relaxed text-gray-700">
We envision a transparent, interoperable, and user-centered digital government ecosystem.
</p>
<a
href="/vision"
class="inline-flex items-center font-medium text-blue-600 transition-colors hover:text-blue-800 hover:underline"
>
Read our full vision →
</a>
</div>
</div>
</div>
</section>

<!-- Featured Projects -->
{#if data.featured.length}
{#if data.recent.length}
<section class="border-t border-gray-200 bg-gray-50 py-16">
<div class="mx-auto max-w-screen-xl px-4">
<div class="mb-12">
Expand All @@ -114,46 +70,46 @@
</p>
</div>

<div class="mb-12 space-y-8">
{#each data.featured.slice(0, 3) as p (p.slug)}
<div class="border border-gray-200 bg-white p-6">
<div class="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
<div class="flex-1">
<h3 class="mb-2 text-xl font-semibold text-gray-900">
<a
href={`/projects/${p.slug}`}
class="text-gray-900 transition-colors hover:text-blue-600"
>
{p.title}
</a>
</h3>
{#if p.summary}
<p class="mb-4 leading-relaxed text-gray-600">{p.summary}</p>
{/if}
{#if p.tags?.length}
<div class="flex flex-wrap gap-2">
{#each p.tags.slice(0, 4) as tag (tag)}
<span class="inline-block bg-gray-100 px-3 py-1 text-sm text-gray-700"
>{tag}</span
>
{/each}
</div>
{/if}
</div>
<div class="lg:ml-6">
<a
href={`/projects/${p.slug}`}
class="inline-flex items-center bg-blue-600 px-4 py-2 font-medium text-white transition-colors hover:bg-blue-700"
<div class="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
{#each data.recent as p (p.slug)}
<a
href={`/projects/${p.slug}`}
class="group flex flex-col border border-gray-200 bg-white p-6 shadow-sm transition-all duration-200 hover:border-[--color-brand] hover:shadow-md focus:ring-2 focus:ring-[--color-brand] focus:outline-none active:scale-[0.98]"
>
<h3
class="mb-2 text-lg font-semibold text-gray-900 transition-colors group-hover:text-[--color-brand]"
>
{p.title}
</h3>
{#if p.summary}
<p class="mb-4 flex-1 text-sm leading-relaxed text-gray-600">
{p.summary.length > 120 ? p.summary.slice(0, 120) + '…' : p.summary}
</p>
{/if}
<div class="mt-auto flex items-center justify-between">
{#if p.status}
<span
class="inline-block rounded-full px-2 py-0.5 text-xs font-medium {p.status ===
'stable'
? 'bg-green-100 text-green-700'
: p.status === 'beta'
? 'bg-blue-100 text-blue-700'
: p.status === 'alpha'
? 'bg-yellow-100 text-yellow-700'
: 'bg-gray-100 text-gray-700'}"
>
View project
</a>
</div>
{p.status}
</span>
{/if}
{#if p.sectors?.length}
<span class="text-xs text-gray-400">{p.sectors[0]}</span>
{/if}
</div>
</div>
</a>
{/each}
</div>

<div>
<div class="mt-12">
<a
href="/directory"
class="inline-flex items-center border border-gray-300 px-6 py-3 font-medium text-gray-700 transition-colors hover:border-gray-400 hover:bg-gray-50"
Expand Down
10 changes: 8 additions & 2 deletions src/routes/+page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ import { getAllProjects } from '$lib/content/projects';

export const load: PageLoad = async () => {
const projects = getAllProjects();
const featured = projects.filter((p) => p.featured).slice(0, 6);
return { featured };
const recent = [...projects]
.sort((a, b) => {
const da = a.dateAdded ? new Date(a.dateAdded).getTime() : 0;
const db = b.dateAdded ? new Date(b.dateAdded).getTime() : 0;
return db - da;
})
.slice(0, 6);
return { recent };
};