diff --git a/package-lock.json b/package-lock.json index f230311..73ce923 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "xlsx": "^0.18.5" }, "devDependencies": { - "@eslint/js": "^9.30.1", + "@eslint/js": "^9.39.2", "@types/file-saver": "^2.0.7", "@types/papaparse": "^5.3.16", "@types/react": "^19.1.8", @@ -95,6 +95,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", "dev": true, + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", @@ -808,10 +809,11 @@ } }, "node_modules/@eslint/js": { - "version": "9.32.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.32.0.tgz", - "integrity": "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -1851,6 +1853,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.9.tgz", "integrity": "sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA==", "devOptional": true, + "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -1860,6 +1863,7 @@ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.7.tgz", "integrity": "sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==", "devOptional": true, + "peer": true, "peerDependencies": { "@types/react": "^19.0.0" } @@ -1907,6 +1911,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.38.0.tgz", "integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==", "dev": true, + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.38.0", "@typescript-eslint/types": "8.38.0", @@ -2146,6 +2151,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2547,6 +2553,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001726", "electron-to-chromium": "^1.5.173", @@ -2946,7 +2953,6 @@ "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", "dev": true, "optional": true, - "peer": true, "engines": { "node": ">=8" } @@ -3245,6 +3251,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.32.0.tgz", "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", "dev": true, + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -3443,6 +3450,19 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/@eslint/js": { + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.32.0.tgz", + "integrity": "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, "node_modules/espree": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", @@ -4476,17 +4496,6 @@ "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/jiti": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", - "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", - "dev": true, - "optional": true, - "peer": true, - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4602,36 +4611,6 @@ "node": ">= 0.8.0" } }, - "node_modules/lightningcss": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", - "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-darwin-arm64": "1.30.1", - "lightningcss-darwin-x64": "1.30.1", - "lightningcss-freebsd-x64": "1.30.1", - "lightningcss-linux-arm-gnueabihf": "1.30.1", - "lightningcss-linux-arm64-gnu": "1.30.1", - "lightningcss-linux-arm64-musl": "1.30.1", - "lightningcss-linux-x64-gnu": "1.30.1", - "lightningcss-linux-x64-musl": "1.30.1", - "lightningcss-win32-arm64-msvc": "1.30.1", - "lightningcss-win32-x64-msvc": "1.30.1" - } - }, "node_modules/lightningcss-darwin-arm64": { "version": "1.30.1", "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", @@ -4644,7 +4623,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -4665,7 +4643,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -4686,7 +4663,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -4707,7 +4683,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -4728,7 +4703,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -4749,7 +4723,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -4770,7 +4743,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -4791,7 +4763,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -4812,7 +4783,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -4833,7 +4803,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -5334,6 +5303,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -5511,6 +5481,7 @@ "version": "19.1.1", "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -5519,6 +5490,7 @@ "version": "19.1.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", + "peer": true, "dependencies": { "scheduler": "^0.26.0" }, @@ -6296,6 +6268,7 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", "dev": true, + "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -6492,6 +6465,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -6646,6 +6620,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz", "integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==", "dev": true, + "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", diff --git a/package.json b/package.json index 52079d4..481b0b1 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "xlsx": "^0.18.5" }, "devDependencies": { - "@eslint/js": "^9.30.1", + "@eslint/js": "^9.39.2", "@types/file-saver": "^2.0.7", "@types/papaparse": "^5.3.16", "@types/react": "^19.1.8", diff --git a/src/App.tsx b/src/App.tsx index 815e1b9..c719d55 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,9 @@ import React, { useRef, useCallback, useState } from 'react' -import { Upload, Download, Plus, Minus, Palette, Copy, FileImage, RefreshCw, Table, MousePointer2, ArrowBigDown, ArrowBigUp, ArrowBigLeft, ArrowBigRight, Type } from 'lucide-react' +import { + Upload, Download, Plus, Minus, Palette, Copy, FileImage, RefreshCw, + Table, MousePointer2, ArrowBigDown, ArrowBigUp, ArrowBigLeft, ArrowBigRight, + Type +} from 'lucide-react' import { FancyTable } from './components/FancyTable.tsx' import { BackgroundWrapper } from './components/BackgroundWrapper.tsx' import { BackgroundControls } from './components/BackgroundControls.tsx' @@ -15,6 +19,8 @@ import { defaultThemes, getThemeById } from './lib/themes.ts' import { downloadFile, cn } from './lib/utils.ts' import html2canvas from 'html2canvas' import { saveAs } from 'file-saver' +import type { CellPosition, CellAlignment, CellType, CellEffect } from './types/table.ts' +import { TableContextMenu } from './components/TableContextMenu.tsx' function App() { const { @@ -23,12 +29,14 @@ function App() { updateTheme, resetTable, addRow, - addColumn + addColumn, + updateCell } = useTableData() const [backgroundColor, setBackgroundColor] = useState(undefined) const [backgroundImage, setBackgroundImage] = useState(undefined) const [hideSelectionForExport, setHideSelectionForExport] = useState(false) + const [selectedCell, setSelectedCell] = useState(null) const [cropSettings, setCropSettings] = useState({ top: 20, right: 20, @@ -37,6 +45,8 @@ function App() { enabled: false }) + const [contextMenu, setContextMenu] = useState<{ x: number, y: number, cell: CellPosition } | null>(null) + const fileInputRef = useRef(null) const tableRef = useRef(null) @@ -190,6 +200,18 @@ function App() { } }, [tableData.name, cropSettings, setCropSettings]) + const handleContextMenu = useCallback((e: React.MouseEvent, cell: CellPosition) => { + e.preventDefault() + setContextMenu({ x: e.clientX, y: e.clientY, cell }) + }, []) + + const handleUpdateCell = useCallback((updates: { type?: CellType, align?: CellAlignment, effect?: CellEffect }) => { + if (contextMenu) { + updateCell(contextMenu.cell.rowIndex, contextMenu.cell.columnIndex, updates) + setContextMenu(null) + } + }, [contextMenu, updateCell]) + const handleThemeChange = useCallback((themeId: string) => { const theme = getThemeById(themeId) updateTheme(theme) @@ -369,6 +391,7 @@ function App() { + {/* Background Controls */}
+ {contextMenu && ( + setContextMenu(null)} + onUpdateCell={handleUpdateCell} + /> + )} +
diff --git a/src/components/FancyTable.tsx b/src/components/FancyTable.tsx index c608b7d..024a626 100644 --- a/src/components/FancyTable.tsx +++ b/src/components/FancyTable.tsx @@ -1,4 +1,4 @@ -import React, { useState, useCallback, useRef } from 'react' +import React, { useState, useCallback, useRef, useEffect } from 'react' import type { TableData, CellPosition, TableTheme } from '../types/table.ts' import { TableCell } from './TableCell.tsx' import { cn } from '../lib/utils.ts' @@ -6,6 +6,8 @@ import { cn } from '../lib/utils.ts' interface FancyTableProps { data: TableData onDataChange: (data: TableData) => void + onSelectionChange?: (cell: CellPosition | null) => void + onContextMenu?: (e: React.MouseEvent, cell: CellPosition) => void className?: string hideSelection?: boolean } @@ -13,6 +15,8 @@ interface FancyTableProps { export const FancyTable: React.FC = ({ data, onDataChange, + onSelectionChange, + onContextMenu, className, hideSelection = false }) => { @@ -22,6 +26,10 @@ export const FancyTable: React.FC = ({ const tableRef = useRef(null) const containerRef = useRef(null) + useEffect(() => { + onSelectionChange?.(selectedCell) + }, [selectedCell, onSelectionChange]) + const handleCellClick = useCallback((rowIndex: number, columnIndex: number) => { setSelectedCell({ rowIndex, columnIndex }) setEditingCell(null) @@ -32,6 +40,11 @@ export const FancyTable: React.FC = ({ } }, []) + const handleCellContextMenu = useCallback((e: React.MouseEvent, rowIndex: number, columnIndex: number) => { + setSelectedCell({ rowIndex, columnIndex }) + onContextMenu?.(e, { rowIndex, columnIndex }) + }, [onContextMenu]) + const handleCellDoubleClick = useCallback((rowIndex: number, columnIndex: number) => { setSelectedCell({ rowIndex, columnIndex }) setEditingCell({ rowIndex, columnIndex }) @@ -177,6 +190,7 @@ export const FancyTable: React.FC = ({ : null } onCellClick={() => handleCellClick(rowIndex, columnIndex)} + onCellContextMenu={(e) => handleCellContextMenu(e, rowIndex, columnIndex)} onCellDoubleClick={() => handleCellDoubleClick(rowIndex, columnIndex)} onCellChange={(value) => handleCellChange(rowIndex, columnIndex, value)} style={getCellStyles(data.theme, rowIndex % 2 === 1)} diff --git a/src/components/TableCell.tsx b/src/components/TableCell.tsx index 796dee5..06d028f 100644 --- a/src/components/TableCell.tsx +++ b/src/components/TableCell.tsx @@ -1,6 +1,7 @@ import React, { useState, useRef, useEffect } from 'react' -import type { TableCell as TableCellType, CellType } from '../types/table.ts' +import type { TableCell as TableCellType, CellType, CellAlignment } from '../types/table.ts' import { formatCurrency, formatNumber, parseNumber, cn } from '../lib/utils.ts' +import { Flame, TrendingUp, TrendingDown } from 'lucide-react' interface TableCellProps { cell: TableCellType @@ -8,6 +9,7 @@ interface TableCellProps { isEditing: boolean editingStartedWithChar?: string | null onCellClick: () => void + onCellContextMenu?: (e: React.MouseEvent) => void onCellDoubleClick: () => void onCellChange: (value: string | number) => void style?: React.CSSProperties @@ -19,6 +21,7 @@ export const TableCell: React.FC = ({ isEditing, editingStartedWithChar, onCellClick, + onCellContextMenu, onCellDoubleClick, onCellChange, style @@ -91,14 +94,46 @@ export const TableCell: React.FC = ({ } } - const getCellAlignment = (type: CellType): string => { + const getCellAlignment = (type: CellType, align?: CellAlignment): string => { + if (align) { + switch (align) { + case 'left': return 'text-left justify-start' + case 'center': return 'text-center justify-center' + case 'right': return 'text-right justify-end' + } + } + switch (type) { case 'number': case 'currency': case 'percentage': - return 'text-right' + return 'text-right justify-end' default: - return 'text-left' + return 'text-left justify-start' + } + } + + const getEffectContent = () => { + if (!cell.effect || cell.effect === 'none') return null + + switch (cell.effect) { + case 'hot': + return + case 'top': + return + case 'low': + return + case 'badge': + return ( + + {cell.badgeText || 'BADGE'} + + ) + default: + return null } } @@ -121,7 +156,8 @@ export const TableCell: React.FC = ({ style={{ fontFamily: 'inherit', fontSize: 'inherit', - color: 'inherit' + color: 'inherit', + textAlign: cell.align || (['number', 'currency', 'percentage'].includes(cell.type) ? 'right' : 'left') }} /> @@ -133,16 +169,17 @@ export const TableCell: React.FC = ({ className={cn( 'relative cursor-cell border border-gray-300 transition-all duration-150', isSelected && 'ring-2 ring-inset ring-blue-500', - getCellAlignment(cell.type), 'hover:bg-black/5' )} style={style} onClick={onCellClick} + onContextMenu={onCellContextMenu} onDoubleClick={onCellDoubleClick} > -
+
{formatCellValue(cell.value, cell.type)} + {getEffectContent()}
) -} \ No newline at end of file +} diff --git a/src/components/TableContextMenu.tsx b/src/components/TableContextMenu.tsx new file mode 100644 index 0000000..5c9a2f4 --- /dev/null +++ b/src/components/TableContextMenu.tsx @@ -0,0 +1,88 @@ +import React from 'react' +import { + AlignLeft, AlignCenter, AlignRight, + Type, Hash, DollarSign, Percent, Calendar, + Flame, TrendingUp, TrendingDown, Badge, X +} from 'lucide-react' +import { Button } from './ui/button.tsx' +import type { CellType, CellAlignment, CellEffect } from '../types/table.ts' + +interface TableContextMenuProps { + x: number + y: number + onClose: () => void + onUpdateCell: (updates: { type?: CellType, align?: CellAlignment, effect?: CellEffect }) => void +} + +export const TableContextMenu: React.FC = ({ x, y, onClose, onUpdateCell }) => { + React.useEffect(() => { + const handleClickOutside = () => onClose() + document.addEventListener('click', handleClickOutside) + return () => document.removeEventListener('click', handleClickOutside) + }, [onClose]) + + return ( +
e.stopPropagation()} + > +
+
Alignment
+
+ + + +
+ +
+ +
Type
+
+ + + + + +
+ +
+ +
Effect
+
+ + + + + +
+
+
+ ) +} diff --git a/src/hooks/useTableData.ts b/src/hooks/useTableData.ts index dc34837..96050b5 100644 --- a/src/hooks/useTableData.ts +++ b/src/hooks/useTableData.ts @@ -1,5 +1,5 @@ import { useState, useCallback } from 'react' -import type { TableData, TableTheme } from '../types/table.ts' +import type { TableData, TableTheme, TableCell } from '../types/table.ts' import { createEmptyTable } from '../lib/fileUtils.ts' export const useTableData = (initialData?: TableData) => { @@ -81,6 +81,26 @@ export const useTableData = (initialData?: TableData) => { }) }, []) + const updateCell = useCallback((rowIndex: number, columnIndex: number, updates: Partial) => { + setTableData(prev => { + const newRows = [...prev.rows] + if (newRows[rowIndex] && newRows[rowIndex].cells[columnIndex]) { + newRows[rowIndex] = { + ...newRows[rowIndex], + cells: [...newRows[rowIndex].cells] + } + newRows[rowIndex].cells[columnIndex] = { + ...newRows[rowIndex].cells[columnIndex], + ...updates + } + } + return { + ...prev, + rows: newRows + } + }) + }, []) + return { tableData, updateTableData, @@ -89,6 +109,7 @@ export const useTableData = (initialData?: TableData) => { addRow, addColumn, removeRow, - removeColumn + removeColumn, + updateCell } } \ No newline at end of file diff --git a/src/lib/themes.ts b/src/lib/themes.ts index f01f43a..9c13d27 100644 --- a/src/lib/themes.ts +++ b/src/lib/themes.ts @@ -96,6 +96,44 @@ export const defaultThemes: TableTheme[] = [ wrapperPadding: '60px', tableShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.25), 0 0 0 1px rgba(255, 255, 255, 0.1)' }, + { + id: 'fire-theme', + name: 'Fire', + background: 'linear-gradient(135deg, #4a0404 0%, #9e1a1a 100%)', + headerBackground: '#7f1d1d', + borderColor: '#b91c1c', + textColor: '#fef2f2', + headerTextColor: '#ffffff', + alternateRowBackground: 'rgba(255, 69, 0, 0.1)', + cellPadding: '14px 18px', + borderRadius: '8px', + fontFamily: '"Poppins", sans-serif', + fontSize: '14px', + shadows: true, + gradients: true, + wrapperBackground: 'linear-gradient(135deg, #1c1917 0%, #7f1d1d 100%)', + wrapperPadding: '60px', + tableShadow: '0 25px 50px -12px rgba(220, 38, 38, 0.3), 0 0 0 1px rgba(239, 68, 68, 0.2)' + }, + { + id: 'ice-theme', + name: 'Ice', + background: 'linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%)', + headerBackground: '#bae6fd', + borderColor: '#7dd3fc', + textColor: '#0c4a6e', + headerTextColor: '#0369a1', + alternateRowBackground: 'rgba(186, 230, 253, 0.3)', + cellPadding: '14px 18px', + borderRadius: '8px', + fontFamily: '"Inter", sans-serif', + fontSize: '14px', + shadows: true, + gradients: true, + wrapperBackground: 'linear-gradient(135deg, #0f172a 0%, #0369a1 100%)', + wrapperPadding: '60px', + tableShadow: '0 25px 50px -12px rgba(56, 189, 248, 0.25), 0 0 0 1px rgba(125, 211, 252, 0.2)' + }, { id: 'minimalist', name: 'Minimalist', diff --git a/src/types/table.ts b/src/types/table.ts index 019249a..eabbd9b 100644 --- a/src/types/table.ts +++ b/src/types/table.ts @@ -1,9 +1,15 @@ export type CellType = 'text' | 'number' | 'currency' | 'percentage' | 'date' +export type CellAlignment = 'left' | 'center' | 'right' +export type CellEffect = 'none' | 'hot' | 'top' | 'low' | 'badge' export interface TableCell { id: string value: string | number type: CellType + align?: CellAlignment + effect?: CellEffect + badgeText?: string + badgeColor?: string format?: { currency?: string decimals?: number