This commit is contained in:
Michel Roegl-Brunner 2025-03-18 16:02:29 +01:00
parent 9e7f276d95
commit 5ba9c81efc
3 changed files with 99 additions and 86 deletions

View File

@ -57,6 +57,7 @@ function ScriptItem({
const os = defaultInstallMethod?.resources?.os || "Proxmox Node"; const os = defaultInstallMethod?.resources?.os || "Proxmox Node";
const version = defaultInstallMethod?.resources?.version || ""; const version = defaultInstallMethod?.resources?.version || "";
const [linksVisible, setLinksVisible] = useState<boolean>(false);
return ( return (
<div className="mr-7 mt-0 flex w-full min-w-fit"> <div className="mr-7 mt-0 flex w-full min-w-fit">
@ -82,7 +83,7 @@ function ScriptItem({
unoptimized unoptimized
/> />
<div className="ml-4 flex flex-col justify-between"> <div className="ml-4 flex flex-col justify-between">
<div className="flex h-full w-full flex-col justify-between"> <div className="flex h-full w-full flex-col mb-4">
<div> <div>
<h1 className="text-lg font-semibold"> <h1 className="text-lg font-semibold">
{item.name} {getDisplayValueFromType(item.type)} {item.name} {getDisplayValueFromType(item.type)}
@ -126,10 +127,20 @@ function ScriptItem({
<div className="flex flex-col items-end gap-4 ml-auto"> <div className="flex flex-col items-end gap-4 ml-auto">
<DefaultSettings item={item} /> <DefaultSettings item={item} />
<InterFaces item={item} /> <InterFaces item={item} />
<Buttons item={item} /> <div>
<>
<button
onClick={() => setLinksVisible(!linksVisible)}
className="flex items-right justify-right gap-1 mb-2 rounded-md border border-accent bg-accent/20 px-2 py-1 text-l hover:bg-accent w-30"
>
Show Links {linksVisible ? '▲' : '▼'}
</button>
{linksVisible && <Buttons item={item} />}
</>
</div>
</div> </div>
</div> </div>
<Separator className="mt-4" />
<div> <div>
<div className="mt-4"> <div className="mt-4">
<Description item={item} /> <Description item={item} />

View File

@ -5,77 +5,78 @@ import { BookOpenText, Code, Globe, RefreshCcw } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
const generateInstallSourceUrl = (slug: string) => { const generateInstallSourceUrl = (slug: string) => {
const baseUrl = `https://raw.githubusercontent.com/community-scripts/${basePath}/main`; const baseUrl = `https://raw.githubusercontent.com/community-scripts/${basePath}/main`;
return `${baseUrl}/install/${slug}-install.sh`; return `${baseUrl}/install/${slug}-install.sh`;
}; };
const generateSourceUrl = (slug: string, type: string) => { const generateSourceUrl = (slug: string, type: string) => {
const baseUrl = `https://raw.githubusercontent.com/community-scripts/${basePath}/main`; const baseUrl = `https://raw.githubusercontent.com/community-scripts/${basePath}/main`;
return type === "vm" ? `${baseUrl}/vm/${slug}.sh` : `${baseUrl}/misc/${slug}.sh`; return type === "vm" ? `${baseUrl}/vm/${slug}.sh` : `${baseUrl}/misc/${slug}.sh`;
return `${baseUrl}/misc/${slug}.sh`; return `${baseUrl}/misc/${slug}.sh`;
}; };
const generateUpdateUrl = (slug: string) => { const generateUpdateUrl = (slug: string) => {
const baseUrl = `https://raw.githubusercontent.com/community-scripts/${basePath}/main`; const baseUrl = `https://raw.githubusercontent.com/community-scripts/${basePath}/main`;
return `${baseUrl}/ct/${slug}.sh`; return `${baseUrl}/ct/${slug}.sh`;
}; };
interface ButtonLinkProps { interface ButtonLinkProps {
href: string; href: string;
icon: React.ReactNode; icon: React.ReactNode;
text: string; text: string;
} }
const ButtonLink = ({ href, icon, text }: ButtonLinkProps) => ( const ButtonLink = ({ href, icon, text }: ButtonLinkProps) => (
<Button variant="secondary" asChild> <Button variant="secondary" asChild>
<Link target="_blank" href={href}> <Link target="_blank" href={href}>
<span className="flex items-center gap-2"> <span className="flex items-center gap-2">
{icon} {icon}
{text} {text}
</span> </span>
</Link> </Link>
</Button> </Button>
); );
export default function Buttons({ item }: { item: Script }) { export default function Buttons({ item }: { item: Script }) {
const isCtOrDefault = ["ct"].includes(item.type); const isCtOrDefault = ["ct"].includes(item.type);
const installSourceUrl = isCtOrDefault ? generateInstallSourceUrl(item.slug) : null; const installSourceUrl = isCtOrDefault ? generateInstallSourceUrl(item.slug) : null;
const updateSourceUrl = isCtOrDefault ? generateUpdateUrl(item.slug) : null; const updateSourceUrl = isCtOrDefault ? generateUpdateUrl(item.slug) : null;
const sourceUrl = !isCtOrDefault ? generateSourceUrl(item.slug, item.type) : null; const sourceUrl = !isCtOrDefault ? generateSourceUrl(item.slug, item.type) : null;
const buttons = [ const buttons = [
item.website && { item.website && {
href: item.website, href: item.website,
icon: <Globe className="h-4 w-4" />, icon: <Globe className="h-4 w-4" />,
text: "Website", text: "Website",
}, },
item.documentation && { item.documentation && {
href: item.documentation, href: item.documentation,
icon: <BookOpenText className="h-4 w-4" />, icon: <BookOpenText className="h-4 w-4" />,
text: "Documentation", text: "Documentation",
}, },
installSourceUrl && { installSourceUrl && {
href: installSourceUrl, href: installSourceUrl,
icon: <Code className="h-4 w-4" />, icon: <Code className="h-4 w-4" />,
text: "Install-Source", text: "Install-Source",
}, },
updateSourceUrl && { updateSourceUrl && {
href: updateSourceUrl, href: updateSourceUrl,
icon: <RefreshCcw className="h-4 w-4" />, icon: <RefreshCcw className="h-4 w-4" />,
text: "Update-Source", text: "Update-Source",
}, },
sourceUrl && { sourceUrl && {
href: sourceUrl, href: sourceUrl,
icon: <Code className="h-4 w-4" />, icon: <Code className="h-4 w-4" />,
text: "Source Code", text: "Source Code",
}, },
].filter(Boolean) as ButtonLinkProps[]; ].filter(Boolean) as ButtonLinkProps[];
return ( return (
<div className="flex flex-wrap justify-end gap-2">
{buttons.map((props, index) => ( <div className="flex flex-wrap justify-end gap-2">
<ButtonLink key={index} {...props} /> {buttons.map((props, index) => (
))} <ButtonLink key={index} {...props} />
</div> ))}
); </div>
);
} }

View File

@ -5,37 +5,38 @@ import { cn } from "@/lib/utils";
import { ClipboardIcon } from "lucide-react"; import { ClipboardIcon } from "lucide-react";
const CopyButton = ({ const CopyButton = ({
label, label,
value, value,
}: { }: {
label: string; label: string;
value: string | number; value: string | number;
}) => ( }) => (
<span <span
className={cn( className={cn(
buttonVariants({ size: "sm", variant: "secondary" }), buttonVariants({ size: "sm", variant: "secondary" }),
"flex items-center gap-2", "flex items-center gap-2",
)} )}
> >
{value} {value}
<ClipboardIcon <ClipboardIcon
onClick={() => handleCopy(label, String(value))} onClick={() => handleCopy(label, String(value))}
className="size-4 cursor-pointer" className="size-4 cursor-pointer"
/> />
</span> </span>
); );
export default function InterFaces({ item }: { item: Script }) { export default function InterFaces({ item }: { item: Script }) {
return ( return (
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
{item.interface_port !== null ? ( {item.interface_port !== null ? (
<div className="flex items-center justify-end"> <div className="flex items-center justify-end">
<h2 className="mr-2 text-end text-lg font-semibold"> <h2 className="mr-2 text-end text-l font-semibold">
{"Default Interface:"} {"Default Interface:"}
</h2>{" "} </h2>{" "}
<CopyButton label="default interface" value={item.interface_port} />
<CopyButton label="default interface" value={item.interface_port} />
</div>
) : null}
</div> </div>
) : null} );
</div>
);
} }