This commit is contained in:
MacRimi
2025-02-13 23:04:40 +01:00
parent a9a89b5b46
commit 990b2bf7de
137 changed files with 7536 additions and 219 deletions

View File

@@ -0,0 +1,34 @@
# Changelog
All notable changes to ProxMenux will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- Initial project setup
- Basic menu structure
- Documentation framework
## [0.1.0] - 2023-06-15
### Added
- Core functionality for executing shell scripts
- Menu-driven interface for script selection
- Basic error handling and logging
### Changed
- Improved script organization with categories
### Fixed
- Issue with script permissions on certain systems
## [0.0.1] - 2023-06-01
### Added
- Project initialization
- README with basic project description
- License file

View File

@@ -0,0 +1,24 @@
import fs from "fs"
import path from "path"
import { remark } from "remark"
import html from "remark-html"
async function getChangelog() {
const changelogPath = path.join(process.cwd(), "CHANGELOG.md")
const fileContents = fs.readFileSync(changelogPath, "utf8")
const result = await remark().use(html).process(fileContents)
return result.toString()
}
export default async function ChangelogPage() {
const changelogContent = await getChangelog()
return (
<div className="container mx-auto px-4 py-16 max-w-4xl">
<h1 className="text-4xl font-bold mb-8">Changelog</h1>
<div className="prose prose-lg dark:prose-invert" dangerouslySetInnerHTML={{ __html: changelogContent }} />
</div>
)
}

View File

@@ -1,14 +0,0 @@
"use client";
import Navbar from "@/components/navbar"
import MouseMoveEffect from "@/components/mouse-move-effect"
export default function ClientLayout({ children }: { children: React.ReactNode }) {
return (
<>
<Navbar />
<MouseMoveEffect />
<div className="pt-16 md:pt-16">{children}</div>
</>
)
}

View File

