mirror of
https://github.com/community-scripts/Proxmox.git
synced 2026-04-05 09:04:01 -04:00
put the script browser inside a separate component for better readability
This commit is contained in:
@@ -5,47 +5,47 @@
|
|||||||
@layer base {
|
@layer base {
|
||||||
:root {
|
:root {
|
||||||
--background: 0 0% 100%;
|
--background: 0 0% 100%;
|
||||||
--foreground: 240 10% 3.9%;
|
--foreground: 20 14.3% 4.1%;
|
||||||
--card: 0 0% 100%;
|
--card: 0 0% 100%;
|
||||||
--card-foreground: 240 10% 3.9%;
|
--card-foreground: 20 14.3% 4.1%;
|
||||||
--popover: 0 0% 100%;
|
--popover: 0 0% 100%;
|
||||||
--popover-foreground: 240 10% 3.9%;
|
--popover-foreground: 20 14.3% 4.1%;
|
||||||
--primary: 240 5.9% 10%;
|
--primary: 24.6 95% 53.1%;
|
||||||
--primary-foreground: 0 0% 98%;
|
--primary-foreground: 60 9.1% 97.8%;
|
||||||
--secondary: 240 4.8% 95.9%;
|
--secondary: 60 4.8% 95.9%;
|
||||||
--secondary-foreground: 240 5.9% 10%;
|
--secondary-foreground: 24 9.8% 10%;
|
||||||
--muted: 240 4.8% 95.9%;
|
--muted: 60 4.8% 95.9%;
|
||||||
--muted-foreground: 240 3.8% 46.1%;
|
--muted-foreground: 25 5.3% 44.7%;
|
||||||
--accent: 240 4.8% 95.9%;
|
--accent: 60 4.8% 95.9%;
|
||||||
--accent-foreground: 240 5.9% 10%;
|
--accent-foreground: 24 9.8% 10%;
|
||||||
--destructive: 0 84.2% 60.2%;
|
--destructive: 0 84.2% 60.2%;
|
||||||
--destructive-foreground: 0 0% 98%;
|
--destructive-foreground: 60 9.1% 97.8%;
|
||||||
--border: 240 5.9% 90%;
|
--border: 20 5.9% 90%;
|
||||||
--input: 240 5.9% 90%;
|
--input: 20 5.9% 90%;
|
||||||
--ring: 240 5.9% 10%;
|
--ring: 24.6 95% 53.1%;
|
||||||
--radius: 0.5rem;
|
--radius: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
--background: 240 10% 3.9%;
|
--background: 20 14.3% 4.1%;
|
||||||
--foreground: 0 0% 98%;
|
--foreground: 60 9.1% 97.8%;
|
||||||
--card: 240 10% 3.9%;
|
--card: 20 14.3% 4.1%;
|
||||||
--card-foreground: 0 0% 98%;
|
--card-foreground: 60 9.1% 97.8%;
|
||||||
--popover: 240 10% 3.9%;
|
--popover: 20 14.3% 4.1%;
|
||||||
--popover-foreground: 0 0% 98%;
|
--popover-foreground: 60 9.1% 97.8%;
|
||||||
--primary: 201 100% 38%;
|
--primary: 20.5 90.2% 48.2%;
|
||||||
--primary-foreground: 240 5.9% 10%;
|
--primary-foreground: 60 9.1% 97.8%;
|
||||||
--secondary: 240 3.7% 15.9%;
|
--secondary: 12 6.5% 15.1%;
|
||||||
--secondary-foreground: 0 0% 98%;
|
--secondary-foreground: 60 9.1% 97.8%;
|
||||||
--muted: 240 3.7% 15.9%;
|
--muted: 12 6.5% 15.1%;
|
||||||
--muted-foreground: 240 5% 64.9%;
|
--muted-foreground: 24 5.4% 63.9%;
|
||||||
--accent: 240 3.7% 15.9%;
|
--accent: 12 6.5% 15.1%;
|
||||||
--accent-foreground: 0 0% 98%;
|
--accent-foreground: 60 9.1% 97.8%;
|
||||||
--destructive: 0 62.8% 30.6%;
|
--destructive: 0 72.2% 50.6%;
|
||||||
--destructive-foreground: 0 0% 98%;
|
--destructive-foreground: 60 9.1% 97.8%;
|
||||||
--border: 240 3.7% 15.9%;
|
--border: 12 6.5% 15.1%;
|
||||||
--input: 240 3.7% 15.9%;
|
--input: 12 6.5% 15.1%;
|
||||||
--ring: 240 4.9% 83.9%;
|
--ring: 20.5 90.2% 48.2%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@layer base {
|
@layer base {
|
||||||
@@ -55,12 +55,4 @@
|
|||||||
body {
|
body {
|
||||||
@apply bg-background text-foreground;
|
@apply bg-background text-foreground;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-state="open"] .accordioncontent {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-state="closed"] .accordioncontent {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
@@ -1,62 +1,8 @@
|
|||||||
"use client";
|
|
||||||
import React, { useEffect, useState, useRef } from "react";
|
|
||||||
import {
|
|
||||||
Accordion,
|
|
||||||
AccordionItem,
|
|
||||||
AccordionTrigger,
|
|
||||||
AccordionContent,
|
|
||||||
} from "@/components/ui/accordion";
|
|
||||||
import { Input } from "@/components/ui/input";
|
|
||||||
import ScriptItem from "@/components/Script";
|
import ScriptItem from "@/components/Script";
|
||||||
import { Category } from "@/lib/types";
|
import ScriptBrowser from "@/components/ScriptBrowser";
|
||||||
import Link from "next/link";
|
|
||||||
import Particles from "@/components/ui/particles";
|
import Particles from "@/components/ui/particles";
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const [selectedItem, setSelectedItem] = useState("");
|
|
||||||
const [links, setLinks] = useState<Category[]>([]);
|
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handleKeyDown = (event: any) => {
|
|
||||||
if (event.key === "/") {
|
|
||||||
if (inputRef.current) {
|
|
||||||
inputRef.current.focus();
|
|
||||||
}
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchData = async () => {
|
|
||||||
try {
|
|
||||||
const data = await getLinks();
|
|
||||||
setLinks(data);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error fetching links:", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
fetchData();
|
|
||||||
|
|
||||||
document.addEventListener("keydown", handleKeyDown);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
document.removeEventListener("keydown", handleKeyDown);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const getLinks = 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 handleSearch = (value: string) => {
|
|
||||||
setSearchTerm(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Particles
|
<Particles
|
||||||
@@ -64,62 +10,7 @@ export default function Page() {
|
|||||||
quantity={100}
|
quantity={100}
|
||||||
/>
|
/>
|
||||||
<div className="mt-20 flex">
|
<div className="mt-20 flex">
|
||||||
<div className="flex min-w-72 max-w-72 flex-col">
|
<ScriptBrowser />
|
||||||
<h1 className="mb-5 text-xl font-bold">Scripts</h1>
|
|
||||||
<Input
|
|
||||||
className="mb-5"
|
|
||||||
type="text"
|
|
||||||
placeholder="Type '/' to search"
|
|
||||||
onChange={(e) => handleSearch(e.target.value)}
|
|
||||||
ref={inputRef}
|
|
||||||
/>
|
|
||||||
<Accordion
|
|
||||||
type={searchTerm ? "multiple" : "single"}
|
|
||||||
{...(searchTerm ? {} : { collapsible: true })}
|
|
||||||
>
|
|
||||||
{links.map(
|
|
||||||
(category) =>
|
|
||||||
category.Items.filter(
|
|
||||||
(script) =>
|
|
||||||
!searchTerm ||
|
|
||||||
script.title
|
|
||||||
.toLowerCase()
|
|
||||||
.includes(searchTerm.toLowerCase()),
|
|
||||||
).length > 0 && (
|
|
||||||
<AccordionItem
|
|
||||||
value={category.id}
|
|
||||||
key={category.id}
|
|
||||||
className={`text-md flex flex-col gap-2`}
|
|
||||||
>
|
|
||||||
<AccordionTrigger>
|
|
||||||
{category.Catagory_Title}
|
|
||||||
</AccordionTrigger>
|
|
||||||
<AccordionContent>
|
|
||||||
{category.Items.filter(
|
|
||||||
(script) =>
|
|
||||||
!searchTerm ||
|
|
||||||
script.title
|
|
||||||
.toLowerCase()
|
|
||||||
.includes(searchTerm.toLowerCase()),
|
|
||||||
).map((script, index) => (
|
|
||||||
<p key={index} className="py-1">
|
|
||||||
<Link
|
|
||||||
href={{
|
|
||||||
pathname: "/scripts",
|
|
||||||
query: { id: script.scriptID },
|
|
||||||
}}
|
|
||||||
className="text-muted-foreground"
|
|
||||||
>
|
|
||||||
{script.title}
|
|
||||||
</Link>
|
|
||||||
</p>
|
|
||||||
))}
|
|
||||||
</AccordionContent>
|
|
||||||
</AccordionItem>
|
|
||||||
),
|
|
||||||
)}
|
|
||||||
</Accordion>
|
|
||||||
</div>
|
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<div className="h-screen w-full">
|
<div className="h-screen w-full">
|
||||||
<ScriptItem />
|
<ScriptItem />
|
||||||
|
|||||||
125
components/ScriptBrowser.tsx
Normal file
125
components/ScriptBrowser.tsx
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
'use client'
|
||||||
|
import {
|
||||||
|
Accordion,
|
||||||
|
AccordionItem,
|
||||||
|
AccordionTrigger,
|
||||||
|
AccordionContent,
|
||||||
|
} from "@/components/ui/accordion";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import Link from "next/link";
|
||||||
|
import React, { useEffect, useState, useRef } from "react";
|
||||||
|
import { Category } from "@/lib/types";
|
||||||
|
|
||||||
|
function ScriptBrowser() {
|
||||||
|
const [selectedItem, setSelectedItem] = useState("");
|
||||||
|
const [links, setLinks] = useState<Category[]>([]);
|
||||||
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
const [isSearch, setIsSearch] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleKeyDown = (event: any) => {
|
||||||
|
if (event.key === "/") {
|
||||||
|
if (inputRef.current) {
|
||||||
|
inputRef.current.focus();
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
const data = await getLinks();
|
||||||
|
setLinks(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching links:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchData();
|
||||||
|
|
||||||
|
document.addEventListener("keydown", handleKeyDown);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener("keydown", handleKeyDown);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getLinks = 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 handleSearch = (value: string) => {
|
||||||
|
setSearchTerm(value);
|
||||||
|
if (value.length > 0) {
|
||||||
|
setIsSearch(true);
|
||||||
|
} else {
|
||||||
|
setIsSearch(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{" "}
|
||||||
|
<div className="flex min-w-72 max-w-72 flex-col">
|
||||||
|
<h1 className="mb-5 text-xl font-bold">Scripts</h1>
|
||||||
|
<Input
|
||||||
|
className="mb-5"
|
||||||
|
type="text"
|
||||||
|
placeholder="Type '/' to search"
|
||||||
|
onChange={(e) => handleSearch(e.target.value)}
|
||||||
|
ref={inputRef}
|
||||||
|
/>
|
||||||
|
<Accordion
|
||||||
|
type={searchTerm ? "multiple" : "single"}
|
||||||
|
{...(searchTerm ? {} : { collapsible: true })}
|
||||||
|
>
|
||||||
|
{links.map(
|
||||||
|
(category) =>
|
||||||
|
category.Items.filter(
|
||||||
|
(script) =>
|
||||||
|
!searchTerm ||
|
||||||
|
script.title.toLowerCase().includes(searchTerm.toLowerCase()),
|
||||||
|
).length > 0 && (
|
||||||
|
<AccordionItem
|
||||||
|
value={category.id}
|
||||||
|
key={category.id}
|
||||||
|
className={`text-md flex flex-col gap-2`}
|
||||||
|
// if search term is present, open the accordion with the [data-state]
|
||||||
|
{...(isSearch ? { "data-state": "open" } : {})}
|
||||||
|
data-state="open"
|
||||||
|
>
|
||||||
|
<AccordionTrigger>{category.Catagory_Title}</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
{category.Items.filter(
|
||||||
|
(script) =>
|
||||||
|
!searchTerm ||
|
||||||
|
script.title
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(searchTerm.toLowerCase()),
|
||||||
|
).map((script, index) => (
|
||||||
|
<p key={index} className="py-1">
|
||||||
|
<Link
|
||||||
|
href={{
|
||||||
|
pathname: "/scripts",
|
||||||
|
query: { id: script.scriptID },
|
||||||
|
}}
|
||||||
|
className="text-muted-foreground"
|
||||||
|
>
|
||||||
|
{script.title}
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</Accordion>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ScriptBrowser
|
||||||
@@ -2,7 +2,6 @@ import type { Config } from "tailwindcss"
|
|||||||
|
|
||||||
const svgToDataUri = require("mini-svg-data-uri");
|
const svgToDataUri = require("mini-svg-data-uri");
|
||||||
|
|
||||||
const colors = require("tailwindcss/colors");
|
|
||||||
const {
|
const {
|
||||||
default: flattenColorPalette,
|
default: flattenColorPalette,
|
||||||
} = require("tailwindcss/lib/util/flattenColorPalette");
|
} = require("tailwindcss/lib/util/flattenColorPalette");
|
||||||
|
|||||||
Reference in New Issue
Block a user