2025-07-14 23:07:09 +00:00
|
|
|
import { Suspense } from "react";
|
|
|
|
|
import { getBrowseParamsFromPathParam } from "../hooks/utils";
|
2025-06-06 19:38:16 +00:00
|
|
|
import { CodePreviewPanel } from "./components/codePreviewPanel";
|
2025-07-14 23:07:09 +00:00
|
|
|
import { Loader2 } from "lucide-react";
|
2025-06-06 19:38:16 +00:00
|
|
|
import { TreePreviewPanel } from "./components/treePreviewPanel";
|
2025-10-15 18:44:30 +00:00
|
|
|
import { Metadata } from "next";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Parses the URL path to generate a descriptive title.
|
|
|
|
|
* It handles three cases:
|
|
|
|
|
* 1. File view (`blob`): "filename.ts - owner/repo"
|
|
|
|
|
* 2. Directory view (`tree`): "directory/ - owner/repo"
|
|
|
|
|
* 3. Repository root: "owner/repo"
|
|
|
|
|
*
|
|
|
|
|
* @param path The array of path segments from Next.js params.
|
|
|
|
|
* @returns A formatted title string.
|
|
|
|
|
*/
|
|
|
|
|
const parsePathForTitle = (path: string[]): string => {
|
|
|
|
|
const pathParam = path.join('/');
|
|
|
|
|
|
|
|
|
|
const { repoName, revisionName, path: filePath, pathType } = getBrowseParamsFromPathParam(pathParam);
|
|
|
|
|
|
|
|
|
|
// Build the base repository and revision string.
|
|
|
|
|
const cleanRepoName = repoName.split('/').slice(1).join('/'); // Remove the version control system prefix
|
|
|
|
|
const repoAndRevision = `${cleanRepoName}${revisionName ? ` @ ${revisionName}` : ''}`;
|
|
|
|
|
|
|
|
|
|
switch (pathType) {
|
|
|
|
|
case 'blob': {
|
|
|
|
|
// For blobs, get the filename from the end of the path.
|
|
|
|
|
const fileName = filePath.split('/').pop() || filePath;
|
|
|
|
|
return `${fileName} - ${repoAndRevision}`;
|
|
|
|
|
}
|
|
|
|
|
case 'tree': {
|
|
|
|
|
// If the path is empty, it's the repo root.
|
|
|
|
|
if (filePath === '' || filePath === '/') {
|
|
|
|
|
return repoAndRevision;
|
|
|
|
|
}
|
|
|
|
|
// Otherwise, show the directory path.
|
|
|
|
|
const directoryPath = filePath.endsWith('/') ? filePath : `${filePath}/`;
|
|
|
|
|
return `${directoryPath} - ${repoAndRevision}`;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Props = {
|
|
|
|
|
params: Promise<{
|
|
|
|
|
domain: string;
|
|
|
|
|
path: string[];
|
|
|
|
|
}>;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export async function generateMetadata({ params: paramsPromise }: Props): Promise<Metadata> {
|
|
|
|
|
let title = 'Browse'; // Default Fallback
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const params = await paramsPromise;
|
|
|
|
|
title = parsePathForTitle(params.path);
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Failed to generate metadata title from path:", error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
title,
|
|
|
|
|
};
|
|
|
|
|
}
|
2025-05-28 23:08:42 +00:00
|
|
|
|
2025-07-14 23:07:09 +00:00
|
|
|
interface BrowsePageProps {
|
2025-08-22 18:48:29 +00:00
|
|
|
params: Promise<{
|
2025-07-14 23:07:09 +00:00
|
|
|
path: string[];
|
2025-08-22 18:48:29 +00:00
|
|
|
}>;
|
2025-07-14 23:07:09 +00:00
|
|
|
}
|
|
|
|
|
|
2025-08-22 18:48:29 +00:00
|
|
|
export default async function BrowsePage(props: BrowsePageProps) {
|
|
|
|
|
const params = await props.params;
|
|
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
path: _rawPath,
|
|
|
|
|
} = params;
|
|
|
|
|
|
2025-09-01 15:45:05 +00:00
|
|
|
const rawPath = _rawPath.join('/');
|
2025-07-14 23:07:09 +00:00
|
|
|
const { repoName, revisionName, path, pathType } = getBrowseParamsFromPathParam(rawPath);
|
|
|
|
|
|
2025-01-07 18:27:42 +00:00
|
|
|
return (
|
2025-06-06 19:38:16 +00:00
|
|
|
<div className="flex flex-col h-full">
|
2025-07-14 23:07:09 +00:00
|
|
|
<Suspense fallback={
|
|
|
|
|
<div className="flex flex-col w-full min-h-full items-center justify-center">
|
|
|
|
|
<Loader2 className="w-4 h-4 animate-spin" />
|
|
|
|
|
Loading...
|
|
|
|
|
</div>
|
|
|
|
|
}>
|
|
|
|
|
{pathType === 'blob' ? (
|
|
|
|
|
<CodePreviewPanel
|
|
|
|
|
path={path}
|
|
|
|
|
repoName={repoName}
|
|
|
|
|
revisionName={revisionName}
|
|
|
|
|
/>
|
|
|
|
|
) : (
|
|
|
|
|
<TreePreviewPanel
|
|
|
|
|
path={path}
|
|
|
|
|
repoName={repoName}
|
|
|
|
|
revisionName={revisionName}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</Suspense>
|
2025-06-06 19:38:16 +00:00
|
|
|
</div>
|
2025-01-07 18:27:42 +00:00
|
|
|
)
|
2025-05-28 23:08:42 +00:00
|
|
|
}
|
2025-06-06 19:38:16 +00:00
|
|
|
|