@@ -1,9 +1,5 @@
"use client"
import Link from "next/link"
import { usePathname } from "next/navigation"
import { useState } from "react"
import { Menu } from "lucide-react"
const sidebarItems = [
{ title: "Introduction", href: "/docs/introduction" },
@@ -11,33 +7,23 @@ const sidebarItems = [
{ title: "Getting Started", href: "/docs/getting-started" },
{ title: "Features", href: "/docs/features" },
{ title: "API", href: "/docs/api" },
{ title: "Guides", href: "/guides" },
{ title: "FAQ", href: "/docs/faq" },
]
export default function DocSidebar() {
const pathname = usePathname()
const [isOpen, setIsOpen] = useState(false)
return (
<nav className="w-full md:w-64 bg-gray-100 p-4 md:p-6">
<div className="flex justify-between items-center md:block">
<h2 className="text-lg font-semibold mb-4 text-gray-900">Documentation</h2>
<button className="md:hidden" onClick={() => setIsOpen(!isOpen)}>
<Menu className="h-6 w-6" />
</button>
</div>
<ul className={`space-y-2 ${isOpen ? "block" : "hidden"} md:block`}>
<nav className="w-64 bg-gray-100 p-6">
<h2 className="text-lg font-semibold mb-4">Documentation</h2>
<ul className="space-y-2">
{sidebarItems.map((item) => (
<li key={item.href}>
<Link
href={item.href}
className={`block p-2 rounded ${
pathname === item.href
? "bg-blue-500 text-white"
: "text-gray-700 hover:bg-gray-200 hover:text-gray-900"
pathname === item.href ? "bg-blue-500 text-white" : "text-gray-700 hover:bg-gray-200"
}`}
onClick={() => setIsOpen(false)}
>
{item.title}
</Link>

View File

@@ -1,28 +0,0 @@
"use client"
import { useEffect, useState } from "react"
export default function MouseMoveEffect() {
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 })
useEffect(() => {
const handleMouseMove = (event: MouseEvent) => {
setMousePosition({ x: event.clientX, y: event.clientY })
}
window.addEventListener("mousemove", handleMouseMove)
return () => {
window.removeEventListener("mousemove", handleMouseMove)
}
}, [])
return (
<div
className="pointer-events-none fixed inset-0 z-30 transition-opacity duration-300"
style={{
background: `radial-gradient(600px at ${mousePosition.x}px ${mousePosition.y}px, rgba(29, 78, 216, 0.15), transparent 80%)`,
}}
/>
)
}

View File

@@ -1,56 +1,74 @@
import Link from "next/link"
import { MessageCircle } from "lucide-react"
import Image from "next/image"
import { Facebook, Twitter, Instagram, Linkedin } from "lucide-react"
export default function Footer() {
return (
<footer className="bg-gray-900 text-white py-12">
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex flex-col md:flex-row justify-between">
{/* Support Section - Left Side */}
<div className="flex flex-col items-start mb-8 md:mb-0">
<h4 className="text-lg font-semibold mb-4">Sponsor</h4>
<p className="text-gray-400 mb-4 max-w-md">
If you would like to support the project, you can buy me a coffee on Ko-fi! Thank you! 😊
</p>
<a
href="https://ko-fi.com/G2G313ECAN"
target="_blank"
rel="noopener noreferrer"
className="hover:opacity-90 transition-opacity flex items-center"
>
<Image
src="https://raw.githubusercontent.com/MacRimi/HWEncoderX/main/images/kofi.png"
alt="Support me on Ko-fi"
width={175}
height={50}
className="w-[175px] mr-[65px]"
/>
</a>
</div>
{/* Connect Section - Right Side */}
<div className="flex flex-col items-start md:items-end">
<h4 className="text-lg font-semibold mb-4">Connect</h4>
<p className="text-gray-400 mb-4 max-w-md md:text-right">
Join our community discussions on GitHub to get help, share ideas, and contribute to the project.
</p>
<Link
href="https://github.com/MacRimi/ProxMenux/discussions"
className="flex items-center text-blue-400 hover:text-blue-300 transition-colors duration-200"
target="_blank"
rel="noopener noreferrer"
>
<MessageCircle className="mr-2 h-5 w-5" />
Join the Discussion
<div className="container mx-auto grid grid-cols-1 md:grid-cols-4 gap-8">
<div>
<h3 className="text-lg font-semibold mb-4">StreamLine</h3>
<p className="text-gray-400">Streamlining your workflow, one task at a time.</p>
</div>
<div>
<h4 className="text-lg font-semibold mb-4">Product</h4>
<ul className="space-y-2">
<li>
<Link href="#features" className="text-gray-400 hover:text-white">
Features
</Link>
</li>
<li>
<Link href="#pricing" className="text-gray-400 hover:text-white">
Pricing
</Link>
</li>
<li>
<Link href="#" className="text-gray-400 hover:text-white">
Integrations
</Link>
</li>
</ul>
</div>
<div>
<h4 className="text-lg font-semibold mb-4">Company</h4>
<ul className="space-y-2">
<li>
<Link href="#" className="text-gray-400 hover:text-white">
About Us
</Link>
</li>
<li>
<Link href="#" className="text-gray-400 hover:text-white">
Careers
</Link>
</li>
<li>
<Link href="#" className="text-gray-400 hover:text-white">
Contact
</Link>
</li>
</ul>
</div>
<div>
<h4 className="text-lg font-semibold mb-4">Connect</h4>
<div className="flex space-x-4">
<Link href="#" className="text-gray-400 hover:text-white">
<Facebook className="h-6 w-6" />
</Link>
<Link href="#" className="text-gray-400 hover:text-white">
<Twitter className="h-6 w-6" />
</Link>
<Link href="#" className="text-gray-400 hover:text-white">
<Instagram className="h-6 w-6" />
</Link>
<Link href="#" className="text-gray-400 hover:text-white">
<Linkedin className="h-6 w-6" />
</Link>
</div>
</div>
{/* Copyright - Center */}
<div className="mt-8 pt-8 border-t border-gray-800 text-center text-gray-400">
<p>&copy; {new Date().getFullYear()} ProxMenux. All rights reserved.</p>
</div>
</div>
<div className="container mx-auto mt-8 pt-8 border-t border-gray-800 text-center text-gray-400">
<p>&copy; 2025 StreamLine. All rights reserved.</p>
</div>
</footer>
)

View File

@@ -1,30 +1,23 @@
import { Button } from "@/components/ui/button"
import { ArrowRight } from "lucide-react"
import Link from "next/link"
export default function Hero() {
return (
<section className="py-20 px-4 sm:px-6 lg:px-8 text-center">
<h1 className="text-4xl sm:text-5xl md:text-6xl font-extrabold mb-6">
ProxMenux{" "}
<span className="bg-clip-text text-transparent bg-gradient-to-r from-blue-400 to-purple-500">
A menu-driven script for Proxmox VE management
</span>
</h1>
<p className="text-base sm:text-lg md:text-xl mb-8 max-w-4xl mx-auto text-gray-300">
ProxMenu is a tool designed to execute shell scripts in an organized manner, using a menu system with categories
to facilitate access and execution of various scripts hosted on GitHub. ProxMenu simplifies script usage, aiming
to improve productivity and streamline automated tasks.
</p>
<div className="flex justify-center">
<Button size="lg" className="bg-blue-500 hover:bg-blue-600" asChild>
<Link href="/docs/installation">
Install Now
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
<div className="relative pt-32 pb-20 sm:pt-40 sm:pb-24">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h1 className="text-4xl sm:text-6xl lg:text-7xl font-bold tracking-tight mb-8">
Everything App
<br />
<span className="text-gray-400">for your teams</span>
</h1>
<p className="max-w-2xl mx-auto text-lg sm:text-xl text-gray-400 mb-10">
Huly, an open-source platform, serves as an all-in-one replacement of Linear, Jira, Slack, and Notion.
</p>
<Button className="relative group px-8 py-6 text-lg bg-gradient-to-r from-primary to-accent hover:opacity-90">
<span className="relative z-10">Try it free</span>
<div className="absolute inset-0 bg-white/20 blur-lg group-hover:blur-xl transition-all duration-300 opacity-0 group-hover:opacity-100" />
</Button>
</div>
</section>
</div>
)
}

View File

@@ -1,29 +0,0 @@
"use client"
import { useEffect, useState } from "react"
export default function MouseMoveEffect() {
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 })
useEffect(() => {
const handleMouseMove = (event: MouseEvent) => {
setMousePosition({ x: event.clientX, y: event.clientY })
}
window.addEventListener("mousemove", handleMouseMove)
return () => {
window.removeEventListener("mousemove", handleMouseMove)
}
}, [])
return (
<div
className="pointer-events-none fixed inset-0 z-30 transition-opacity duration-300"
style={{
background: `radial-gradient(600px at ${mousePosition.x}px ${mousePosition.y}px, rgba(29, 78, 216, 0.15), transparent 80%)`,
}}
/>
)
}

View File

@@ -1,73 +1,47 @@
"use client"
import Link from "next/link"
import Image from "next/image"
import { Book, GitBranch, FileText, Github, Menu } from "lucide-react"
import { useState } from "react"
import { Button } from "@/components/ui/button"
export default function Navbar() {
const [isMenuOpen, setIsMenuOpen] = useState(false)
const navItems = [
{ href: "/docs/introduction", icon: <Book className="h-4 w-4" />, label: "Documentation" },
{ href: "/changelog", icon: <FileText className="h-4 w-4" />, label: "Changelog" },
{ href: "/guides", icon: <GitBranch className="h-4 w-4" />, label: "Guides" },
{ href: "https://github.com/MacRimi/ProxMenux", icon: <Github className="h-4 w-4" />, label: "GitHub" },
]
return (
<header className="fixed top-0 left-0 right-0 z-50 bg-background/95 backdrop-blur border-b border-border/40">
<div className="container mx-auto px-4">
<nav className="fixed top-0 left-0 right-0 z-50 bg-background/80 backdrop-blur-md border-b border-white/10">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-16">
<Link href="/" className="flex items-center space-x-2">
<Image
src="https://raw.githubusercontent.com/MacRimi/ProxMenux/main/images/logo2.png"
alt="ProxMenux Logo"
width={32}
height={32}
className="w-8 h-8"
/>
<span className="text-xl font-bold">ProxMenux</span>
</Link>
{/* Desktop menu */}
<nav className="hidden md:flex items-center space-x-6 text-sm font-medium">
{navItems.map((item) => (
<Link
key={item.href}
href={item.href}
className="flex items-center space-x-2 transition-colors hover:text-primary"
>
{item.icon}
<span>{item.label}</span>
</Link>
))}
</nav>
{/* Mobile menu button */}
<button className="md:hidden p-2" onClick={() => setIsMenuOpen(!isMenuOpen)}>
<Menu className="h-6 w-6" />
</button>
<div className="flex items-center">
<Link
href="/"
className="text-2xl font-bold bg-gradient-to-r from-primary to-accent bg-clip-text text-transparent"
>
StreamLine
</Link>
<div className="hidden md:block ml-10">
<div className="flex items-center space-x-8">
<Link href="#" className="text-sm text-gray-300 hover:text-white">
Pricing
</Link>
<Link href="/docs" className="text-sm text-gray-300 hover:text-white">
Docs
</Link>
<Link href="#" className="text-sm text-gray-300 hover:text-white">
Resources
</Link>
<Link href="#" className="text-sm text-gray-300 hover:text-white">
Community
</Link>
<Link href="#" className="text-sm text-gray-300 hover:text-white">
Download
</Link>
</div>
</div>
</div>
<div className="flex items-center space-x-4">
<Button variant="ghost" className="text-sm">
Sign In
</Button>
<Button className="text-sm bg-gradient-to-r from-primary to-accent hover:opacity-90">Get Started</Button>
</div>
</div>
{/* Mobile menu */}
{isMenuOpen && (
<nav className="md:hidden py-4">
{navItems.map((item) => (
<Link
key={item.href}
href={item.href}
className="flex items-center space-x-2 py-2 transition-colors hover:text-primary"
onClick={() => setIsMenuOpen(false)}
>
{item.icon}
<span>{item.label}</span>
</Link>
))}
</nav>
)}
</div>
</header>
</nav>
)
}

View File

@@ -1,52 +0,0 @@
import { Book, GitBranch, FileText, Github } from "lucide-react"
import Link from "next/link"
const resources = [
{
icon: <Book className="h-6 w-6" />,
title: "Documentation",
description: "Comprehensive guides to get you started",
link: "/docs/introduction",
},
{
icon: <FileText className="h-6 w-6" />,
title: "Changelog",
description: "Stay up to date with the latest changes",
link: "/changelog",
},
{
icon: <GitBranch className="h-6 w-6" />,
title: "Guides",
description: "Step-by-step tutorials for common tasks",
link: "/guides",
},
{
icon: <Github className="h-6 w-6" />,
title: "GitHub Repository",
description: "Explore the source code and contribute",
link: "https://github.com/MacRimi/ProxMenux",
},
]
export default function Resources() {
return (
<section className="py-20 bg-gray-900">
<div className="container mx-auto px-4">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
{resources.map((resource, index) => (
<Link key={index} href={resource.link} className="block">
<div className="bg-gray-800 p-6 rounded-lg shadow-lg hover:bg-gray-700 transition-colors duration-200">
<div className="flex items-center mb-4">
{resource.icon}
<h3 className="text-xl font-semibold ml-2">{resource.title}</h3>
</div>
<p className="text-gray-400">{resource.description}</p>
</div>
</Link>
))}
</div>
</div>
</section>
)
}

View File

@@ -1,26 +0,0 @@
import { Button } from "@/components/ui/button"
import { Star } from "lucide-react"
export default function SupportProject() {
return (
<section className="py-16 bg-gray-900">
<div className="container mx-auto px-4 text-center">
<h2 className="text-3xl font-bold mb-6">Support the Project!</h2>
<p className="text-xl mb-8">
If you find <span className="font-bold">ProxMenux</span> useful, consider giving it a on GitHub to help
others discover it!
</p>
<div className="flex justify-center items-center">
<Button
className="bg-yellow-400 text-gray-900 hover:bg-yellow-500"
onClick={() => window.open("https://github.com/MacRimi/ProxMenux", "_blank")}
>
<Star className="mr-2" />
Star on GitHub
</Button>
</div>
</div>
</section>
)
}

View File

@@ -18,16 +18,18 @@ const testimonials = [
export default function Testimonials() {
return (
<section className="py-20 px-4 sm:px-6 lg:px-8 bg-gray-900">
<h2 className="text-3xl font-bold text-center mb-12">What Our Customers Say</h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{testimonials.map((testimonial, index) => (
<div key={index} className="bg-gray-800 p-6 rounded-lg shadow-lg">
<p className="text-lg mb-4">"{testimonial.quote}"</p>
<p className="font-semibold">{testimonial.author}</p>
<p className="text-sm text-gray-400">{testimonial.company}</p>
</div>
))}
<section id="testimonials" className="py-20 bg-white">
<div className="container mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">What Our Customers Say</h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{testimonials.map((testimonial, index) => (
<div key={index} className="bg-gray-50 p-6 rounded-lg">
<p className="text-lg mb-4">"{testimonial.quote}"</p>
<p className="font-semibold">{testimonial.author}</p>
<p className="text-sm text-gray-600">{testimonial.company}</p>
</div>
))}
</div>
</div>
</section>
)

View File

@@ -1,7 +0,0 @@
'use client'
import { ThemeProvider as NextThemesProvider } from "next-themes";
export function ThemeProvider({ children }: { children: React.ReactNode }) {
return <NextThemesProvider>{children}</NextThemesProvider>;
}

View File

@@ -1,56 +0,0 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline:
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = "Button"
export { Button, buttonVariants }

View File

@@ -1,35 +0,0 @@
import React from "react"
interface StepProps {
title: string
children: React.ReactNode
}
const Step: React.FC<StepProps> = ({ title, children }) => (
<div className="mb-8">
<h3 className="text-xl font-semibold mb-2 text-gray-900">{title}</h3>
{children}
</div>
)
interface StepsProps {
children: React.ReactNode
}
const Steps: React.FC<StepsProps> & { Step: typeof Step } = ({ children }) => (
<div className="space-y-4">
{React.Children.map(children, (child, index) => (
<div className="flex items-start">
<div className="flex-shrink-0 w-8 h-8 bg-blue-500 text-white rounded-full flex items-center justify-center mr-4 mt-1">
{index + 1}
</div>
<div className="flex-grow">{child}</div>
</div>
))}
</div>
)
Steps.Step = Step
export { Steps }

View File

@@ -1,129 +0,0 @@
"use client"
import * as React from "react"
import * as ToastPrimitives from "@radix-ui/react-toast"
import { cva, type VariantProps } from "class-variance-authority"
import { X } from "lucide-react"
import { cn } from "@/lib/utils"
const ToastProvider = ToastPrimitives.Provider
const ToastViewport = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Viewport>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Viewport
ref={ref}
className={cn(
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
className
)}
{...props}
/>
))
ToastViewport.displayName = ToastPrimitives.Viewport.displayName
const toastVariants = cva(
"group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
{
variants: {
variant: {
default: "border bg-background text-foreground",
destructive:
"destructive group border-destructive bg-destructive text-destructive-foreground",
},
},
defaultVariants: {
variant: "default",
},
}
)
const Toast = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
VariantProps<typeof toastVariants>
>(({ className, variant, ...props }, ref) => {
return (
<ToastPrimitives.Root
ref={ref}
className={cn(toastVariants({ variant }), className)}
{...props}
/>
)
})
Toast.displayName = ToastPrimitives.Root.displayName
const ToastAction = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Action>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Action
ref={ref}
className={cn(
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
className
)}
{...props}
/>
))
ToastAction.displayName = ToastPrimitives.Action.displayName
const ToastClose = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Close>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Close
ref={ref}
className={cn(
"absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
className
)}
toast-close=""
{...props}
>
<X className="h-4 w-4" />
</ToastPrimitives.Close>
))
ToastClose.displayName = ToastPrimitives.Close.displayName
const ToastTitle = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Title>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Title
ref={ref}
className={cn("text-sm font-semibold", className)}
{...props}
/>
))
ToastTitle.displayName = ToastPrimitives.Title.displayName
const ToastDescription = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Description>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Description
ref={ref}
className={cn("text-sm opacity-90", className)}
{...props}
/>
))
ToastDescription.displayName = ToastPrimitives.Description.displayName
type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>
type ToastActionElement = React.ReactElement<typeof ToastAction>
export {
type ToastProps,
type ToastActionElement,
ToastProvider,
ToastViewport,
Toast,
ToastTitle,
ToastDescription,
ToastClose,
ToastAction,
}

