Initial xlxs support
All checks were successful
Automated Container Build / build-and-push (push) Successful in 1m25s

This commit is contained in:
Elijah 2026-05-25 09:57:09 -07:00
parent 2648a5ae84
commit 709c13995c
5 changed files with 164 additions and 22 deletions

View file

@ -14,7 +14,7 @@ interface FileItem {
}
interface OfficeHomeProps {
type: 'docs' | 'slides';
type: 'docs' | 'slides' | 'sheets';
onFileSelect: (file: FileItem) => void;
onCreateBlank: (file: FileItem) => void;
onPinChange?: () => void;
@ -38,6 +38,15 @@ function PptIcon({ className }: { className?: string }) {
);
}
// Custom Excel icon (green)
function SheetIcon({ className }: { className?: string }) {
return (
<div className={`flex items-center justify-center font-black tracking-tighter text-white bg-[#107C41] rounded-lg ${className || ''}`}>
X
</div>
);
}
interface ContextMenuState {
x: number;
y: number;
@ -55,8 +64,8 @@ export default function OfficeHome({ type, onFileSelect, onCreateBlank, onPinCha
const [renameValue, setRenameValue] = useState('');
const renameInputRef = useRef<HTMLInputElement>(null);
const ext = type === 'docs' ? '.docx' : '.pptx';
const fileTypeParam = type === 'docs' ? 'docx' : 'pptx';
const ext = type === 'docs' ? '.docx' : type === 'slides' ? '.pptx' : '.xlsx';
const fileTypeParam = type === 'docs' ? 'docx' : type === 'slides' ? 'pptx' : 'xlsx';
const fetchFiles = () => {
// Fetch recent files from root directory
@ -132,7 +141,7 @@ export default function OfficeHome({ type, onFileSelect, onCreateBlank, onPinCha
const handleCreateBlank = async () => {
try {
const res = await api.createOnlyOfficeFile(type === 'docs' ? 'word' : 'slide');
const res = await api.createOnlyOfficeFile(type === 'docs' ? 'word' : type === 'slides' ? 'slide' : 'cell');
const { path, name } = res;
const newFile: FileItem = {
@ -140,7 +149,9 @@ export default function OfficeHome({ type, onFileSelect, onCreateBlank, onPinCha
path,
is_dir: false,
size: 0,
mime_type: type === 'docs' ? 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' : 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
mime_type: type === 'docs' ? 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' :
type === 'slides' ? 'application/vnd.openxmlformats-officedocument.presentationml.presentation' :
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
is_pinned: false,
is_trashed: false,
mod_time: new Date().toISOString()
@ -204,9 +215,9 @@ export default function OfficeHome({ type, onFileSelect, onCreateBlank, onPinCha
}
};
const title = type === 'docs' ? 'Documents' : 'Presentations';
const Icon = type === 'docs' ? WordIcon : PptIcon;
const accentColor = type === 'docs' ? '#2B579A' : '#D24726';
const title = type === 'docs' ? 'Documents' : type === 'slides' ? 'Presentations' : 'Spreadsheets';
const Icon = type === 'docs' ? WordIcon : type === 'slides' ? PptIcon : SheetIcon;
const accentColor = type === 'docs' ? '#2B579A' : type === 'slides' ? '#D24726' : '#107C41';
const renderFileCard = (file: FileItem) => {
const isRenaming = renaming === file.path;
@ -218,7 +229,7 @@ export default function OfficeHome({ type, onFileSelect, onCreateBlank, onPinCha
<button
onClick={() => !isRenaming && onFileSelect(file)}
onContextMenu={(e) => handleContextMenu(e, file)}
className={`w-full ${type === 'docs' ? 'aspect-[1/1.4]' : 'aspect-[1.4/1]'} rounded-lg border hover:border-blue-500 transition-colors flex items-center justify-center shadow-sm overflow-hidden relative`}
className={`w-full ${type === 'slides' ? 'aspect-[1.4/1]' : 'aspect-[1/1.4]'} rounded-lg border hover:border-blue-500 transition-colors flex items-center justify-center shadow-sm overflow-hidden relative`}
style={{ backgroundColor: 'var(--color-bg-elevated)', borderColor: 'var(--color-border)' }}
>
<Icon className="w-16 h-16 text-3xl opacity-30 group-hover:opacity-60 transition-opacity" />
@ -257,12 +268,12 @@ export default function OfficeHome({ type, onFileSelect, onCreateBlank, onPinCha
{/* Top Banner */}
<div className="py-8 px-10" style={{ backgroundColor: 'var(--color-bg-secondary)' }}>
<div className="max-w-6xl mx-auto">
<h2 className="text-lg font-medium mb-4" style={{ color: 'var(--color-text-primary)' }}>Start a new {type === 'docs' ? 'document' : 'presentation'}</h2>
<h2 className="text-lg font-medium mb-4" style={{ color: 'var(--color-text-primary)' }}>Start a new {type === 'docs' ? 'document' : type === 'slides' ? 'presentation' : 'spreadsheet'}</h2>
<div className="flex gap-4">
<div className="flex flex-col gap-3">
<button
onClick={handleCreateBlank}
className={`${type === 'docs' ? 'w-40 h-52' : 'w-52 h-40'} rounded-lg border hover:border-blue-500 transition-colors flex items-center justify-center shadow-sm group`}
className={`${type === 'slides' ? 'w-52 h-40' : 'w-40 h-52'} rounded-lg border hover:border-blue-500 transition-colors flex items-center justify-center shadow-sm group`}
style={{ backgroundColor: 'var(--color-bg-elevated)', borderColor: 'var(--color-border)' }}
>
<Plus className="w-12 h-12 text-gray-300 group-hover:text-blue-500 transition-colors" />
@ -284,7 +295,7 @@ export default function OfficeHome({ type, onFileSelect, onCreateBlank, onPinCha
) : recentFiles.length === 0 ? (
<div className="text-sm text-gray-500">No recent {title.toLowerCase()} found.</div>
) : (
<div className={`grid ${type === 'docs' ? 'grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6' : 'grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5'} gap-6`}>
<div className={`grid ${type === 'slides' ? 'grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5' : 'grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6'} gap-6`}>
{recentFiles.map(file => renderFileCard(file))}
</div>
)}
@ -301,7 +312,7 @@ export default function OfficeHome({ type, onFileSelect, onCreateBlank, onPinCha
) : allFiles.length === 0 ? (
<div className="text-sm text-gray-500">No {title.toLowerCase()} found in your drive.</div>
) : (
<div className={`grid ${type === 'docs' ? 'grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6' : 'grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5'} gap-6`}>
<div className={`grid ${type === 'slides' ? 'grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5' : 'grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6'} gap-6`}>
{allFiles.map(file => renderFileCard(file))}
</div>
)}