Table UI fix and XLSX library fix
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import * as XLSX from "xlsx";
|
||||
import ExcelJS from "exceljs";
|
||||
import { chemicalsApi } from "../lib/api";
|
||||
import type { ChemicalInventory } from "../shared/types";
|
||||
import { Card } from "./ui/card";
|
||||
@@ -282,15 +282,19 @@ export function Inventory() {
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
function handleDownloadExcel() {
|
||||
const wsData = [
|
||||
TABLE_COLUMNS.map(c => c.label),
|
||||
...filtered.map(item => TABLE_COLUMNS.map(c => item[c.key] ?? "")),
|
||||
];
|
||||
const ws = XLSX.utils.aoa_to_sheet(wsData);
|
||||
const wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, "Chemical Inventory");
|
||||
XLSX.writeFile(wb, "chemical_inventory.xlsx");
|
||||
async function handleDownloadExcel() {
|
||||
const wb = new ExcelJS.Workbook();
|
||||
const ws = wb.addWorksheet("Chemical Inventory");
|
||||
ws.addRow(TABLE_COLUMNS.map(c => c.label));
|
||||
filtered.forEach(item => ws.addRow(TABLE_COLUMNS.map(c => item[c.key] ?? "")));
|
||||
const buffer = await wb.xlsx.writeBuffer();
|
||||
const blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = "chemical_inventory.xlsx";
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
// ── derived ─────────────────────────────────────────────────────────────
|
||||
@@ -622,7 +626,7 @@ export function Inventory() {
|
||||
</div>
|
||||
</div>
|
||||
</DialogHeader>
|
||||
<div className="overflow-auto flex-1">
|
||||
<div className="table-scroll flex-1">
|
||||
<table className="text-xs border-collapse min-w-max">
|
||||
<thead className="sticky top-0 z-10 bg-muted">
|
||||
<tr>
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
"cmdk": "^1.1.1",
|
||||
"dotenv": "^17.3.1",
|
||||
"embla-carousel-react": "^8.6.0",
|
||||
"exceljs": "^4.4.0",
|
||||
"input-otp": "^1.4.2",
|
||||
"lucide-react": "^0.487.0",
|
||||
"next-themes": "^0.4.6",
|
||||
@@ -53,8 +54,7 @@
|
||||
"recharts": "^2.15.2",
|
||||
"sonner": "^2.0.3",
|
||||
"tailwind-merge": "^2.6.0",
|
||||
"vaul": "^1.1.2",
|
||||
"xlsx": "^0.18.5"
|
||||
"vaul": "^1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/vite": "^4.0.0",
|
||||
|
||||
@@ -198,3 +198,91 @@
|
||||
html {
|
||||
font-size: var(--font-size);
|
||||
}
|
||||
|
||||
.table-scroll {
|
||||
overflow: scroll;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.table-scroll::-webkit-scrollbar {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.table-scroll::-webkit-scrollbar-track {
|
||||
background: var(--muted);
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.table-scroll::-webkit-scrollbar-thumb {
|
||||
background: var(--muted-foreground);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 999px;
|
||||
min-width: 30px;
|
||||
min-height: 30px;
|
||||
}
|
||||
|
||||
.table-scroll::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--foreground);
|
||||
}
|
||||
|
||||
/* Hide all buttons by default, then selectively show the correct one per end */
|
||||
.table-scroll::-webkit-scrollbar-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Up arrow — top of vertical bar */
|
||||
.table-scroll::-webkit-scrollbar-button:vertical:decrement:start {
|
||||
display: block;
|
||||
background: var(--muted);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 999px 999px 0 0;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath d='M4 2 L7 6 L1 6 Z' fill='%23666'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 8px 8px;
|
||||
}
|
||||
|
||||
/* Down arrow — bottom of vertical bar */
|
||||
.table-scroll::-webkit-scrollbar-button:vertical:increment:end {
|
||||
display: block;
|
||||
background: var(--muted);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 0 0 999px 999px;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath d='M4 6 L7 2 L1 2 Z' fill='%23666'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 8px 8px;
|
||||
}
|
||||
|
||||
/* Left arrow — left end of horizontal bar */
|
||||
.table-scroll::-webkit-scrollbar-button:horizontal:decrement:start {
|
||||
display: block;
|
||||
background: var(--muted);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 999px 0 0 999px;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath d='M2 4 L6 1 L6 7 Z' fill='%23666'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 8px 8px;
|
||||
}
|
||||
|
||||
/* Right arrow — right end of horizontal bar */
|
||||
.table-scroll::-webkit-scrollbar-button:horizontal:increment:end {
|
||||
display: block;
|
||||
background: var(--muted);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 0 999px 999px 0;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath d='M6 4 L2 1 L2 7 Z' fill='%23666'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 8px 8px;
|
||||
}
|
||||
|
||||
.table-scroll::-webkit-scrollbar-button:hover {
|
||||
background: var(--border);
|
||||
}
|
||||
|
||||
.table-scroll::-webkit-scrollbar-corner {
|
||||
background: transparent;
|
||||
}
|
||||
Reference in New Issue
Block a user