View File

@@ -3,30 +3,21 @@ import path from "path"
import { remark } from "remark"
import html from "remark-html"
// Function to retrieve the guide content based on the slug
async function getGuideContent(slug: string) {
// Adjusted to look inside the correct 'guides' folder at the root level of the project
const guidePath = path.join(process.cwd(), "..", "guides", slug, "index.md") // Corrected to look in the root directory
const guidePath = path.join(process.cwd(), "guides", `${slug}.md`)
const fileContents = fs.readFileSync(guidePath, "utf8")
const result = await remark().use(html).process(fileContents)
return result.toString()
}
// Function to generate static paths for all available guides
export async function generateStaticParams() {
// Adjusted to look in the correct 'guides' folder at the root level of the project
const guidesPath = path.join(process.cwd(), "..", "guides")
const guideFolders = fs.readdirSync(guidesPath, { withFileTypes: true }) // Read only directories
return guideFolders
.filter((folder) => folder.isDirectory()) // Ensure it's a directory
.map((folder) => ({
slug: folder.name, // Use the folder name as slug
}))
const guideFiles = fs.readdirSync(path.join(process.cwd(), "guides"))
return guideFiles.map((file) => ({
slug: file.replace(/\.md$/, ""),
}))
}
// Page component to render a guide based on its slug
export default async function GuidePage({ params }: { params: { slug: string } }) {
const guideContent = await getGuideContent(params.slug)
@@ -36,3 +27,4 @@ export default async function GuidePage({ params }: { params: { slug: string } }
</div>
)
}

