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 { @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;
}

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 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 />

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 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");