Skip to content

Commit 8feb84e

Browse files
committed
feat: add fullscreen overlay
1 parent 81840d9 commit 8feb84e

File tree

1 file changed

+124
-15
lines changed

1 file changed

+124
-15
lines changed

app/dataTable.tsx

Lines changed: 124 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
} from "ag-grid-community";
88
import * as XLSX from "xlsx";
99
import * as cptable from "codepage";
10+
import ReactDOM from "react-dom";
1011

1112
const theme = themeQuartz.withParams({
1213
borderRadius: 6,
@@ -26,13 +27,6 @@ XLSX.set_cptable(cptable);
2627
// Register all community modules for AG Grid v34+
2728
ModuleRegistry.registerModules([AllCommunityModule]);
2829

29-
function decodeHTMLEntities(text: string) {
30-
if (typeof text !== "string") return text;
31-
const txt = document.createElement("textarea");
32-
txt.innerHTML = text;
33-
return txt.value;
34-
}
35-
3630
export function DataTable({
3731
fileUrl,
3832
cells,
@@ -49,7 +43,6 @@ export function DataTable({
4943
const [rowData, setRowData] = useState<Array<any>>([]);
5044
const [colHeaders, setColHeaders] = useState<Array<string>>([]);
5145
const [loading, setLoading] = useState<boolean>(!!fileUrl);
52-
5346
useEffect(() => {
5447
if (cells && cells.length > 1) {
5548
let rows = cells.map((row: any) =>
@@ -125,7 +118,6 @@ export function DataTable({
125118
pinned: "left" as const,
126119
width: 35,
127120
suppressMovable: true,
128-
suppressMenu: true,
129121
suppressColumnsToolPanel: true,
130122
suppressFiltersToolPanel: true,
131123
suppressAutoSize: true,
@@ -165,14 +157,10 @@ export function DataTable({
165157
if (loading) return <div>Loading...</div>;
166158

167159
return (
168-
<div
169-
style={{ height: 300 }}
170-
// style={{ maxHeight: 300, overflow: "auto" }}
171-
>
160+
<FullscreenOverlay>
172161
<AgGridReact
173162
theme={theme}
174163
rowData={rowData}
175-
// domLayout="autoHeight"
176164
autoSizeStrategy={{
177165
type: "fitCellContents",
178166
defaultMaxWidth: 300,
@@ -188,10 +176,17 @@ export function DataTable({
188176
: {}
189177
}
190178
/>
191-
</div>
179+
</FullscreenOverlay>
192180
);
193181
}
194182

183+
function decodeHTMLEntities(text: string) {
184+
if (typeof text !== "string") return text;
185+
const txt = document.createElement("textarea");
186+
txt.innerHTML = text;
187+
return txt.value;
188+
}
189+
195190
function HeaderWithSelect({
196191
displayName,
197192
headerSelect,
@@ -246,3 +241,117 @@ function HeaderWithSelect({
246241
</div>
247242
);
248243
}
244+
245+
function FullscreenOverlay({ children }: { children: React.ReactNode }) {
246+
const [fullscreen, setFullscreen] = useState(false);
247+
248+
// Prevent background scroll when fullscreen is open
249+
useEffect(() => {
250+
if (fullscreen) {
251+
const original = document.body.style.overflow;
252+
document.body.style.overflow = "hidden";
253+
// Add ESC key handler
254+
const handleKeyDown = (e: KeyboardEvent) => {
255+
if (e.key === "Escape") {
256+
setFullscreen(false);
257+
}
258+
};
259+
window.addEventListener("keydown", handleKeyDown);
260+
return () => {
261+
document.body.style.overflow = original;
262+
window.removeEventListener("keydown", handleKeyDown);
263+
};
264+
}
265+
}, [fullscreen]);
266+
267+
if (fullscreen) {
268+
let overlay = (
269+
<div
270+
style={{
271+
position: "fixed",
272+
top: 0,
273+
left: 0,
274+
width: "100vw",
275+
height: "100vh",
276+
zIndex: 999999,
277+
background: "rgba(255,255,255,0.85)",
278+
backdropFilter: "blur(16px) saturate(180%)",
279+
WebkitBackdropFilter: "blur(16px) saturate(180%)",
280+
display: "flex",
281+
alignItems: "center",
282+
justifyContent: "center",
283+
}}
284+
>
285+
<div
286+
style={{
287+
width: "80%",
288+
height: "80%",
289+
position: "relative",
290+
}}
291+
>
292+
{/* Close button */}
293+
<button
294+
aria-label="Close fullscreen table"
295+
onClick={() => setFullscreen(false)}
296+
style={{
297+
position: "absolute",
298+
top: -16,
299+
right: -16,
300+
zIndex: 1001,
301+
borderRadius: "50%",
302+
width: 40,
303+
height: 40,
304+
background: "#fff",
305+
border: "1px solid #ccc",
306+
boxShadow: "0 2px 8px rgba(0,0,0,0.08)",
307+
display: "flex",
308+
alignItems: "center",
309+
justifyContent: "center",
310+
cursor: "pointer",
311+
fontSize: 24,
312+
}}
313+
>
314+
<i className="fa fa-times" aria-hidden="true"></i>
315+
</button>
316+
{/* Table */}
317+
{children}
318+
</div>
319+
</div>
320+
);
321+
return ReactDOM.createPortal(overlay, document.body);
322+
} else {
323+
return (
324+
<div style={{ position: "relative" }}>
325+
{/* Table */}
326+
<div style={{ height: 300 }}>{children}</div>
327+
{/* Expand button */}
328+
<button
329+
aria-label="Expand table"
330+
onClick={() => setFullscreen(true)}
331+
style={{
332+
position: "absolute",
333+
bottom: -10,
334+
right: -10,
335+
zIndex: 2,
336+
borderRadius: "50%",
337+
width: 28,
338+
height: 28,
339+
background: "#fff",
340+
border: "1px solid #ccc",
341+
boxShadow: "0 2px 8px rgba(0,0,0,0.08)",
342+
display: "flex",
343+
alignItems: "center",
344+
justifyContent: "center",
345+
cursor: "pointer",
346+
}}
347+
>
348+
{/* FontAwesome expand icon */}
349+
<i
350+
className="fa-solid fa-sm fa-up-right-and-down-left-from-center"
351+
aria-hidden="true"
352+
></i>
353+
</button>
354+
</div>
355+
);
356+
}
357+
}

0 commit comments

Comments
 (0)