View File

@@ -0,0 +1,52 @@
# Setting up NVIDIA Drivers on Proxmox VE with GPU Passthrough
This guide explains how to install and configure NVIDIA drivers on your Proxmox VE host and enable GPU passthrough to your virtual machines. This allows you to leverage the power of your NVIDIA GPU within your VMs for tasks like machine learning, gaming, or video editing.
## Prerequisites
Before you begin, ensure you have the following:
* A Proxmox VE server with an NVIDIA GPU installed.
* Access to the Proxmox VE command line interface (CLI) via SSH.
* A basic understanding of Proxmox VE and virtual machine management.
## Installing the NVIDIA Driver on the Proxmox VE Host
This step involves installing the NVIDIA driver on your Proxmox VE host operating system. The exact steps may vary slightly depending on your Proxmox VE version and the specific NVIDIA GPU you are using. Consult the official NVIDIA documentation for the most up-to-date instructions.
Generally, you will need to download the appropriate driver package from the NVIDIA website and then install it using the package manager for your distribution.
## Enabling GPU Passthrough
Once the NVIDIA driver is installed, you need to enable GPU passthrough for your virtual machines. This involves assigning the GPU to a specific VM.
1. **Identify your GPU:** Use the `lspci` command to identify the PCI address of your NVIDIA GPU. The output will look something like this:
\`\`\`bash
01:00.0 VGA compatible controller: NVIDIA Corporation ...
\`\`\`
Note the `01:00.0` part this is the PCI address.
2. **Create a VM:** Create a new virtual machine in Proxmox VE.
3. **Assign the GPU:** During the VM creation process, or afterwards using the VM's configuration, assign the NVIDIA GPU to the VM using the PCI address you identified earlier. This is typically done in the "Hardware" section of the VM's settings.
4. **Install the Guest Additions:** Once the VM is created, install the appropriate guest additions for your VM's operating system. This will ensure that the VM can properly utilize the passed-through GPU.
## Verifying GPU Passthrough
After completing these steps, boot your VM and verify that the NVIDIA GPU is working correctly. You can use tools like `nvidia-smi` (within the VM) to check the GPU status and utilization.
## Troubleshooting
If you encounter any issues, check the following:
* **Driver Installation:** Ensure the NVIDIA driver is correctly installed on the Proxmox VE host.
* **PCI Address:** Double-check that you have used the correct PCI address when assigning the GPU to the VM.
* **Guest Additions:** Make sure the appropriate guest additions are installed within the VM.
* **VM Configuration:** Verify that the VM's configuration is correct and that the GPU is properly assigned.
* **Proxmox VE Logs:** Check the Proxmox VE logs for any errors related to the GPU or VM.
This guide provides a general overview. For more detailed instructions and troubleshooting tips, refer to the official NVIDIA and Proxmox VE documentation.

View File

@@ -1,13 +1,11 @@
import Link from "next/link"
// Interface defining the structure of a guide
interface Guide {
title: string
description: string
slug: string
}
// Guide list (manually added, can be automated later)
const guides: Guide[] = [
{
title: "Setting up NVIDIA Drivers on Proxmox VE with GPU Passthrough",
@@ -16,14 +14,13 @@ const guides: Guide[] = [
slug: "nvidia_proxmox",
},
{
title: "Example Additional Guide",
description: "This is a sample guide to show how multiple guides are handled.",
title: "Ejemplo de Guía Adicional",
description: "Esta es una guía de ejemplo para mostrar cómo se manejan múltiples guías.",
slug: "example_guide",
},
// Add more guides as needed
// Añade más guías aquí según sea necesario
]
// Main component that renders the list of available guides
export default function GuidesPage() {
return (
<div className="container mx-auto px-4 py-16">
@@ -44,3 +41,4 @@ export default function GuidesPage() {
</div>
)
}

View File

@@ -1,7 +1,9 @@
import "./globals.css"
import { Inter } from "next/font/google"
import type React from "react"
import type { Metadata } from "next"
import ClientLayout from "@/components/ClientLayout"
import Navbar from "@/components/navbar"
import MouseMoveEffect from "@/components/mouse-move-effect"
const inter = Inter({ subsets: ["latin"] })
@@ -9,15 +11,25 @@ export const metadata: Metadata = {
title: "ProxMenux - A menu-driven script for Proxmox VE management",
description:
"ProxMenux is a tool designed to execute shell scripts in an organized manner for Proxmox VE management.",
generator: "v0.dev",
generator: 'v0.dev'
}
export default function RootLayout({ children }: { children: React.ReactNode }) {
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en" className="dark">
<body className={`${inter.className} bg-background text-foreground antialiased`}>
<ClientLayout>{children}</ClientLayout>
<Navbar />
<MouseMoveEffect />
<div className="pt-16 md:pt-16">{children}</div>
</body>
</html>
)
}
import './globals.css'

View File

@@ -1,5 +1,3 @@
"use client";
import Hero from "@/components/hero"
import Resources from "@/components/resources"
import SupportProject from "@/components/support-project"