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
34 changes: 10 additions & 24 deletions apps/landing-page/src/app/(home)/download/page.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@
import { Avatar, Tabs } from '@skeletonlabs/skeleton-react';
import { DownloadIcon, MonitorIcon, TerminalIcon } from 'lucide-react';
import { useState } from 'react';
import type { Octokit } from 'octokit';

type OctokitRelease = Awaited<
ReturnType<Octokit['rest']['repos']['listReleases']>
>['data'][number];
import type { GithubRelease, GithubAsset } from './types';

export default function DownloadView({
releases,
}: {
releases: OctokitRelease[];
releases: GithubRelease[];
}) {
const [tabOS, setTabOS] = useState('windows');
const [selectedReleaseIndex, setSelectedReleaseIndex] = useState(0);
Expand All @@ -23,7 +19,7 @@ export default function DownloadView({

const release = releases[selectedReleaseIndex];

const assets = release.assets ?? [];
const assets = release.releaseAssets?.nodes ?? [];
const windows = assets.filter((a) =>
a.name.toLowerCase().includes('windows'),
);
Expand Down Expand Up @@ -72,7 +68,7 @@ export default function DownloadView({
>
{releases.map((rel, index) => (
<option key={rel.id} value={index}>
{rel.name ?? rel.tag_name ?? `#${rel.id}`}
{rel.name ?? rel.tagName ?? `#${rel.id}`}
</option>
))}
</select>
Expand All @@ -81,7 +77,7 @@ export default function DownloadView({
<div className="mt-4 flex items-center justify-center gap-4 text-surface-800-200">
<Avatar className="size-10">
<Avatar.Image
src={release.author?.avatar_url ?? ''}
src={release.author?.avatarUrl ?? ''}
alt={release.author?.login ?? 'author'}
/>
<Avatar.Fallback>
Expand All @@ -96,9 +92,9 @@ export default function DownloadView({
</span>
<span className="opacity-60">
Published on{' '}
{release.published_at
{release.publishedAt
? new Date(
release.published_at,
release.publishedAt,
).toLocaleDateString()
: 'Unknown'}
</span>
Expand Down Expand Up @@ -157,17 +153,7 @@ export default function DownloadView({
);
}

function AssetGrid({
assets,
}: {
assets: {
id: number;
name: string;
size: number;
download_count: number;
browser_download_url: string;
}[];
}) {
function AssetGrid({ assets }: { assets: GithubAsset[] }) {
if (!assets || assets.length === 0) {
return (
<div className="card preset-filled-surface-100-900 mx-auto flex max-w-xl flex-col items-center justify-center p-12 text-center opacity-70">
Expand All @@ -191,12 +177,12 @@ function AssetGrid({
{(asset.size / 1024 / 1024).toFixed(2)} MB
</span>
<span className="badge preset-tonal-surface rounded-lg py-1 text-xs">
{asset.download_count} Downloads
{asset.downloadCount} Downloads
</span>
</div>
</div>
<a
href={asset.browser_download_url}
href={asset.downloadUrl}
className="btn preset-filled w-full font-bold"
>
<DownloadIcon className="mr-2 size-4" /> Download
Expand Down
54 changes: 39 additions & 15 deletions apps/landing-page/src/app/(home)/download/page.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,49 @@
import { AlertTriangle } from 'lucide-react';
import DownloadView from './page.client';
import { RequestError } from 'octokit';
import type { Octokit } from 'octokit';
import { octokit } from '@/server/providers/octokit.server';

type OctokitRelease = Awaited<
ReturnType<Octokit['rest']['repos']['listReleases']>
>['data'][number];
import type { GithubRelease } from './types';

export default async function DownloadPage() {
let allReleases: OctokitRelease[] = [];
let allReleases: GithubRelease[] = [];
try {
const octokitReleases = await octokit.paginate(
octokit.rest.repos.listReleases,
{
owner: 'chithi-dev',
repo: 'chithi',
per_page: 100,
},
);
allReleases = octokitReleases as OctokitRelease[];
const data = await octokit.graphql<{
repository: {
releases: {
nodes: GithubRelease[];
};
};
}>(`
query {
repository(owner: "chithi-dev", name: "chithi") {
releases(first: 100, orderBy: {field: CREATED_AT, direction: DESC}) {
nodes {
id
name
tagName
publishedAt
author {
login
avatarUrl
}
releaseAssets(first: 100) {
nodes {
id
name
size
downloadCount
downloadUrl
}
}
}
}
}
}
`);

if (data?.repository?.releases?.nodes) {
allReleases = data.repository.releases.nodes;
}
} catch (error: unknown) {
const isRateLimited =
error instanceof RequestError && error.status === 403;
Expand Down
24 changes: 14 additions & 10 deletions apps/landing-page/src/app/(home)/download/types.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
// Define minimal types for the GitHub Release and Assets
export type Asset = {
id: number;
export type GithubAsset = {
id: string;
name: string;
size: number;
download_count: number;
browser_download_url: string;
downloadCount: number;
downloadUrl: string;
};

export type Release = {
id: number;
export type GithubRelease = {
id: string;
name: string;
tagName: string;
published_at: string;
author: { login: string; avatar_url: string };
assets: Asset[];
publishedAt: string;
author: {
login: string;
avatarUrl: string;
};
releaseAssets: {
nodes: GithubAsset[];
};
};
31 changes: 15 additions & 16 deletions apps/landing-page/src/app/(home)/layout.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,20 @@ import Image from 'next/image';
import Link from 'next/link';
import { GithubIcon as Github } from '@/icons/github';
import { Star, GitBranch } from 'lucide-react';
import type { Octokit } from 'octokit';

type OctokitRelease = Awaited<
ReturnType<Octokit['rest']['repos']['getLatestRelease']>
>['data'];
type OctokitRepo = Awaited<ReturnType<Octokit['rest']['repos']['get']>>['data'];
type GithubRepoData = {
stargazerCount: number;
forkCount: number;
latestRelease: {
tagName: string;
} | null;
} | null;

type Props = {
release?: OctokitRelease | null;
repo?: OctokitRepo | null;
repo?: GithubRepoData;
};

export function Navbar({ release, repo }: Props) {
export function Navbar({ repo }: Props) {
return (
<div className="sticky top-0 z-50 border-surface-200-800/50 border-b bg-transparent backdrop-blur-md">
<AppBar className="mx-auto w-full max-w-7xl bg-transparent">
Expand All @@ -43,9 +44,9 @@ export function Navbar({ release, repo }: Props) {
className="btn btn-sm hover:preset-tonal flex items-center gap-2 rounded-full border border-surface-200-800 px-4 transition-colors"
>
<Github size={16} />
{release?.tag_name && (
{repo?.latestRelease?.tagName && (
<span className="opacity-50">
{release.tag_name}
{repo.latestRelease.tagName}
</span>
)}
</a>
Expand All @@ -55,7 +56,7 @@ export function Navbar({ release, repo }: Props) {
>
<Star size={14} />
<span className="opacity-60 text-sm">
{repo?.stargazers_count ?? 0}
{repo?.stargazerCount ?? 0}
</span>
</a>

Expand All @@ -65,7 +66,7 @@ export function Navbar({ release, repo }: Props) {
>
<GitBranch size={14} />
<span className="opacity-60 text-sm">
{repo?.forks_count ?? 0}
{repo?.forkCount ?? 0}
</span>
</a>
</AppBar.Trail>
Expand Down Expand Up @@ -109,16 +110,14 @@ export function Footer() {

export default function HomeLayoutClient({
children,
release,
repo = null,
}: Readonly<{
children: React.ReactNode;
release?: OctokitRelease | null;
repo?: OctokitRepo | null;
repo?: GithubRepoData | null;
}>) {
return (
<div className="min-h-screen overflow-x-hidden font-sans text-surface-900-100">
<Navbar release={release} repo={repo} />
<Navbar repo={repo} />
{children}
<Footer />
</div>
Expand Down
53 changes: 22 additions & 31 deletions apps/landing-page/src/app/(home)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,35 @@ export default async function HomeLayout({
children: React.ReactNode;
}>) {
// Inline concurrent fetch of latest release and repo data
let release = null;
let repoData = null;

try {
const releasePromise = octokit.rest.repos.getLatestRelease({
owner: 'chithi-dev',
repo: 'chithi',
});
const data = await octokit.graphql<{
repository: {
stargazerCount: number;
forkCount: number;
latestRelease: {
tagName: string;
} | null;
};
}>(`
query {
repository(owner: "chithi-dev", name: "chithi") {
stargazerCount
forkCount
latestRelease {
tagName
}
}
}
`);

const repoPromise = octokit.rest.repos.get({
owner: 'chithi-dev',
repo: 'chithi',
});

const [releaseRes, repoRes] = await Promise.allSettled([
releasePromise,
repoPromise,
]);

if (releaseRes.status === 'fulfilled') {
release = releaseRes.value.data;
} else {
// Not fatal: repository may have no releases or request may fail
console.warn('getLatestRelease failed', releaseRes.reason);
}

if (repoRes.status === 'fulfilled') {
repoData = repoRes.value.data;
} else {
console.error('Failed to fetch repository data', repoRes.reason);
if (data?.repository) {
repoData = data.repository;
}
} catch (err) {
console.error('Unexpected error fetching GitHub data', err);
}

return (
<HomeLayoutClient release={release} repo={repoData}>
{children}
</HomeLayoutClient>
);
return <HomeLayoutClient repo={repoData}>{children}</HomeLayoutClient>;
}
Loading