diff --git a/app/new/page.tsx b/app/new/page.tsx new file mode 100644 index 0000000..234eebf --- /dev/null +++ b/app/new/page.tsx @@ -0,0 +1,377 @@ +"use client"; +import { pb } from "@/lib/pocketbase"; +import Image from "next/image"; +import React, { useEffect, useState } from "react"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { Clipboard, Info } from "lucide-react"; +import { Separator } from "@/components/ui/separator"; +import { Button } from "@/components/ui/button"; +import Link from "next/link"; +import { extractDate } from "@/lib/time"; +import { toast } from "sonner"; + + +interface Script { + title: string; + scriptID: string; +} + +interface Category { + id: string; + Catagory_Title: string; + Items: Script[]; +} + +type Scripts = { + id: string; + title: string; + description: string; + installCommand: string; + logo: string; + updated: string; + created: string; + default_cpu: string; + default_ram: string; + default_hdd: string; + port: number; + item_type: string; + website: string; + documentation: string; + isUpdateable: boolean; + post_install: string; + hasAlpineScript: boolean; + alpineScript: string; + alpine_default_cpu: string; + alpine_default_ram: string; + alpine_default_hdd: string; + alert1: string; + alert2: string; + alert3: string; +}; + +const getCatagories = async () => { + const res = await fetch( + `${process.env.NEXT_PUBLIC_POCKETBASE_URL}/api/collections/proxmox_items/records`, + ); + const data = await res.json(); + return data.items as Category[]; +}; + +const getItems = async () => { + const records = await pb.collection("proxmox_scripts").getFullList({ + sort: "-created", + }); + return records as unknown as Scripts[]; +}; + + function handleCopy(type: string, value: any) { + navigator.clipboard.writeText(value); + toast( +
+ + Copied {type} to clipboard +
, + ); + } + + +function page() { + const [selectedItem, setSelectedItem] = useState(""); + const [categories, setCategories] = useState([]); + const [items, setItems] = useState([]); + + useEffect(() => { + const fetchdata = async () => { + try { + const categories = await getCatagories(); + const items = await getItems(); + setCategories(categories); + setItems(items); + } catch (error) { + console.error("Error fetching links:", error); + } + }; + fetchdata(); + }, []); + + return ( +
+ {categories.map((category: Category) => ( +
+

+ {category.Catagory_Title} +

{" "} +
+ {category.Items.map((script: Script) => { + const item = items.find((item) => item.id === script.scriptID); + if (item) { + return ( + + +
setSelectedItem(item.id)} + > +
+
+ {item.title} +
+
+

+ {item.title} +

+
+
+
+
+ + + +
+ {item && ( + <> +
+
+
+ {item.title} +
+
+
+

+ {item.title} +

+

+ Date added:{" "} + {extractDate(item.created)} +

+
+
+ {item.default_cpu && ( +
+

+ Default settings +

+

+ CPU: {item.default_cpu} +

+

+ RAM: {item.default_ram} +

+

+ HDD: {item.default_hdd} +

+
+ )} + {item.hasAlpineScript && ( +
+

+ Default Alpine settings +

+

+ CPU: {item.alpine_default_cpu} +

+

+ RAM: {item.alpine_default_ram} +

+

+ HDD: {item.alpine_default_hdd} +

+
+ )} +
+
+
+
+
+ {item.website && ( + + )} + {item.documentation && ( + + )} +
+
+ +
+
+

+ Description +

+

{item.description}

+ + {item.alert1 && ( +
+

+ + {item.alert1} +

+ {item.alert2 && ( +

+ + {item.alert2} +

+ )} + {item.alert3 && ( +

+ + {item.alert3} +

+ )} +
+ )} +
+ +
+

+ How to{" "} + {item.item_type ? "install" : "use"} +

+ {item.item_type && ( + <> +

+ To create a new Proxmox VE{" "} + {item.title} {item.item_type}, run + the command below in the Proxmox VE + Shell. +

+ {item.isUpdateable && ( +

+ To Update {item.title}, run the + command below (or type update) in + the LXC Console. +

+ )} + + )} + +

+ click to copy +

+ + + {item.hasAlpineScript && ( + <> + + +

+ Alpine Linux +

+

+ As an alternative option, you can + use Alpine Linux and the{" "} + {item.title} package to create a{" "} + {item.title} {item.item_type}{" "} + container with faster creation time + and minimal system resource usage. +

+ +

+ To create a new Proxmox VE Alpine- + {item.title} {item.item_type}, run + the command below in the{" "} + + Proxmox VE Shell + +

+ +

+ click to copy +

+ + + )} +
+ {item.port != 0 && ( +
+

+ Default Port +

+

+ click to copy +

+ +
+ )} +
+
+ + )} +
+
+
+
+
+ ); + } + return null; + })} +
+
+ ))} +
+ ); +} + +export default page; diff --git a/bun.lockb b/bun.lockb index da7a422..486020a 100644 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/components/ui/dialog.tsx b/components/ui/dialog.tsx new file mode 100644 index 0000000..00ac307 --- /dev/null +++ b/components/ui/dialog.tsx @@ -0,0 +1,122 @@ +"use client" + +import * as React from "react" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { X } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Dialog = DialogPrimitive.Root + +const DialogTrigger = DialogPrimitive.Trigger + +const DialogPortal = DialogPrimitive.Portal + +const DialogClose = DialogPrimitive.Close + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)) +DialogContent.displayName = DialogPrimitive.Content.displayName + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogHeader.displayName = "DialogHeader" + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogFooter.displayName = "DialogFooter" + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogTitle.displayName = DialogPrimitive.Title.displayName + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogDescription.displayName = DialogPrimitive.Description.displayName + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogClose, + DialogTrigger, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +} diff --git a/package.json b/package.json index 6a731a5..e1740e6 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "@radix-ui/react-accordion": "^1.1.2", + "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-navigation-menu": "^1.1.4", "@radix-ui/react-separator": "^1.0.3",