Skip to content

Commit d199762

Browse files
authored
Use static assets instead of fetching from github (#156)
1 parent 2af11d1 commit d199762

File tree

18 files changed

+135
-106
lines changed

18 files changed

+135
-106
lines changed

frontend/public/json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../json

frontend/src/app/api/categories/route.ts

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
1-
import { basePath } from "@/config/siteConfig";
2-
import { Category, Script } from "@/lib/types";
1+
import { Metadata, Script } from "@/lib/types";
2+
import { promises as fs } from "fs";
33
import { NextResponse } from "next/server";
4+
import path from "path";
45

56
export const dynamic = "force-static";
67

7-
const fetchCategories = async (): Promise<Category[]> => {
8-
const response = await fetch(
9-
`https://raw.githubusercontent.com/community-scripts/${basePath}/refs/heads/main/json/metadata.json`,
10-
);
11-
const data = await response.json();
12-
return data.categories;
8+
const jsonDir = "public/json";
9+
const metadataFileName = "metadata.json";
10+
const encoding = "utf-8";
11+
12+
const getMetadata = async () => {
13+
const filePath = path.resolve(jsonDir, metadataFileName);
14+
const fileContent = await fs.readFile(filePath, encoding);
15+
const metadata: Metadata = JSON.parse(fileContent);
16+
return metadata;
1317
};
1418

15-
const fetchScripts = async (): Promise<Script[]> => {
16-
const response = await fetch(
17-
`https://api.github.com/repos/community-scripts/${basePath}/contents/json`,
18-
);
19-
const files: { download_url: string }[] = await response.json();
19+
const getScripts = async () => {
20+
const filePaths = (await fs.readdir(jsonDir))
21+
.filter((fileName) => fileName !== metadataFileName)
22+
.map((fileName) => path.resolve(jsonDir, fileName));
23+
2024
const scripts = await Promise.all(
21-
files.map(async (file) : Promise<Script> => {
22-
const response = await fetch(file.download_url);
23-
const script = await response.json();
25+
filePaths.map(async (filePath) => {
26+
const fileContent = await fs.readFile(filePath, encoding);
27+
const script: Script = JSON.parse(fileContent);
2428
return script;
2529
}),
2630
);
@@ -29,11 +33,18 @@ const fetchScripts = async (): Promise<Script[]> => {
2933

3034
export async function GET() {
3135
try {
32-
const categories = await fetchCategories();
33-
const scripts = await fetchScripts();
34-
for (const category of categories) {
35-
category.scripts = scripts.filter((script) => script.categories.includes(category.id));
36-
}
36+
const metadata = await getMetadata();
37+
const scripts = await getScripts();
38+
39+
const categories = metadata.categories
40+
.map((category) => {
41+
category.scripts = scripts.filter((script) =>
42+
script.categories.includes(category.id),
43+
);
44+
return category;
45+
})
46+
.sort((a, b) => a.sort_order - b.sort_order);
47+
3748
return NextResponse.json(categories);
3849
} catch (error) {
3950
console.error(error as Error);

frontend/src/app/layout.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import Footer from "@/components/Footer";
22
import Navbar from "@/components/Navbar";
33
import { ThemeProvider } from "@/components/theme-provider";
44
import { Toaster } from "@/components/ui/sonner";
5+
import { analytics, basePath } from "@/config/siteConfig";
56
import "@/styles/globals.css";
67
import { Inter } from "next/font/google";
7-
import React from "react";
88
import { NuqsAdapter } from "nuqs/adapters/next/app";
9-
import { analytics, basePath } from "@/config/siteConfig";
9+
import React from "react";
1010

1111
const inter = Inter({ subsets: ["latin"] });
1212

@@ -65,7 +65,6 @@ export default function RootLayout({
6565
data-website-id={analytics.token}
6666
></script>
6767
<link rel="manifest" href="manifest.webmanifest" />
68-
<link rel="preconnect" href={process.env.NEXT_PUBLIC_POCKETBASE_URL} />
6968
<link rel="preconnect" href="https://api.github.com" />
7069
</head>
7170
<body className={inter.className}>

frontend/src/app/page.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
"use client";
22
import AnimatedGradientText from "@/components/ui/animated-gradient-text";
3-
import Particles from "@/components/ui/particles";
43
import { Button } from "@/components/ui/button";
4+
import { CardFooter } from "@/components/ui/card";
5+
import {
6+
Dialog,
7+
DialogContent,
8+
DialogDescription,
9+
DialogHeader,
10+
DialogTitle,
11+
DialogTrigger,
12+
} from "@/components/ui/dialog";
13+
import Particles from "@/components/ui/particles";
514
import { Separator } from "@/components/ui/separator";
15+
import { basePath } from "@/config/siteConfig";
616
import { cn } from "@/lib/utils";
717
import { ArrowRightIcon, ExternalLink } from "lucide-react";
818
import { useTheme } from "next-themes";
919
import Link from "next/link";
1020
import { useEffect, useState } from "react";
11-
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
12-
import { CardFooter } from "@/components/ui/card";
1321
import { FaGithub } from "react-icons/fa";
14-
import { basePath } from "@/config/siteConfig";
1522

1623
function CustomArrowRightIcon() {
1724
return <ArrowRightIcon className="h-4 w-4" width={1} />;

frontend/src/app/scripts/_components/ScriptItem.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ function ScriptItem({
5252
<div className="ml-4 flex flex-col justify-between">
5353
<div className="flex h-full w-full flex-col justify-between">
5454
<div>
55-
<h1 className="text-lg font-semibold">{item.name} {getDisplayValueFromType(item.type)}</h1>
55+
<h1 className="text-lg font-semibold">
56+
{item.name} {getDisplayValueFromType(item.type)}
57+
</h1>
5658
<p className="w-full text-sm text-muted-foreground">
5759
Date added: {extractDate(item.date_created)}
5860
</p>

frontend/src/app/scripts/_components/ScriptItems/DefaultPassword.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
import handleCopy from "@/components/handleCopy";
12
import { Button } from "@/components/ui/button";
23
import { Separator } from "@/components/ui/separator";
3-
import handleCopy from "@/components/handleCopy";
44
import { Script } from "@/lib/types";
55

66
export default function DefaultPassword({ item }: { item: Script }) {
7-
const hasDefaultLogin = item.default_credentials.username && item.default_credentials.password;
7+
const hasDefaultLogin =
8+
item.default_credentials.username && item.default_credentials.password;
89

910
return (
1011
<div>
@@ -25,7 +26,10 @@ export default function DefaultPassword({ item }: { item: Script }) {
2526
variant={"secondary"}
2627
size={"null"}
2728
onClick={() =>
28-
handleCopy("username", item.default_credentials.username ?? "")
29+
handleCopy(
30+
"username",
31+
item.default_credentials.username ?? "",
32+
)
2933
}
3034
>
3135
{item.default_credentials.username}
@@ -37,7 +41,10 @@ export default function DefaultPassword({ item }: { item: Script }) {
3741
variant={"secondary"}
3842
size={"null"}
3943
onClick={() =>
40-
handleCopy("password", item.default_credentials.password ?? "")
44+
handleCopy(
45+
"password",
46+
item.default_credentials.password ?? "",
47+
)
4148
}
4249
>
4350
{item.default_credentials.password}

frontend/src/app/scripts/_components/ScriptItems/DefaultSettings.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ export default function DefaultSettings({ item }: { item: Script }) {
4444
CPU: {defaultAlpineSettings?.resources.cpu}vCPU
4545
</p>
4646
<p className="text-sm text-muted-foreground">
47-
RAM: {getDisplayValueFromRAM(defaultAlpineSettings?.resources.ram ?? 0)}
47+
RAM:{" "}
48+
{getDisplayValueFromRAM(defaultAlpineSettings?.resources.ram ?? 0)}
4849
</p>
4950
<p className="text-sm text-muted-foreground">
5051
HDD: {defaultAlpineSettings?.resources.hdd}GB

frontend/src/app/scripts/_components/ScriptItems/InstallCommand.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ import { getDisplayValueFromType } from "../ScriptInfoBlocks";
66

77
const getInstallCommand = (scriptPath?: string) => {
88
return `bash -c "$(wget -qLO - https://github.com/community-scripts/${basePath}/raw/main/${scriptPath})"`;
9-
}
9+
};
1010

1111
export default function InstallCommand({ item }: { item: Script }) {
1212
const alpineScript = item.install_methods.find(
1313
(method) => method.type === "alpine",
1414
);
1515

1616
const defaultScript = item.install_methods.find(
17-
(method) => method.type === "default"
17+
(method) => method.type === "default",
1818
);
1919

2020
const renderInstructions = (isAlpine = false) => (
@@ -60,7 +60,9 @@ export default function InstallCommand({ item }: { item: Script }) {
6060
</TabsList>
6161
<TabsContent value="default">
6262
{renderInstructions()}
63-
<CodeCopyButton>{getInstallCommand(defaultScript?.script)}</CodeCopyButton>
63+
<CodeCopyButton>
64+
{getInstallCommand(defaultScript?.script)}
65+
</CodeCopyButton>
6466
</TabsContent>
6567
<TabsContent value="alpine">
6668
{renderInstructions(true)}

frontend/src/app/scripts/_components/ScriptItems/InterFaces.tsx

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { Button, buttonVariants } from "@/components/ui/button";
21
import handleCopy from "@/components/handleCopy";
2+
import { buttonVariants } from "@/components/ui/button";
3+
import { Script } from "@/lib/types";
34
import { cn } from "@/lib/utils";
45
import { ClipboardIcon } from "lucide-react";
5-
import { Script } from "@/lib/types";
66

77
const CopyButton = ({
88
label,
@@ -11,7 +11,12 @@ const CopyButton = ({
1111
label: string;
1212
value: string | number;
1313
}) => (
14-
<span className={cn(buttonVariants({size: "sm", variant: "secondary"}), "flex items-center gap-2")}>
14+
<span
15+
className={cn(
16+
buttonVariants({ size: "sm", variant: "secondary" }),
17+
"flex items-center gap-2",
18+
)}
19+
>
1520
{value}
1621
<ClipboardIcon
1722
onClick={() => handleCopy(label, String(value))}
@@ -20,19 +25,15 @@ const CopyButton = ({
2025
</span>
2126
);
2227

23-
export default function InterFaces({item} : {item : Script}) {
24-
28+
export default function InterFaces({ item }: { item: Script }) {
2529
return (
2630
<div className="flex flex-col gap-2">
2731
{item.interface_port !== null ? (
2832
<div className="flex items-center justify-end">
2933
<h2 className="mr-2 text-end text-lg font-semibold">
3034
{"Default Interface:"}
3135
</h2>{" "}
32-
<CopyButton
33-
label="default interface"
34-
value={item.interface_port}
35-
/>
36+
<CopyButton label="default interface" value={item.interface_port} />
3637
</div>
3738
) : null}
3839
</div>

frontend/src/app/scripts/_components/Sidebar.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,16 @@ const Sidebar = ({
1717
<div className="flex items-end justify-between pb-4">
1818
<h1 className="text-xl font-bold">Categories</h1>
1919
<p className="text-xs italic text-muted-foreground">
20-
{items.reduce(
21-
(acc, category) => acc + category.scripts.length,
22-
0,
23-
)}{" "}
20+
{items.reduce((acc, category) => acc + category.scripts.length, 0)}{" "}
2421
Total scripts
2522
</p>
2623
</div>
2724
<div className="rounded-lg">
28-
<ScriptAccordion items={items} selectedScript={selectedScript} setSelectedScript={setSelectedScript} />
25+
<ScriptAccordion
26+
items={items}
27+
selectedScript={selectedScript}
28+
setSelectedScript={setSelectedScript}
29+
/>
2930
</div>
3031
</div>
3132
);

0 commit comments

Comments
 (0)