"use client";
import { useState, useRef, useEffect } from 'react';
import { useEditor, EditorContent, BubbleMenu } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import TextStyle from '@tiptap/extension-text-style';
import FontFamily from '@tiptap/extension-font-family';
import Color from '@tiptap/extension-color';
import Highlight from '@tiptap/extension-highlight';
import TextAlign from '@tiptap/extension-text-align';
import Link from '@tiptap/extension-link';
import Image from '@tiptap/extension-image';
import Underline from '@tiptap/extension-underline';
import Table from '@tiptap/extension-table';
import TableCell from '@tiptap/extension-table-cell';
import TableHeader from '@tiptap/extension-table-header';
import TableRow from '@tiptap/extension-table-row';
import {
Bold, Italic, Underline as UnderlineIcon, AlignLeft, AlignCenter, AlignRight, AlignJustify,
Link as LinkIcon, Image as ImageIcon, Save, FileText, Printer, Table as TableIcon,
Plus, Minus, Trash2, Type, Palette, Highlighter, FileImage, File, Home,
View, ChevronDown, Search,
Undo, Redo, Copy, MoreVertical
} from 'lucide-react';
const RibbonTab = ({ label, isActive, onClick, children }) => (
{isActive && (
{children}
)}
);
const RibbonGroup = ({ title, children }) => (
);
const RibbonButton = ({ icon: Icon, label, onClick, isActive, size = 'medium', dropdown = false }) => (
);
export default function RibbonWordClone() {
const [fileName, setFileName] = useState('Document 1');
const [fontSize, setFontSize] = useState('12');
const [fontFamily, setFontFamily] = useState('Calibri');
const [textColor, setTextColor] = useState('#000000');
const [highlightColor, setHighlightColor] = useState('#ffff00');
const [activeTab, setActiveTab] = useState('home');
const [zoom, setZoom] = useState(100);
const [pages, setPages] = useState([1]);
const fileInputRef = useRef(null);
const editor = useEditor({
extensions: [
StarterKit,
TextStyle,
FontFamily,
Color,
Highlight.configure({ multicolor: true }),
TextAlign.configure({ types: ['heading', 'paragraph', 'tableCell'] }),
Link.configure({ openOnClick: false }),
Image,
Underline,
Table.configure({
resizable: true,
HTMLAttributes: {
class: 'editor-table',
},
}),
TableRow,
TableHeader,
TableCell,
],
content: `
${fileName}
Start typing your document here...
`,
onUpdate: ({ editor }) => {
// Simulate multiple pages based on content height
const element = document.querySelector('.ProseMirror');
if (element) {
const contentHeight = element.scrollHeight;
const pageHeight = 1123; // A4 height in pixels at 96 DPI
const neededPages = Math.max(1, Math.ceil(contentHeight / pageHeight));
if (neededPages !== pages.length) {
setPages(Array.from({ length: neededPages }, (_, i) => i + 1));
}
}
},
});
const addImage = () => {
if (fileInputRef.current) {
fileInputRef.current.click();
}
};
const handleImageUpload = (e) => {
const file = e.target.files?.[0];
if (file && editor) {
const reader = new FileReader();
reader.onload = (event) => {
const imageUrl = event.target?.result;
editor.chain().focus().setImage({ src: imageUrl }).run();
};
reader.readAsDataURL(file);
}
};
const saveDocument = () => {
if (editor) {
const content = editor.getHTML();
const blob = new Blob([content], { type: 'text/html' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${fileName}.html`;
a.click();
URL.revokeObjectURL(url);
}
};
if (!editor) {
return null;
}
return (
{/* Quick Access Toolbar */}
{/* Ribbon */}
{activeTab === 'home' && (
document.execCommand('copy')} isActive={undefined} />
document.execCommand('paste')} isActive={undefined} />
document.execCommand('cut')} isActive={undefined} />
editor.chain().focus().toggleBold().run()}
isActive={editor.isActive('bold')}
/>
editor.chain().focus().toggleItalic().run()}
isActive={editor.isActive('italic')}
/>
editor.chain().focus().toggleUnderline().run()}
isActive={editor.isActive('underline')}
/>
editor.chain().focus().setTextAlign('left').run()}
isActive={editor.isActive({ textAlign: 'left' })}
/>
editor.chain().focus().setTextAlign('center').run()}
isActive={editor.isActive({ textAlign: 'center' })}
/>
editor.chain().focus().setTextAlign('right').run()}
isActive={editor.isActive({ textAlign: 'right' })}
/>
editor.chain().focus().setTextAlign('justify').run()}
isActive={editor.isActive({ textAlign: 'justify' })}
/>
)}
{activeTab === 'insert' && (
editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run()} isActive={undefined} />
{
const previousUrl = editor.getAttributes('link').href;
const url = window.prompt('URL', previousUrl);
if (url === null) return;
if (url === '') {
editor.chain().focus().extendMarkRange('link').unsetLink().run();
return;
}
editor.chain().focus().extendMarkRange('link').setLink({ href: url }).run();
}}
isActive={editor.isActive('link')}
/>
)}
{activeTab === 'view' && (
)}
{/* Editor Area */}
{pages.map((pageNum, index) => (
Page {pageNum}
{index === 0 && }
))}
{/* Bubble Menu */}
{editor && (
editor.chain().focus().toggleBold().run()}
isActive={editor.isActive('bold')}
/>
editor.chain().focus().toggleItalic().run()}
isActive={editor.isActive('italic')}
/>
editor.chain().focus().toggleUnderline().run()}
isActive={editor.isActive('underline')}
/>
{
const previousUrl = editor.getAttributes('link').href;
const url = window.prompt('URL', previousUrl);
if (url === null) return;
if (url === '') {
editor.chain().focus().extendMarkRange('link').unsetLink().run();
return;
}
editor.chain().focus().extendMarkRange('link').setLink({ href: url }).run();
}}
isActive={editor.isActive('link')}
/>
)}
{/* Status Bar */}
Page {pages.length} of {pages.length} | Words: {editor.storage.characterCount?.words() || 0}
{zoom}%
{/* Hidden file input */}
);
}