forked from forkanization/Proxmox-arm64
Merge remote-tracking branch 'upstream/main'
This commit is contained in:
@@ -64,7 +64,7 @@ export default function Buttons({ item }: { item: Script }) {
|
||||
icon: <Code className="h-4 w-4" />,
|
||||
text: "Install Source",
|
||||
},
|
||||
updateSourceUrl && {
|
||||
updateSourceUrl && item.updateable && {
|
||||
href: updateSourceUrl,
|
||||
icon: <RefreshCcw className="h-4 w-4" />,
|
||||
text: "Update Source",
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
} from "@/components/ui/command";
|
||||
import { basePath } from "@/config/siteConfig";
|
||||
import { fetchCategories } from "@/lib/data";
|
||||
import { Category } from "@/lib/types";
|
||||
import { Category, Script } from "@/lib/types";
|
||||
import { cn } from "@/lib/utils";
|
||||
import Image from "next/image";
|
||||
import { useRouter } from "next/navigation";
|
||||
@@ -16,6 +16,10 @@ import React from "react";
|
||||
import { Badge } from "./ui/badge";
|
||||
import { Button } from "./ui/button";
|
||||
import { DialogTitle } from "./ui/dialog";
|
||||
import { Sparkles } from "lucide-react";
|
||||
import { TooltipContent, TooltipProvider } from "./ui/tooltip";
|
||||
import { TooltipTrigger } from "./ui/tooltip";
|
||||
import { Tooltip } from "./ui/tooltip";
|
||||
|
||||
export const formattedBadge = (type: string) => {
|
||||
switch (type) {
|
||||
@@ -31,11 +35,19 @@ export const formattedBadge = (type: string) => {
|
||||
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() {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [links, setLinks] = React.useState<Category[]>([]);
|
||||
const router = useRouter();
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
React.useEffect(() => {
|
||||
const down = (e: KeyboardEvent) => {
|
||||
@@ -45,7 +57,6 @@ export default function CommandMenu() {
|
||||
setOpen((open) => !open);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("keydown", down);
|
||||
return () => document.removeEventListener("keydown", down);
|
||||
}, []);
|
||||
@@ -63,23 +74,61 @@ 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 (
|
||||
<>
|
||||
<Button
|
||||
variant="outline"
|
||||
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();
|
||||
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="text-xs">⌘</span>K
|
||||
</kbd>
|
||||
</Button>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
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();
|
||||
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="text-xs">⌘</span>K
|
||||
</kbd>
|
||||
</Button>
|
||||
|
||||
<TooltipProvider>
|
||||
<Tooltip delayDuration={100}>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant="outline" size="icon" onClick={openRandomScript} disabled={isLoading} className="hidden lg:flex">
|
||||
<Sparkles className="size-4" />
|
||||
<span className="sr-only">Open Random Script</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>Open Random Script</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
|
||||
<CommandDialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTitle className="sr-only">Search scripts</DialogTitle>
|
||||
<CommandInput placeholder="Search for a script..." />
|
||||
|
||||
@@ -12,7 +12,7 @@ export default function Footer() {
|
||||
<p>
|
||||
Website built by the community. The source code is available on{" "}
|
||||
<Link
|
||||
href={`https://github.com/community-scripts/${basePath}/frontend`}
|
||||
href={`https://github.com/community-scripts/${basePath}/tree/main/frontend`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="font-semibold underline-offset-2 duration-300 hover:underline"
|
||||
|
||||
@@ -41,8 +41,8 @@ export default function CodeCopyButton({
|
||||
|
||||
return (
|
||||
<div className="mt-4 flex">
|
||||
<Card className="flex items-center overflow-x-auto bg-primary-foreground pl-4">
|
||||
<div className="overflow-x-auto whitespace-pre-wrap text-nowrap break-all pr-4 text-sm">
|
||||
<Card className="flex items-center overflow-x-auto bg-primary-foreground pl-4 [&::-webkit-scrollbar]:h-1.5 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-muted-foreground/20">
|
||||
<div className="overflow-x-auto whitespace-pre-wrap text-nowrap break-all pr-4 text-sm [&::-webkit-scrollbar]:h-1.5 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-muted-foreground/20">
|
||||
{!isMobile && children ? children : "Copy install command"}
|
||||
</div>
|
||||
<button
|
||||
|
||||
@@ -34,4 +34,9 @@ export const FAQ_Items = [
|
||||
content:
|
||||
"If an LXC script fails, run it again using Verbose mode. Standard mode hides detailed output for neatness, showing only progress. Verbose mode displays all messages, which helps you (and us) diagnose the error. Include this verbose output if you report the issue.",
|
||||
},
|
||||
{
|
||||
title: "What does \"Updatable\" and \"Not updatable\" mean?",
|
||||
content:
|
||||
"Updatable means that script has a function that is used to update the installed application to the latest version available. Not updatable means that script doesn't have a function that can safely update the application to the latest version available, so only the LXC OS is updated.",
|
||||
},
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user