Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: redirect url #7

Merged
merged 1 commit into from
Sep 8, 2024
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
9 changes: 0 additions & 9 deletions src/app/[owner]/[repo]/loading.tsx

This file was deleted.

47 changes: 37 additions & 10 deletions src/app/[owner]/[repo]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
import { Suspense } from "react";
import type { Metadata } from "next";
import { redirect } from "next/navigation";
import { Loader } from "lucide-react";
import { createSearchParamsCache, parseAsBoolean } from "nuqs/server";

import { Controls } from "~/components/controls/controls";
import { Header } from "~/components/header";
import { CONTROLS_SEARCH_PARAMS } from "~/lib/params/controls.params";
import { RepoPreview } from "./_components/repo-preview";

type Params = {
owner: string;
repo: string;
};
type Params = { owner: string; repo: string };

type SearchParams = Record<string, string | string[] | undefined>;

const searchParamsCache = createSearchParamsCache({
redirect: parseAsBoolean.withDefault(false),
});

export async function generateMetadata({
params,
searchParams,
}: {
params: Params;
searchParams: Record<string, string | string[] | undefined>;
searchParams: SearchParams;
}) {
const theme = CONTROLS_SEARCH_PARAMS.theme.parseServerSide(
searchParams.theme,
Expand All @@ -35,11 +43,30 @@ export async function generateMetadata({
} satisfies Metadata;
}

export default function Page({ params }: { params: Params }) {
export default function Page({
params,
searchParams,
}: {
params: Params;
searchParams: SearchParams;
}) {
const { redirect: shouldRedirect } = searchParamsCache.parse(searchParams);

if (shouldRedirect) {
redirect(`https://github.com/${params.owner}/${params.repo}`);
}

return (
<main className="flex min-h-dvh items-center justify-center bg-background">
<Controls />
<RepoPreview owner={params.owner} repo={params.repo} />
</main>
<>
<Header />
<main className="flex min-h-dvh items-center justify-center">
<Suspense
fallback={<Loader className="animate-spin text-muted-foreground" />}
>
<Controls />
<RepoPreview owner={params.owner} repo={params.repo} />
</Suspense>
</main>
</>
);
}
2 changes: 0 additions & 2 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Inter } from "next/font/google";
import { Analytics } from "@vercel/analytics/react";
import { ThemeProvider } from "next-themes";

import { Header } from "~/components/header";
import { Toaster } from "~/components/ui/sonner";
import { TooltipProvider } from "~/components/ui/tooltip";

Expand Down Expand Up @@ -33,7 +32,6 @@ export default function RootLayout({
<body className={inter.className}>
<Analytics />
<ThemeProvider attribute="class" defaultTheme="dark">
<Header />
<Toaster />
<TooltipProvider>{children}</TooltipProvider>
</ThemeProvider>
Expand Down
20 changes: 12 additions & 8 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import { Header } from "~/components/header";
import { SearchForm } from "./_components/search-form";
import { SuggestedRepos } from "./_components/suggested-repos";

export default function Page() {
return (
<main className="flex min-h-dvh flex-col items-center justify-center px-6">
<h1 className="text-3xl font-semibold sm:text-4xl">gnip</h1>
<p className="mb-8 mt-3.5 text-sm text-muted-foreground">
Create snippets for your GitHub repositories.
</p>
<SearchForm />
<SuggestedRepos />
</main>
<>
<Header />
<main className="flex min-h-dvh flex-col items-center justify-center px-6">
<h1 className="text-3xl font-semibold sm:text-4xl">gnip</h1>
<p className="mb-8 mt-3.5 text-sm text-muted-foreground">
Create snippets for your GitHub repositories.
</p>
<SearchForm />
<SuggestedRepos />
</main>
</>
);
}
7 changes: 5 additions & 2 deletions src/components/controls/controls-download.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
"use client";

import { useParams } from "next/navigation";
import { ChevronDown, Download } from "lucide-react";
import { toast } from "sonner";
import { z } from "zod";

import { EXPORT_SIZES } from "~/lib/const/export-size.const";
import { download } from "~/lib/download";
import { toBlob, toPng, toSvg } from "~/lib/image";
import { useControls } from "~/lib/params/controls.params";
import { useZodParams } from "~/lib/use-zod-params";
import { Button } from "../ui/button";
import {
DropdownMenu,
Expand All @@ -23,8 +24,10 @@ import {
} from "../ui/dropdown-menu";
import { Tooltip } from "../ui/tooltip";

const paramsSchema = z.object({ repo: z.string() });

export function ControlsDownload() {
const params = useParams();
const params = useZodParams(paramsSchema.shape);

const [{ size }, setControls] = useControls();

Expand Down
34 changes: 34 additions & 0 deletions src/components/controls/controls-url.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"use client";

import { Link } from "lucide-react";
import { toast } from "sonner";
import { z } from "zod";

import { useZodParams } from "~/lib/use-zod-params";
import { Button } from "../ui/button";
import { Tooltip } from "../ui/tooltip";

const paramsSchema = z.object({ owner: z.string(), repo: z.string() });

export function ControlsUrl() {
const params = useZodParams(paramsSchema.shape);

function copyRedirectUrl() {
const url = `${window.location.origin}/${params.owner}/${params.repo}?redirect=true`;
navigator.clipboard.writeText(url);
toast.success("Redirect URL copied to clipboard");
}

return (
<Tooltip content="Copy Redirect URL">
<Button
size="icon"
variant="ghost"
className="size-6 shrink-0"
onClick={copyRedirectUrl}
>
<Link size={15} />
</Button>
</Tooltip>
);
}
6 changes: 5 additions & 1 deletion src/components/controls/controls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ControlsDarkMode } from "./controls-dark-mode";
import { ControlsDownload } from "./controls-download";
import { ControlsPadding } from "./controls-padding";
import { ControlsTheme } from "./controls-theme";
import { ControlsUrl } from "./controls-url";

export function Controls() {
return (
Expand All @@ -18,7 +19,10 @@ export function Controls() {
<Separator orientation="vertical" className="mx-2 h-5" />
<ControlsPadding />
<Separator orientation="vertical" className="mx-2 h-5" />
<ControlsDownload />
<div className="flex items-center gap-1">
<ControlsUrl />
<ControlsDownload />
</div>
</div>
);
}
7 changes: 7 additions & 0 deletions src/lib/use-zod-params.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { useParams } from "next/navigation";
import { z } from "zod";

export const useZodParams = <T extends z.ZodRawShape>(schema: T) => {
const params = useParams();
return z.object(schema).parse(params);
};