"use client"; import { useState, useRef, useEffect } from 'react'; import { Bold, Italic, Underline as UnderlineIcon, AlignLeft, AlignCenter, AlignRight, AlignJustify, Table as TableIcon, Plus, Minus, Trash2, Palette, Highlighter, ChevronDown, Search, Copy, PieChart, BarChart3, LineChart, Sigma, Filter, DollarSign, Percent, WrapText, Merge, Split, Grid, List, Columns, Rows, PlusSquare, MinusSquare, Table2, ZoomIn as ZoomInIcon, ZoomOut as ZoomOutIcon, Cat as CatIcon, TextIcon, CpuIcon, IceCreamCone, DnaIcon } from 'lucide-react'; import { createUniver, defaultTheme, LocaleType, merge } from '@univerjs/presets'; import { UniverSheetsCorePreset } from '@univerjs/presets/preset-sheets-core'; import UniverPresetSheetsCoreEnUS from '@univerjs/presets/preset-sheets-core/locales/en-US'; import '@univerjs/presets/lib/styles/preset-sheets-core.css'; import './styles.css'; // Import your custom styles const RibbonTab = ({ label, isActive, onClick, children }) => (
{isActive &&
{children}
}
); const RibbonGroup = ({ title, children }) => (
{children}
{title}
); // @ts-ignore const RibbonButton = ({ icon: Icon, label, onClick, isActive = undefined, size = 'medium', dropdown = false }) => ( ); // @ts-ignore const RibbonDropdownButton = ({ icon: Icon, label, onClick, isActive = undefined, children }) => (
{children}
); // @ts-ignore const RibbonSplitButton = ({ icon: Icon, label, onClick, dropdownOnClick, isActive }) => (
); export default function Lotus123Clone() { // @ts-ignore const [fileName, setFileName] = useState('Sales Report'); const [activeTab, setActiveTab] = useState('home'); // @ts-ignore const [formulaMode, setFormulaMode] = useState('@'); const [commandMode, setCommandMode] = useState(false); // @ts-ignore const [currentCell, setCurrentCell] = useState('A1'); const [cellContent, setCellContent] = useState(''); const [zoomLevel, setZoomLevel] = useState(100); const [showSampleData, setShowSampleData] = useState(false); const univerRef = useRef(null); const containerRef = useRef(null); useEffect(() => { const { univerAPI } = createUniver({ locale: LocaleType.EN_US, locales: { [LocaleType.EN_US]: merge( {}, UniverPresetSheetsCoreEnUS, ), }, theme: defaultTheme, presets: [ UniverSheetsCorePreset({ container: containerRef.current, }), ], }); // Create a sample workbook with some data const workbook = univerAPI.createWorkbook({ name: fileName, styles: { 1: { // Style ID 1 for header bl: 1, // bold bg: { rgb: 'f2f2f2' } // background color }, 2: { // Style ID 2 for currency ff: '$#,##0' // currency format }, 3: { // Style ID 3 for percentages ff: '0.00%' // percentage format } } }); // Add a worksheet // @ts-ignore const worksheet = workbook.create('Sales Data'); // Set sample data if enabled if (showSampleData) { // Merge cells for title const titleRange = worksheet.getRange('A1:F1'); titleRange.merge(); // Set title titleRange.setValue('Sales Report'); // @ts-ignore titleRange.setStyle({ fs: 16, bl: 1 }); // font size 16, bold // Set headers const headers = ['Region', 'Q1', 'Q2', 'Q3', 'Q4', 'Total']; const headerRange = worksheet.getRange(1, 0, 1, headers.length - 1); headerRange.setValues([headers]); // @ts-ignore headerRange.setStyle(1); // Apply header style // Set data rows const data = [ ['North', 12500, 15000, 14200, 16800, '=SUM(B3:E3)'], ['South', 9800, 11200, 10800, 12400, '=SUM(B4:E4)'], ['East', 15300, 16800, 17500, 19200, '=SUM(B5:E5)'], ['West', 11800, 13200, 12800, 14500, '=SUM(B6:E6)'] ]; const dataRange = worksheet.getRange(2, 0, data.length, data[0].length); dataRange.setValues(data); // Apply currency format to Q1-Q4 and Total columns const currencyRange = worksheet.getRange(2, 1, data.length, 5); // @ts-ignore currencyRange.setStyle(2); // Set totals row const totalsRow = 2 + data.length; worksheet.getRange(totalsRow, 0).setValue('Total'); for (let col = 1; col <= 5; col++) { const colLetter = String.fromCharCode(64 + col); // A=65, B=66, etc. const formula = col === 5 ? `=SUM(F3:F6)` : `=SUM(${colLetter}3:${colLetter}6)`; worksheet.getRange(totalsRow, col).setValue(formula); // @ts-ignore worksheet.getRange(totalsRow, col).setStyle({ bl: 1 }); // bold } // Set growth rate section const growthTitleRow = totalsRow + 2; worksheet.getRange(growthTitleRow, 0).setValue('Growth Rate'); // @ts-ignore worksheet.getRange(growthTitleRow, 0).setStyle({ fs: 14, bl: 1 }); const growthRates = [ ['Q1 to Q2', '=C3/B3-1', '=C4/B4-1', '=C5/B5-1', '=C6/B6-1', '=C7/B7-1'], ['Q2 to Q3', '=D3/C3-1', '=D4/C4-1', '=D5/C5-1', '=D6/C6-1', '=D7/C7-1'], ['Q3 to Q4', '=E3/D3-1', '=E4/D4-1', '=E5/D5-1', '=E6/D6-1', '=E7/D7-1'] ]; const growthRange = worksheet.getRange(growthTitleRow + 1, 0, growthRates.length, growthRates[0].length); growthRange.setValues(growthRates); // Apply styles to growth rates const growthLabelRange = worksheet.getRange(growthTitleRow + 1, 0, growthRates.length, 1); // @ts-ignore growthLabelRange.setStyle({ bg: { rgb: 'f2f2f2' } }); const growthValueRange = worksheet.getRange(growthTitleRow + 1, 1, growthRates.length, growthRates[0].length - 1); // @ts-ignore growthValueRange.setStyle(3); // percentage format // Adjust column widths worksheet.setColumnWidth(0, 120); for (let col = 1; col <= 5; col++) { worksheet.setColumnWidth(col, 80); } // Adjust row heights worksheet.setRowHeight(0, 30); // title row worksheet.setRowHeight(1, 22); // header row worksheet.setRowHeight(totalsRow, 22); // totals row worksheet.setRowHeight(growthTitleRow, 24); // growth rate title } univerRef.current = univerAPI; return () => { univerAPI.dispose(); }; }, [fileName, showSampleData]); // Get the active range from selection const getActiveRange = () => { const workbook = univerRef.current?.getActiveWorkbook(); if (!workbook) return null; const worksheet = workbook.getActiveSheet(); if (!worksheet) return null; const selection = worksheet.getSelection(); if (!selection) return null; return worksheet.getRange(selection.getRange()); }; const handleCopy = () => { const range = getActiveRange(); if (range) { const values = range.getValues(); navigator.clipboard.writeText(JSON.stringify(values)); } }; const handlePaste = async () => { try { const text = await navigator.clipboard.readText(); const range = getActiveRange(); if (range) { try { const values = JSON.parse(text); range.setValues(values); } catch { range.setValue(text); } } } catch (error) { console.error('Paste failed:', error); } }; const handleInsertRow = () => { const range = getActiveRange(); if (range) { range.insertCells(univerRef.current.Enum.Dimension.ROWS); } }; // @ts-ignore const handleInsertColumn = () => { const range = getActiveRange(); if (range) { range.insertCells(univerRef.current.Enum.Dimension.COLUMNS); } }; const handleDeleteRow = () => { const range = getActiveRange(); if (range) { range.deleteCells(univerRef.current.Enum.Dimension.ROWS); } }; // @ts-ignore const handleDeleteColumn = () => { const range = getActiveRange(); if (range) { range.deleteCells(univerRef.current.Enum.Dimension.COLUMNS); } }; const handleBold = () => { const range = getActiveRange(); if (range) { const isBold = range.getCellStyle()?.bl === 1; range.setFontWeight(isBold ? null : 'bold'); } }; const handleItalic = () => { const range = getActiveRange(); if (range) { const isItalic = range.getCellStyle()?.it === 1; range.setFontLine(isItalic ? null : 'italic'); } }; const handleUnderline = () => { const range = getActiveRange(); if (range) { const isUnderlined = range.getCellStyle()?.ul === 1; range.setFontLine(isUnderlined ? null : 'underline'); } }; const handleAlignment = (alignment) => { const range = getActiveRange(); if (range) { range.setTextAlignment(alignment); } }; const handleSort = () => { const range = getActiveRange(); if (range) { const worksheet = range.getWorksheet(); worksheet.sort(range, { column: range.getColumn(), ascending: true }); } }; // @ts-ignore const handleFillDown = () => { const range = getActiveRange(); if (range && range.getRowCount() > 1) { const sourceValue = range.getValue(); const values = Array(range.getRowCount()).fill(sourceValue); range.setValues(values); } }; // @ts-ignore const handleFillRight = () => { const range = getActiveRange(); if (range && range.getColumnCount() > 1) { const sourceValue = range.getValue(); const values = Array(range.getColumnCount()).fill(sourceValue); range.setValues([values]); } }; // @ts-ignore const handleUndo = () => { univerRef.current?.undo(); }; // @ts-ignore const handleRedo = () => { univerRef.current?.redo(); }; // @ts-ignore const handleSave = () => { const workbook = univerRef.current?.getActiveWorkbook(); if (workbook) { const data = workbook.save(); const blob = new Blob([JSON.stringify(data)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `${fileName}.json`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } }; const handleZoomIn = () => { setZoomLevel(prev => Math.min(prev + 10, 200)); univerRef.current?.setZoomLevel(zoomLevel / 100 + 0.1); }; const handleZoomOut = () => { setZoomLevel(prev => Math.max(prev - 10, 50)); univerRef.current?.setZoomLevel(zoomLevel / 100 - 0.1); }; const handleSlashCommand = (e) => { if (e.key === '/') { setCommandMode(true); } else if (e.key === 'Escape') { setCommandMode(false); } }; // @ts-ignore const handleLoadSampleData = () => { setShowSampleData(true); }; const handleMergeCells = () => { const range = getActiveRange(); if (range) { if (range.isMerged()) { range.breakApart(); } else { range.merge(); } } }; const handleClearFormat = () => { const range = getActiveRange(); if (range) { range.clearFormat(); } }; const handleClearContent = () => { const range = getActiveRange(); if (range) { range.clearContent(); } }; const handleHighlightRange = () => { const range = getActiveRange(); if (range) { const highlightDisposable = range.highlight({ stroke: 'red', fill: 'rgba(255, 255, 0, 0.3)' }); // Remove highlight after 5 seconds setTimeout(() => { highlightDisposable.dispose(); }, 5000); } }; const handleSplitText = () => { const range = getActiveRange(); if (range) { range.splitTextToColumns(true); // Split with default delimiter (comma) } }; return (
{/* ... (keep all the existing JSX and styles the same) ... */}
setActiveTab('home')}>
{}} /> {}} />
handleAlignment('left')} /> handleAlignment('center')} /> handleAlignment('right')} />
{}} />
{}} /> {}} /> {}} />
{}} /> {}} />
{}} />
setActiveTab('home')}>
{}}>
Font Family
Font Size
{}} />
handleAlignment('left')} /> handleAlignment('center')} /> handleAlignment('right')} /> handleAlignment('justify')} />
{}} /> {}} />
{}} /> {}} /> {}} />
{}} /> {}} />
{}} />
{}} /> {}} />
{}} />
setActiveTab('insert')}> {}} /> {}} /> {}} /> {}} /> {}} /> {}} /> setActiveTab('data')}> {}} /> {}} /> {}} /> {}} /> setActiveTab('view')}> {}} /> {}} /> {}} /> {}} />
{currentCell}
setCellContent(e.target.value)} onKeyDown={handleSlashCommand} placeholder="Enter formula or value" /> {commandMode && (
/Worksheet - Manage worksheets
/Range - Format range
/File - Save or open files
/Print - Print options
/Graph - Create charts
/Data - Sort and filter
/System - Settings
/Quit - Exit application
)}
{formulaMode === '@' ? 'READY' : 'EDIT'}
For help, press F1
{zoomLevel}%
); }