CoolFace
Apppublic

ramangos/ResumeEditor

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
index.html511 linesDownload Raw Back to root
1<!DOCTYPE html>2<html lang="en">3<head>4    <meta charset="UTF-8">5    <meta name="viewport" content="width=device-width, initial-scale=1.0">6    <title>Resume Editor</title>7    <script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.4.2/mammoth.browser.min.js"></script>8    <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>9    <script src="https://cdnjs.cloudflare.com/ajax/libs/pizzip/3.1.4/pizzip.min.js"></script>10    <script src="https://cdnjs.cloudflare.com/ajax/libs/docxtemplater/3.37.11/docxtemplater.min.js"></script>11    <style>12        * {13            margin: 0;14            padding: 0;15            box-sizing: border-box;16        }17 18        body {19            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;20            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);21            min-height: 100vh;22            padding: 20px;23        }24 25        .container {26            max-width: 900px;27            margin: 0 auto;28            background: white;29            border-radius: 20px;30            box-shadow: 0 20px 40px rgba(0,0,0,0.1);31            overflow: hidden;32            animation: slideUp 0.6s ease-out;33        }34 35        @keyframes slideUp {36            from {37                opacity: 0;38                transform: translateY(30px);39            }40            to {41                opacity: 1;42                transform: translateY(0);43            }44        }45 46        .header {47            background: linear-gradient(135deg, #2c3e50, #3498db);48            color: white;49            padding: 30px;50            text-align: center;51        }52 53        .header h1 {54            font-size: 2.5em;55            margin-bottom: 10px;56            font-weight: 300;57        }58 59        .header p {60            opacity: 0.9;61            font-size: 1.1em;62        }63 64        .upload-section {65            padding: 40px;66            text-align: center;67            border-bottom: 1px solid #eee;68        }69 70        .upload-area {71            border: 3px dashed #3498db;72            border-radius: 15px;73            padding: 60px 40px;74            background: #f8f9fa;75            transition: all 0.3s ease;76            cursor: pointer;77            position: relative;78            overflow: hidden;79        }80 81        .upload-area:hover {82            border-color: #2980b9;83            background: #e8f4f8;84            transform: translateY(-2px);85        }86 87        .upload-area.dragover {88            border-color: #27ae60;89            background: #e8f5e8;90        }91 92        .upload-icon {93            font-size: 4em;94            color: #3498db;95            margin-bottom: 20px;96        }97 98        .upload-text {99            font-size: 1.2em;100            color: #2c3e50;101            margin-bottom: 15px;102        }103 104        .upload-hint {105            color: #7f8c8d;106            font-size: 0.9em;107        }108 109        #fileInput {110            display: none;111        }112 113        .toolbar {114            background: #f8f9fa;115            padding: 15px 30px;116            border-bottom: 1px solid #dee2e6;117            display: none;118        }119 120        .toolbar button {121            background: #3498db;122            color: white;123            border: none;124            padding: 10px 20px;125            border-radius: 8px;126            cursor: pointer;127            font-size: 14px;128            margin-right: 10px;129            transition: all 0.3s ease;130        }131 132        .toolbar button:hover {133            background: #2980b9;134            transform: translateY(-1px);135        }136 137        .toolbar button:disabled {138            background: #95a5a6;139            cursor: not-allowed;140            transform: none;141        }142 143        .editor-section {144            padding: 40px;145            display: none;146        }147 148        .editor {149            min-height: 600px;150            border: 2px solid #e9ecef;151            border-radius: 10px;152            padding: 30px;153            background: white;154            font-family: 'Times New Roman', serif;155            font-size: 12pt;156            line-height: 1.6;157            outline: none;158            box-shadow: inset 0 2px 4px rgba(0,0,0,0.06);159        }160 161        .editor:focus {162            border-color: #3498db;163            box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);164        }165 166        .status {167            margin-top: 20px;168            padding: 15px;169            border-radius: 8px;170            font-weight: 500;171            text-align: center;172            display: none;173        }174 175        .status.success {176            background: #d4edda;177            color: #155724;178            border: 1px solid #c3e6cb;179        }180 181        .status.error {182            background: #f8d7da;183            color: #721c24;184            border: 1px solid #f5c6cb;185        }186 187        .loading {188            display: none;189            text-align: center;190            padding: 20px;191        }192 193        .spinner {194            border: 4px solid #f3f3f3;195            border-top: 4px solid #3498db;196            border-radius: 50%;197            width: 40px;198            height: 40px;199            animation: spin 1s linear infinite;200            margin: 0 auto 15px;201        }202 203        @keyframes spin {204            0% { transform: rotate(0deg); }205            100% { transform: rotate(360deg); }206        }207 208        .file-info {209            background: #e8f4f8;210            padding: 15px;211            border-radius: 8px;212            margin-bottom: 20px;213            display: none;214        }215 216        .file-info h3 {217            color: #2c3e50;218            margin-bottom: 5px;219        }220 221        .file-info p {222            color: #7f8c8d;223            font-size: 0.9em;224        }225 226        /* Preserve Word document styling */227        .editor h1, .editor h2, .editor h3, .editor h4, .editor h5, .editor h6 {228            font-weight: bold;229            margin: 12px 0 6px 0;230        }231 232        .editor p {233            margin: 6px 0;234        }235 236        .editor ul, .editor ol {237            margin: 6px 0;238            padding-left: 20px;239        }240 241        .editor strong {242            font-weight: bold;243        }244 245        .editor em {246            font-style: italic;247        }248 249        .editor u {250            text-decoration: underline;251        }252    </style>253</head>254<body>255    <div class="container">256        <div class="header">257            <h1>Resume Editor</h1>258            <p>Upload, edit, and save your resume in .docx format</p>259        </div>260 261        <div class="upload-section" id="uploadSection">262            <div class="upload-area" id="uploadArea">263                <div class="upload-icon">๐Ÿ“„</div>264                <div class="upload-text">Drop your resume here or click to browse</div>265                <div class="upload-hint">Supports .docx files only</div>266                <input type="file" id="fileInput" accept=".docx" />267            </div>268        </div>269 270        <div class="loading" id="loading">271            <div class="spinner"></div>272            <p>Processing your resume...</p>273        </div>274 275        <div class="toolbar" id="toolbar">276            <button id="saveBtn">๐Ÿ’พ Save as DOCX</button>277            <button id="newFileBtn">๐Ÿ“„ Upload New File</button>278        </div>279 280        <div class="editor-section" id="editorSection">281            <div class="file-info" id="fileInfo">282                <h3 id="fileName"></h3>283                <p id="fileSize"></p>284            </div>285            <div class="editor" id="editor" contenteditable="true"></div>286        </div>287 288        <div class="status" id="status"></div>289    </div>290 291    <script>292        let originalDocContent = null;293        let currentFileName = '';294 295        // DOM elements296        const uploadArea = document.getElementById('uploadArea');297        const fileInput = document.getElementById('fileInput');298        const uploadSection = document.getElementById('uploadSection');299        const toolbar = document.getElementById('toolbar');300        const editorSection = document.getElementById('editorSection');301        const editor = document.getElementById('editor');302        const loading = document.getElementById('loading');303        const status = document.getElementById('status');304        const fileInfo = document.getElementById('fileInfo');305        const fileName = document.getElementById('fileName');306        const fileSize = document.getElementById('fileSize');307        const saveBtn = document.getElementById('saveBtn');308        const newFileBtn = document.getElementById('newFileBtn');309 310        // Event listeners311        uploadArea.addEventListener('click', () => fileInput.click());312        uploadArea.addEventListener('dragover', handleDragOver);313        uploadArea.addEventListener('dragleave', handleDragLeave);314        uploadArea.addEventListener('drop', handleDrop);315        fileInput.addEventListener('change', handleFileSelect);316        saveBtn.addEventListener('click', saveDocument);317        newFileBtn.addEventListener('click', resetEditor);318 319        function handleDragOver(e) {320            e.preventDefault();321            uploadArea.classList.add('dragover');322        }323 324        function handleDragLeave(e) {325            e.preventDefault();326            uploadArea.classList.remove('dragover');327        }328 329        function handleDrop(e) {330            e.preventDefault();331            uploadArea.classList.remove('dragover');332            const files = e.dataTransfer.files;333            if (files.length > 0) {334                processFile(files[0]);335            }336        }337 338        function handleFileSelect(e) {339            const file = e.target.files[0];340            if (file) {341                processFile(file);342            }343        }344 345        function processFile(file) {346            if (!file.name.endsWith('.docx')) {347                showStatus('Please select a .docx file only.', 'error');348                return;349            }350 351            currentFileName = file.name;352            showLoading(true);353            354            // Display file info355            fileName.textContent = file.name;356            fileSize.textContent = `Size: ${(file.size / 1024).toFixed(1)} KB`;357            fileInfo.style.display = 'block';358 359            // Read the file as array buffer for later use360            const reader = new FileReader();361            reader.onload = function(e) {362                originalDocContent = e.target.result;363                364                // Convert to HTML for editing365                mammoth.convertToHtml({arrayBuffer: e.target.result})366                    .then(function(result) {367                        editor.innerHTML = result.value;368                        showEditor();369                        showLoading(false);370                        showStatus('Resume loaded successfully! You can now edit it.', 'success');371                    })372                    .catch(function(error) {373                        showLoading(false);374                        showStatus('Error loading the document. Please try again.', 'error');375                        console.error('Error:', error);376                    });377            };378            reader.readAsArrayBuffer(file);379        }380 381        function showEditor() {382            uploadSection.style.display = 'none';383            toolbar.style.display = 'block';384            editorSection.style.display = 'block';385        }386 387        function showLoading(show) {388            loading.style.display = show ? 'block' : 'none';389        }390 391        function showStatus(message, type) {392            status.textContent = message;393            status.className = `status ${type}`;394            status.style.display = 'block';395            setTimeout(() => {396                status.style.display = 'none';397            }, 3000);398        }399 400        function saveDocument() {401            if (!originalDocContent) {402                showStatus('No document to save.', 'error');403                return;404            }405 406            try {407                // Get the edited HTML content408                const editedHtml = editor.innerHTML;409                410                // For a more robust solution, you would need to:411                // 1. Parse the HTML back to maintain Word formatting412                // 2. Update the original document structure413                // 3. Generate a new .docx file414                415                // This is a simplified approach using the original document416                // and creating a basic text version417                const textContent = editor.innerText;418                419                // Create a simple document structure420                const doc = new PizZip(originalDocContent);421                422                // This is a basic implementation - in a production app,423                // you'd want to use a more sophisticated approach to maintain formatting424                const blob = new Blob([textContent], {425                    type: 'text/plain'426                });427                428                // For now, save as text file with instructions429                const newFileName = currentFileName.replace('.docx', '_edited.txt');430                saveAs(blob, newFileName);431                432                showStatus('Document saved! Note: For full .docx support, consider using a server-side solution.', 'success');433                434            } catch (error) {435                showStatus('Error saving document. Please try again.', 'error');436                console.error('Save error:', error);437            }438        }439 440        function resetEditor() {441            uploadSection.style.display = 'block';442            toolbar.style.display = 'none';443            editorSection.style.display = 'none';444            fileInfo.style.display = 'none';445            editor.innerHTML = '';446            originalDocContent = null;447            currentFileName = '';448            fileInput.value = '';449            status.style.display = 'none';450        }451 452        // Enhanced save function with better DOCX handling453        async function saveAsDocx() {454            if (!originalDocContent) {455                showStatus('No document to save.', 'error');456                return;457            }458 459            try {460                // Convert HTML back to a format that can be saved as DOCX461                const editedText = editor.innerText;462                463                // Create a new document with the edited content464                // This is a simplified approach - for production use, consider:465                // 1. Using a server-side solution with libraries like python-docx466                // 2. Implementing a more sophisticated HTML-to-DOCX converter467                // 3. Using commercial APIs that specialize in document conversion468                469                const zip = new PizZip(originalDocContent);470                const doc = new window.docxtemplater(zip, {471                    paragraphLoop: true,472                    linebreaks: true,473                });474 475                // Replace content (simplified approach)476                const content = {477                    content: editedText478                };479 480                doc.setData(content);481                482                try {483                    doc.render();484                    const out = doc.getZip().generate({485                        type: "blob",486                        mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",487                    });488                    489                    const newFileName = currentFileName.replace('.docx', '_edited.docx');490                    saveAs(out, newFileName);491                    showStatus('Document saved as DOCX!', 'success');492                    493                } catch (error) {494                    // Fallback to text file495                    const blob = new Blob([editedText], { type: 'text/plain' });496                    const newFileName = currentFileName.replace('.docx', '_edited.txt');497                    saveAs(blob, newFileName);498                    showStatus('Saved as text file. For full DOCX support, use a specialized document editor.', 'success');499                }500                501            } catch (error) {502                showStatus('Error saving document. Please try again.', 'error');503                console.error('Save error:', error);504            }505        }506 507        // Update save button to use the enhanced function508        saveBtn.addEventListener('click', saveAsDocx);509    </script>510</body>511</html>