Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,4 @@ config.

# allow required generated files
!app/icons.gen.ts
!app/overrides.gen.css
!app/overrides.gen.css
25 changes: 7 additions & 18 deletions app/releases/page.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,17 @@
import { getReleases } from "@/lib/releases";
import { ReleaseCard } from "@/components/Releases/ReleaseCard";
import ReleasesClient from "@/components/Releases/ReleasesClient";

export default async function ReleasesPage() {
const releases = await getReleases();

return (
<div className="max-w-5xl mx-auto px-4 py-10 space-y-6">
<div>
<h1 className="text-3xl font-bold text-[#50B78B]">
Releases
</h1>
<p className="text-sm text-zinc-500 mt-1">
Celebrating contributors across CircuitVerse releases
</p>
</div>
<div className="mx-auto w-full max-w-5xl px-4 py-10">
<h1 className="text-3xl font-bold text-[#50B78B]">Releases</h1>
<p className="text-sm text-zinc-500 mt-1">
Celebrating contributors across CircuitVerse releases
</p>

<div className="space-y-4">
{releases.map((release, index) => (
<ReleaseCard
key={`${release.repoSlug}-${release.version}`}
release={release}
/>
))}
</div>
<ReleasesClient releases={releases} />
</div>
);
}
27 changes: 14 additions & 13 deletions components/Releases/ReleaseCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,25 @@ export function ReleaseCard({ release }: { release: Release }) {
<Card className="transition-all hover:shadow-md hover:border-[#50B78B]/50">
<CardContent className="p-5 space-y-4">
{/* Header */}
<div className="flex items-start justify-between gap-4">
<div>
<h3 className="text-lg font-semibold">
{release.repo} — {release.version}
</h3>
<p className="text-sm text-muted-foreground">
{release.summary}
</p>
</div>
<div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-2 sm:gap-4">
<div className="min-w-0">
<h3 className="text-base sm:text-lg font-semibold break-words">
{release.repo} — {release.version}
</h3>
<p className="text-sm text-muted-foreground break-words">
{release.summary}
</p>

<span className="text-sm text-zinc-500 whitespace-nowrap">
{release.date}
</span>
</div>
<span className="text-xs sm:text-sm text-zinc-500 whitespace-normal sm:whitespace-nowrap sm:self-start">
{release.date}
</span>

</div>

{/* Contributors */}
{release.contributors.length > 0 && (
<div className="flex flex-wrap gap-3 pt-2">
<div className="flex flex-wrap gap-2 pt-2">
{release.contributors.map((c) => (
<Link
key={c.username}
Expand Down
72 changes: 72 additions & 0 deletions components/Releases/ReleasesClient.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
"use client";

import { useState } from "react";
import { Release } from "@/lib/releases";
import { ReleaseCard } from "./ReleaseCard";

export default function ReleasesClient({
releases,
}: {
releases: Release[];
}) {
const [activeRepo, setActiveRepo] =
useState<"Mobile App" | "Vue Simulator">("Mobile App");

const filtered = releases.filter(
(r) => r.repo === activeRepo
);

return (
<div className="mt-6 space-y-6">
{/* Tabs */}
<div
role="tablist"
aria-label="Release repositories"
className="flex gap-6 border-b pb-2"
>
<button
role="tab"
aria-selected={activeRepo === "Mobile App"}
aria-controls="mobile-panel"
onClick={() => setActiveRepo("Mobile App")}
className={
activeRepo === "Mobile App"
? "font-semibold text-[#50B78B]"
: "text-zinc-500"
}
>
Mobile App
</button>

<button
role="tab"
aria-selected={activeRepo === "Vue Simulator"}
aria-controls="vue-panel"
onClick={() => setActiveRepo("Vue Simulator")}
className={
activeRepo === "Vue Simulator"
? "font-semibold text-[#50B78B]"
: "text-zinc-500"
}
>
Vue Simulator
</button>
</div>


{/* Content */}
{filtered.length === 0 ? (
<p className="text-sm text-zinc-500">
No releases yet for {activeRepo}.
</p>
) : (
filtered.map((release) => (
<ReleaseCard
key={`${release.repoSlug}-${release.version}`}
release={release}
/>
))
)}
</div>
);
}