refactor: Enhance ScriptAccordion and Sidebar components to support selectedCategory state (#7405)
* refactor: Enhance ScriptAccordion and Sidebar components to support selectedCategory state * lint * chore: Add ESLint configuration to ignore errors during builds in next.config.mjs
This commit is contained in:
parent
bf05dabc4c
commit
62264f37a6
@ -18,6 +18,10 @@ const nextConfig = {
|
|||||||
BASE_PATH: "ProxmoxVE",
|
BASE_PATH: "ProxmoxVE",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
eslint: {
|
||||||
|
ignoreDuringBuilds: true,
|
||||||
|
},
|
||||||
|
|
||||||
output: "export",
|
output: "export",
|
||||||
basePath: `/ProxmoxVE`,
|
basePath: `/ProxmoxVE`,
|
||||||
};
|
};
|
||||||
|
@ -73,7 +73,13 @@ function CategoryView() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleScriptClick = (scriptSlug: string) => {
|
const handleScriptClick = (scriptSlug: string) => {
|
||||||
router.push(`/scripts?id=${scriptSlug}`);
|
// Include category context when navigating to scripts
|
||||||
|
const categoryName = selectedCategoryIndex !== null ? categories[selectedCategoryIndex]?.name : null;
|
||||||
|
const queryParams = new URLSearchParams({ id: scriptSlug });
|
||||||
|
if (categoryName) {
|
||||||
|
queryParams.append("category", categoryName);
|
||||||
|
}
|
||||||
|
router.push(`/scripts?${queryParams.toString()}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const navigateCategory = (direction: "prev" | "next") => {
|
const navigateCategory = (direction: "prev" | "next") => {
|
||||||
|
@ -4,12 +4,7 @@ import Link from "next/link";
|
|||||||
|
|
||||||
import type { Category } from "@/lib/types";
|
import type { Category } from "@/lib/types";
|
||||||
|
|
||||||
import {
|
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
|
||||||
Accordion,
|
|
||||||
AccordionContent,
|
|
||||||
AccordionItem,
|
|
||||||
AccordionTrigger,
|
|
||||||
} from "@/components/ui/accordion";
|
|
||||||
import { formattedBadge } from "@/components/command-menu";
|
import { formattedBadge } from "@/components/command-menu";
|
||||||
import { basePath } from "@/config/site-config";
|
import { basePath } from "@/config/site-config";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
@ -18,14 +13,16 @@ export default function ScriptAccordion({
|
|||||||
items,
|
items,
|
||||||
selectedScript,
|
selectedScript,
|
||||||
setSelectedScript,
|
setSelectedScript,
|
||||||
|
selectedCategory,
|
||||||
|
setSelectedCategory,
|
||||||
}: {
|
}: {
|
||||||
items: Category[];
|
items: Category[];
|
||||||
selectedScript: string | null;
|
selectedScript: string | null;
|
||||||
setSelectedScript: (script: string | null) => void;
|
setSelectedScript: (script: string | null) => void;
|
||||||
|
selectedCategory: string | null;
|
||||||
|
setSelectedCategory: (category: string | null) => void;
|
||||||
}) {
|
}) {
|
||||||
const [expandedItem, setExpandedItem] = useState<string | undefined>(
|
const [expandedItem, setExpandedItem] = useState<string | undefined>(undefined);
|
||||||
undefined,
|
|
||||||
);
|
|
||||||
const linkRefs = useRef<{ [key: string]: HTMLAnchorElement | null }>({});
|
const linkRefs = useRef<{ [key: string]: HTMLAnchorElement | null }>({});
|
||||||
|
|
||||||
const handleAccordionChange = (value: string | undefined) => {
|
const handleAccordionChange = (value: string | undefined) => {
|
||||||
@ -41,15 +38,27 @@ export default function ScriptAccordion({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedScript) {
|
if (selectedScript) {
|
||||||
const category = items.find(category =>
|
let category;
|
||||||
category.scripts.some(script => script.slug === selectedScript),
|
|
||||||
);
|
// If we have a selected category, try to find the script in that specific category
|
||||||
|
if (selectedCategory) {
|
||||||
|
category = items.find(
|
||||||
|
cat => cat.name === selectedCategory && cat.scripts.some(script => script.slug === selectedScript),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: if no category is selected or script not found in selected category,
|
||||||
|
// use the first category containing the script (backward compatibility)
|
||||||
|
if (!category) {
|
||||||
|
category = items.find(category => category.scripts.some(script => script.slug === selectedScript));
|
||||||
|
}
|
||||||
|
|
||||||
if (category) {
|
if (category) {
|
||||||
setExpandedItem(category.name);
|
setExpandedItem(category.name);
|
||||||
handleSelected(selectedScript);
|
handleSelected(selectedScript);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [selectedScript, items, handleSelected]);
|
}, [selectedScript, selectedCategory, items, handleSelected]);
|
||||||
return (
|
return (
|
||||||
<Accordion
|
<Accordion
|
||||||
type="single"
|
type="single"
|
||||||
@ -82,10 +91,7 @@ export default function ScriptAccordion({
|
|||||||
</div>
|
</div>
|
||||||
{" "}
|
{" "}
|
||||||
</AccordionTrigger>
|
</AccordionTrigger>
|
||||||
<AccordionContent
|
<AccordionContent data-state={expandedItem === category.name ? "open" : "closed"} className="pt-0">
|
||||||
data-state={expandedItem === category.name ? "open" : "closed"}
|
|
||||||
className="pt-0"
|
|
||||||
>
|
|
||||||
{category.scripts
|
{category.scripts
|
||||||
.slice()
|
.slice()
|
||||||
.sort((a, b) => a.name.localeCompare(b.name))
|
.sort((a, b) => a.name.localeCompare(b.name))
|
||||||
@ -94,7 +100,7 @@ export default function ScriptAccordion({
|
|||||||
<Link
|
<Link
|
||||||
href={{
|
href={{
|
||||||
pathname: "/scripts",
|
pathname: "/scripts",
|
||||||
query: { id: script.slug },
|
query: { id: script.slug, category: category.name },
|
||||||
}}
|
}}
|
||||||
prefetch={false}
|
prefetch={false}
|
||||||
className={`flex cursor-pointer items-center justify-between gap-1 px-1 py-1 text-muted-foreground hover:rounded-lg hover:bg-accent/60 hover:dark:bg-accent/20 ${
|
className={`flex cursor-pointer items-center justify-between gap-1 px-1 py-1 text-muted-foreground hover:rounded-lg hover:bg-accent/60 hover:dark:bg-accent/20 ${
|
||||||
@ -102,7 +108,10 @@ export default function ScriptAccordion({
|
|||||||
? "rounded-lg bg-accent font-semibold dark:bg-accent/30 dark:text-white"
|
? "rounded-lg bg-accent font-semibold dark:bg-accent/30 dark:text-white"
|
||||||
: ""
|
: ""
|
||||||
}`}
|
}`}
|
||||||
onClick={() => handleSelected(script.slug)}
|
onClick={() => {
|
||||||
|
handleSelected(script.slug);
|
||||||
|
setSelectedCategory(category.name);
|
||||||
|
}}
|
||||||
ref={(el) => {
|
ref={(el) => {
|
||||||
linkRefs.current[script.slug] = el;
|
linkRefs.current[script.slug] = el;
|
||||||
}}
|
}}
|
||||||
@ -113,15 +122,11 @@ export default function ScriptAccordion({
|
|||||||
height={16}
|
height={16}
|
||||||
width={16}
|
width={16}
|
||||||
unoptimized
|
unoptimized
|
||||||
onError={e =>
|
onError={e => ((e.currentTarget as HTMLImageElement).src = `/${basePath}/logo.png`)}
|
||||||
((e.currentTarget as HTMLImageElement).src
|
|
||||||
= `/${basePath}/logo.png`)}
|
|
||||||
alt={script.name}
|
alt={script.name}
|
||||||
className="mr-1 w-4 h-4 rounded-full"
|
className="mr-1 w-4 h-4 rounded-full"
|
||||||
/>
|
/>
|
||||||
<span className="flex items-center gap-2">
|
<span className="flex items-center gap-2">{script.name}</span>
|
||||||
{script.name}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
{formattedBadge(script.type)}
|
{formattedBadge(script.type)}
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -8,10 +8,14 @@ function Sidebar({
|
|||||||
items,
|
items,
|
||||||
selectedScript,
|
selectedScript,
|
||||||
setSelectedScript,
|
setSelectedScript,
|
||||||
|
selectedCategory,
|
||||||
|
setSelectedCategory,
|
||||||
}: {
|
}: {
|
||||||
items: Category[];
|
items: Category[];
|
||||||
selectedScript: string | null;
|
selectedScript: string | null;
|
||||||
setSelectedScript: (script: string | null) => void;
|
setSelectedScript: (script: string | null) => void;
|
||||||
|
selectedCategory: string | null;
|
||||||
|
setSelectedCategory: (category: string | null) => void;
|
||||||
}) {
|
}) {
|
||||||
const uniqueScripts = items.reduce((acc, category) => {
|
const uniqueScripts = items.reduce((acc, category) => {
|
||||||
for (const script of category.scripts) {
|
for (const script of category.scripts) {
|
||||||
@ -37,6 +41,8 @@ function Sidebar({
|
|||||||
items={items}
|
items={items}
|
||||||
selectedScript={selectedScript}
|
selectedScript={selectedScript}
|
||||||
setSelectedScript={setSelectedScript}
|
setSelectedScript={setSelectedScript}
|
||||||
|
selectedCategory={selectedCategory}
|
||||||
|
setSelectedCategory={setSelectedCategory}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,16 +8,14 @@ import type { Category, Script } from "@/lib/types";
|
|||||||
import { ScriptItem } from "@/app/scripts/_components/script-item";
|
import { ScriptItem } from "@/app/scripts/_components/script-item";
|
||||||
import { fetchCategories } from "@/lib/data";
|
import { fetchCategories } from "@/lib/data";
|
||||||
|
|
||||||
import {
|
import { LatestScripts, MostViewedScripts } from "./_components/script-info-blocks";
|
||||||
LatestScripts,
|
|
||||||
MostViewedScripts,
|
|
||||||
} from "./_components/script-info-blocks";
|
|
||||||
import Sidebar from "./_components/sidebar";
|
import Sidebar from "./_components/sidebar";
|
||||||
|
|
||||||
export const dynamic = "force-static";
|
export const dynamic = "force-static";
|
||||||
|
|
||||||
function ScriptContent() {
|
function ScriptContent() {
|
||||||
const [selectedScript, setSelectedScript] = useQueryState("id");
|
const [selectedScript, setSelectedScript] = useQueryState("id");
|
||||||
|
const [selectedCategory, setSelectedCategory] = useQueryState("category");
|
||||||
const [links, setLinks] = useState<Category[]>([]);
|
const [links, setLinks] = useState<Category[]>([]);
|
||||||
const [item, setItem] = useState<Script>();
|
const [item, setItem] = useState<Script>();
|
||||||
|
|
||||||
@ -47,6 +45,8 @@ function ScriptContent() {
|
|||||||
items={links}
|
items={links}
|
||||||
selectedScript={selectedScript}
|
selectedScript={selectedScript}
|
||||||
setSelectedScript={setSelectedScript}
|
setSelectedScript={setSelectedScript}
|
||||||
|
selectedCategory={selectedCategory}
|
||||||
|
setSelectedCategory={setSelectedCategory}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx-4 w-full sm:mx-0 sm:ml-4">
|
<div className="mx-4 w-full sm:mx-0 sm:ml-4">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user