put the script browser inside a separate component for better readability

This commit is contained in:
Bram Suurd
2024-05-05 21:01:56 +02:00
parent f0c1fad282
commit 20e0cc76c5
4 changed files with 162 additions and 155 deletions

View File

@@ -5,47 +5,47 @@
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
--foreground: 20 14.3% 4.1%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--card-foreground: 20 14.3% 4.1%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;
--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--popover-foreground: 20 14.3% 4.1%;
--primary: 24.6 95% 53.1%;
--primary-foreground: 60 9.1% 97.8%;
--secondary: 60 4.8% 95.9%;
--secondary-foreground: 24 9.8% 10%;
--muted: 60 4.8% 95.9%;
--muted-foreground: 25 5.3% 44.7%;
--accent: 60 4.8% 95.9%;
--accent-foreground: 24 9.8% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 240 5.9% 90%;
--input: 240 5.9% 90%;
--ring: 240 5.9% 10%;
--destructive-foreground: 60 9.1% 97.8%;
--border: 20 5.9% 90%;
--input: 20 5.9% 90%;
--ring: 24.6 95% 53.1%;
--radius: 0.5rem;
}
.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
--card: 240 10% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 240 10% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 201 100% 38%;
--primary-foreground: 240 5.9% 10%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%;
--accent: 240 3.7% 15.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;
--ring: 240 4.9% 83.9%;
--background: 20 14.3% 4.1%;
--foreground: 60 9.1% 97.8%;
--card: 20 14.3% 4.1%;
--card-foreground: 60 9.1% 97.8%;
--popover: 20 14.3% 4.1%;
--popover-foreground: 60 9.1% 97.8%;
--primary: 20.5 90.2% 48.2%;
--primary-foreground: 60 9.1% 97.8%;
--secondary: 12 6.5% 15.1%;
--secondary-foreground: 60 9.1% 97.8%;
--muted: 12 6.5% 15.1%;
--muted-foreground: 24 5.4% 63.9%;
--accent: 12 6.5% 15.1%;
--accent-foreground: 60 9.1% 97.8%;
--destructive: 0 72.2% 50.6%;
--destructive-foreground: 60 9.1% 97.8%;
--border: 12 6.5% 15.1%;
--input: 12 6.5% 15.1%;
--ring: 20.5 90.2% 48.2%;
}
}
@layer base {
@@ -55,12 +55,4 @@
body {
@apply bg-background text-foreground;
}
}
[data-state="open"] .accordioncontent {
display: block;
}
[data-state="closed"] .accordioncontent {
display: none;
}
}

View File

@@ -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 { Category } from "@/lib/types";
import Link from "next/link";
import ScriptBrowser from "@/components/ScriptBrowser";
import Particles from "@/components/ui/particles";
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 (
<>
<Particles
@@ -64,62 +10,7 @@ export default function Page() {
quantity={100}
/>
<div className="mt-20 flex">
<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`}
>
<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>
<ScriptBrowser />
<div className="flex">
<div className="h-screen w-full">
<ScriptItem />

View 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

View File

@@ -2,7 +2,6 @@ import type { Config } from "tailwindcss"
const svgToDataUri = require("mini-svg-data-uri");
const colors = require("tailwindcss/colors");
const {
default: flattenColorPalette,
} = require("tailwindcss/lib/util/flattenColorPalette");