This commit is contained in:
Artyom Tsyrulnikov
2025-07-13 11:33:04 +03:00
parent f74f52f1a4
commit 137033ef7e
6 changed files with 3 additions and 3 deletions

View File

@@ -0,0 +1,112 @@
import { FC, useState } from 'react';
interface CellData {
value: string;
isSelected: boolean;
}
const Spreadsheet: FC = () => {
const [cells, setCells] = useState<CellData[][]>(() => {
// Создаем сетку 20x10 с пустыми ячейками
return Array(20).fill(null).map(() =>
Array(10).fill(null).map(() => ({ value: '', isSelected: false }))
);
});
const [selectedCell, setSelectedCell] = useState<{row: number, col: number} | null>(null);
const handleCellClick = (row: number, col: number) => {
setSelectedCell({ row, col });
};
const handleCellChange = (row: number, col: number, value: string) => {
setCells(prev => {
const newCells = [...prev];
newCells[row][col] = { ...newCells[row][col], value };
return newCells;
});
};
const getColumnLabel = (index: number) => {
return String.fromCharCode(65 + index); // A, B, C, ...
};
return (
<div className="w-full h-full bg-white">
{/* Formula bar */}
<div className="border-b border-gray-200 p-2 bg-white">
<div className="flex items-center space-x-2">
<div className="text-sm text-gray-600 min-w-[60px]">
{selectedCell ? `${getColumnLabel(selectedCell.col)}${selectedCell.row + 1}` : ''}
</div>
<div className="flex-1">
<input
type="text"
className="w-full px-2 py-1 text-sm border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="Введите формулу..."
value={selectedCell ? cells[selectedCell.row][selectedCell.col].value : ''}
onChange={(e) => {
if (selectedCell) {
handleCellChange(selectedCell.row, selectedCell.col, e.target.value);
}
}}
/>
</div>
</div>
</div>
{/* Spreadsheet */}
<div className="overflow-auto h-[calc(100vh-200px)]">
<table className="border-collapse">
<thead>
<tr>
{/* Empty corner cell */}
<th className="w-12 h-8 bg-gray-100 border border-gray-300 text-xs text-gray-600 font-medium sticky top-0 left-0 z-20"></th>
{/* Column headers */}
{Array.from({ length: 10 }, (_, i) => (
<th
key={i}
className="w-24 h-8 bg-gray-100 border border-gray-300 text-xs text-gray-600 font-medium text-center sticky top-0 z-10"
>
{getColumnLabel(i)}
</th>
))}
</tr>
</thead>
<tbody>
{cells.map((row, rowIndex) => (
<tr key={rowIndex}>
{/* Row header */}
<td className="w-12 h-8 bg-gray-100 border border-gray-300 text-xs text-gray-600 font-medium text-center sticky left-0 z-10">
{rowIndex + 1}
</td>
{/* Data cells */}
{row.map((cell, colIndex) => (
<td
key={colIndex}
className={`w-24 h-8 border border-gray-300 relative cursor-cell ${
selectedCell?.row === rowIndex && selectedCell?.col === colIndex
? 'bg-blue-100 border-blue-500 border-2'
: 'hover:bg-gray-50'
}`}
onClick={() => handleCellClick(rowIndex, colIndex)}
>
<input
type="text"
className="w-full h-full px-1 text-sm bg-transparent border-none outline-none resize-none"
value={cell.value}
onChange={(e) => handleCellChange(rowIndex, colIndex, e.target.value)}
onFocus={() => setSelectedCell({ row: rowIndex, col: colIndex })}
/>
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
</div>
);
};
export default Spreadsheet;

View File

@@ -0,0 +1 @@
export { default as Spreadsheet } from './Spreadsheet';

2
src/components/index.ts Normal file
View File

@@ -0,0 +1,2 @@
export { Spreadsheet } from "./Spreadsheet";