1
0
mirror of https://github.com/community-scripts/ProxmoxVE.git synced 2025-04-30 12:03:07 +00:00

Feat: Random Script picker for Website (#4090)

* Feat: Random Script picker

* Remove extra site

* Changes for Mick
This commit is contained in:
Michel Roegl-Brunner 2025-04-29 11:11:59 +02:00 committed by GitHub
parent 57e5f23c72
commit a2fdb4e236
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 67 additions and 18 deletions

View File

@ -8,7 +8,7 @@ import {
} from "@/components/ui/command"; } from "@/components/ui/command";
import { basePath } from "@/config/siteConfig"; import { basePath } from "@/config/siteConfig";
import { fetchCategories } from "@/lib/data"; import { fetchCategories } from "@/lib/data";
import { Category } from "@/lib/types"; import { Category, Script } from "@/lib/types";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import Image from "next/image"; import Image from "next/image";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
@ -16,6 +16,7 @@ import React from "react";
import { Badge } from "./ui/badge"; import { Badge } from "./ui/badge";
import { Button } from "./ui/button"; import { Button } from "./ui/button";
import { DialogTitle } from "./ui/dialog"; import { DialogTitle } from "./ui/dialog";
import { Sparkles } from "lucide-react"; // <- Hinzugefügt
export const formattedBadge = (type: string) => { export const formattedBadge = (type: string) => {
switch (type) { switch (type) {
@ -31,11 +32,19 @@ export const formattedBadge = (type: string) => {
return null; return null;
}; };
// random Script
function getRandomScript(categories: Category[]): Script | null {
const allScripts = categories.flatMap((cat) => cat.scripts || []);
if (allScripts.length === 0) return null;
const idx = Math.floor(Math.random() * allScripts.length);
return allScripts[idx];
}
export default function CommandMenu() { export default function CommandMenu() {
const [open, setOpen] = React.useState(false); const [open, setOpen] = React.useState(false);
const [links, setLinks] = React.useState<Category[]>([]); const [links, setLinks] = React.useState<Category[]>([]);
const router = useRouter();
const [isLoading, setIsLoading] = React.useState(false); const [isLoading, setIsLoading] = React.useState(false);
const router = useRouter();
React.useEffect(() => { React.useEffect(() => {
const down = (e: KeyboardEvent) => { const down = (e: KeyboardEvent) => {
@ -45,7 +54,6 @@ export default function CommandMenu() {
setOpen((open) => !open); setOpen((open) => !open);
} }
}; };
document.addEventListener("keydown", down); document.addEventListener("keydown", down);
return () => document.removeEventListener("keydown", down); return () => document.removeEventListener("keydown", down);
}, []); }, []);
@ -63,23 +71,58 @@ export default function CommandMenu() {
}); });
}; };
const openRandomScript = async () => {
if (links.length === 0) {
setIsLoading(true);
try {
const categories = await fetchCategories();
setLinks(categories);
const randomScript = getRandomScript(categories);
if (randomScript) {
router.push(`/scripts?id=${randomScript.slug}`);
}
} finally {
setIsLoading(false);
}
} else {
const randomScript = getRandomScript(links);
if (randomScript) {
router.push(`/scripts?id=${randomScript.slug}`);
}
}
};
return ( return (
<> <>
<Button <div className="flex gap-2">
variant="outline" <Button
className={cn( variant="outline"
"relative h-9 w-full justify-start rounded-[0.5rem] bg-muted/50 text-sm font-normal text-muted-foreground shadow-none sm:pr-12 md:w-40 lg:w-64", className={cn(
)} "relative h-9 w-full justify-start rounded-[0.5rem] bg-muted/50 text-sm font-normal text-muted-foreground shadow-none sm:pr-12 md:w-40 lg:w-64",
onClick={() => { )}
fetchSortedCategories(); onClick={() => {
setOpen(true); fetchSortedCategories();
}} setOpen(true);
> }}
<span className="inline-flex">Search scripts...</span> >
<kbd className="pointer-events-none absolute right-[0.3rem] top-[0.45rem] hidden h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium opacity-100 sm:flex"> <span className="inline-flex">Search scripts...</span>
<span className="text-xs"></span>K <kbd className="pointer-events-none absolute right-[0.3rem] top-[0.45rem] hidden h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium opacity-100 sm:flex">
</kbd> <span className="text-xs"></span>K
</Button> </kbd>
</Button>
<Button
variant="outline"
size="icon"
onClick={openRandomScript}
title="Open random script"
disabled={isLoading}
className="h-9 w-9"
>
<Sparkles className="h-5 w-5" />
</Button>
</div>
<CommandDialog open={open} onOpenChange={setOpen}> <CommandDialog open={open} onOpenChange={setOpen}>
<DialogTitle className="sr-only">Search scripts</DialogTitle> <DialogTitle className="sr-only">Search scripts</DialogTitle>
<CommandInput placeholder="Search for a script..." /> <CommandInput placeholder="Search for a script..." />

6
package-lock.json generated Normal file
View File

@ -0,0 +1,6 @@
{
"name": "ProxmoxVE",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}