|
1 | 1 | 'use client'; |
2 | | -import { useState } from "react"; |
3 | | -import Image from "next/image"; // make sure this is at the top |
4 | | -import toolsData, { OS, PkgManager } from "@/data/tool"; |
5 | 2 |
|
| 3 | +import { useEffect, useState } from "react"; |
| 4 | +import * as XLSX from "xlsx"; |
| 5 | +import Image from "next/image"; |
| 6 | + |
| 7 | +type OS = "windows" | "macos" | "linux"; |
| 8 | +type WindowsPkg = "choco" | "winget" | "scoop"; |
| 9 | +type MacPkg = "homebrew"; |
| 10 | +type LinuxPkg = "apt" | "dnf" | "pacman"; |
| 11 | +type PkgManager = WindowsPkg | MacPkg | LinuxPkg; |
| 12 | + |
| 13 | +interface Tool { |
| 14 | + name: string; |
| 15 | + iconsrc: string; |
| 16 | + install: Partial<Record<PkgManager, string>>; |
| 17 | +} |
| 18 | + |
| 19 | +interface ToolCategory { |
| 20 | + category: string; |
| 21 | + tools: Tool[]; |
| 22 | +} |
6 | 23 |
|
7 | 24 | const osOptions: OS[] = ["windows", "macos", "linux"]; |
8 | 25 | const pkgManagers: Record<OS, PkgManager[]> = { |
9 | 26 | windows: ["choco", "winget", "scoop"], |
10 | 27 | macos: ["homebrew"], |
11 | | - linux: ["apt", "dnf", "pacman"] |
| 28 | + linux: ["apt", "dnf", "pacman"], |
12 | 29 | }; |
13 | 30 |
|
14 | | - |
15 | | - |
16 | 31 | export default function ScriptGenerator() { |
| 32 | + const [toolsData, setToolsData] = useState<ToolCategory[]>([]); |
17 | 33 | const [selectedOS, setSelectedOS] = useState<OS>("windows"); |
18 | 34 | const [selectedPkg, setSelectedPkg] = useState<PkgManager>("choco"); |
19 | 35 | const [selectedTools, setSelectedTools] = useState<string[]>([]); |
| 36 | + const [loading, setLoading] = useState(true); |
| 37 | + |
| 38 | + // Load and parse Excel on mount |
| 39 | + useEffect(() => { |
| 40 | + const fetchAndParse = async () => { |
| 41 | + try { |
| 42 | + const res = await fetch("/tools.xlsx"); |
| 43 | + const arrayBuffer = await res.arrayBuffer(); |
| 44 | + const workbook = XLSX.read(arrayBuffer, { type: "array" }); |
| 45 | + |
| 46 | + // Assuming sheet 1 contains your data in a suitable format. |
| 47 | + const sheetName = workbook.SheetNames[0]; |
| 48 | + const worksheet = workbook.Sheets[sheetName]; |
| 49 | + // Parse sheet to JSON |
| 50 | + const jsonData: any[] = XLSX.utils.sheet_to_json(worksheet, { defval: "" }); |
| 51 | + |
| 52 | + // Transform flat rows into structured ToolCategory[] |
| 53 | + // Adjust this logic according to your Excel structure. |
| 54 | + // Here is an example assuming columns: category, name, iconsrc, install_choco, install_apt, etc. |
| 55 | + |
| 56 | + const categoriesMap: Record<string, ToolCategory> = {}; |
| 57 | + |
| 58 | + jsonData.forEach((row) => { |
| 59 | + const category = row.category || "Uncategorized"; |
| 60 | + |
| 61 | + if (!categoriesMap[category]) { |
| 62 | + categoriesMap[category] = { category, tools: [] }; |
| 63 | + } |
| 64 | + |
| 65 | + const install: Partial<Record<PkgManager, string>> = {}; |
| 66 | + |
| 67 | + // Check all known package manager columns, adjust to your Excel headers |
| 68 | + const pkgCols = ["choco", "winget", "scoop", "homebrew", "apt", "dnf", "pacman"]; |
| 69 | + pkgCols.forEach((pkg) => { |
| 70 | + const colName = `install_${pkg}`; |
| 71 | + if (row[colName]) { |
| 72 | + install[pkg as PkgManager] = row[colName]; |
| 73 | + } |
| 74 | + }); |
| 75 | + |
| 76 | + categoriesMap[category].tools.push({ |
| 77 | + name: row.name, |
| 78 | + iconsrc: row.iconsrc, |
| 79 | + install, |
| 80 | + }); |
| 81 | + }); |
| 82 | + |
| 83 | + setToolsData(Object.values(categoriesMap)); |
| 84 | + setLoading(false); |
| 85 | + } catch (error) { |
| 86 | + console.error("Failed to load Excel data", error); |
| 87 | + setLoading(false); |
| 88 | + } |
| 89 | + }; |
| 90 | + |
| 91 | + fetchAndParse(); |
| 92 | + }, []); |
20 | 93 |
|
21 | 94 | const handleToolSelect = (toolName: string) => { |
22 | 95 | setSelectedTools((prev) => |
@@ -55,6 +128,14 @@ export default function ScriptGenerator() { |
55 | 128 | document.body.removeChild(link); |
56 | 129 | }; |
57 | 130 |
|
| 131 | + if (loading) { |
| 132 | + return ( |
| 133 | + <div className="text-white font-sans text-center mt-20"> |
| 134 | + Loading tools data... |
| 135 | + </div> |
| 136 | + ); |
| 137 | + } |
| 138 | + |
58 | 139 | return ( |
59 | 140 | <div className="bg-[#0d1117] min-h-screen text-white font-sans"> |
60 | 141 | <div className="max-w-screen mx-auto px-4 py-10"> |
@@ -128,13 +209,8 @@ export default function ScriptGenerator() { |
128 | 209 | onChange={() => handleToolSelect(tool.name)} |
129 | 210 | className="mb-3 w-5 h-5 accent-indigo-500" |
130 | 211 | /> |
131 | | - <Image |
132 | | - src={tool.iconsrc} |
133 | | - alt={tool.name} |
134 | | - width={40} |
135 | | - height={40} |
136 | | - className="object-contain mb-2" |
137 | | - /> |
| 212 | + <img src={tool.iconsrc} alt={tool.name} width={40} height={40} /> |
| 213 | + |
138 | 214 | <span className="text-sm text-center">{tool.name}</span> |
139 | 215 | </label> |
140 | 216 | ); |
|
0 commit comments