ninhmedia-com / index.html
ninhdapchai's picture
làm 1 app cho phép chuyển đổi file mà dân văn phòng app web - Follow Up Deployment
e4c6520 verified
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Office File Converter - Công cụ chuyển đổi file văn phòng</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.file-drop-area {
border: 2px dashed #3b82f6;
transition: all 0.3s ease;
}
.file-drop-area.active {
border-color: #10b981;
background-color: #f0fdf4;
}
.progress-bar {
transition: width 0.3s ease;
}
.convert-btn:disabled {
opacity: 0.7;
cursor: not-allowed;
}
.file-icon {
font-size: 2.5rem;
}
.toast {
animation: slideIn 0.3s, fadeOut 0.5s 2.5s forwards;
}
@keyframes slideIn {
from { transform: translateY(20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
@keyframes fadeOut {
to { opacity: 0; }
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="container mx-auto px-4 py-8">
<!-- Header -->
<header class="text-center mb-10">
<h1 class="text-3xl md:text-4xl font-bold text-blue-600 mb-2">
<i class="fas fa-file-export mr-2"></i>Office File Converter
</h1>
<p class="text-gray-600 max-w-2xl mx-auto">
Công cụ chuyển đổi file văn phòng trực tuyến miễn phí. Hỗ trợ DOCX, PDF, XLSX, PPTX và nhiều định dạng khác.
</p>
</header>
<!-- Main Converter -->
<div class="max-w-4xl mx-auto bg-white rounded-xl shadow-md overflow-hidden p-6 mb-8">
<div class="flex flex-col md:flex-row gap-6">
<!-- File Input Section -->
<div class="w-full md:w-1/2">
<div id="fileDropArea" class="file-drop-area rounded-lg p-8 text-center cursor-pointer h-full flex flex-col items-center justify-center">
<i class="fas fa-cloud-upload-alt file-icon text-blue-400 mb-4"></i>
<h3 class="text-lg font-semibold mb-2">Kéo & thả file vào đây</h3>
<p class="text-gray-500 mb-4">hoặc</p>
<label for="fileInput" class="bg-blue-500 hover:bg-blue-600 text-white px-6 py-2 rounded-md cursor-pointer transition">
<i class="fas fa-folder-open mr-2"></i>Chọn file
</label>
<input type="file" id="fileInput" class="hidden">
<p class="text-xs text-gray-400 mt-4">Hỗ trợ: DOCX, PDF, XLSX, PPTX, TXT, RTF, ODT</p>
</div>
</div>
<!-- Conversion Options -->
<div class="w-full md:w-1/2">
<div class="bg-gray-50 rounded-lg p-6 h-full">
<h3 class="text-lg font-semibold mb-4 flex items-center">
<i class="fas fa-cog text-blue-500 mr-2"></i> Tùy chọn chuyển đổi
</h3>
<!-- Selected File Info -->
<div id="fileInfo" class="hidden mb-4 p-3 bg-blue-50 rounded-md">
<div class="flex items-center justify-between">
<div class="flex items-center truncate">
<i id="fileTypeIcon" class="fas fa-file mr-2 text-blue-500"></i>
<span id="fileName" class="font-medium truncate"></span>
</div>
<button id="removeFile" class="text-red-500 hover:text-red-700">
<i class="fas fa-times"></i>
</button>
</div>
<div id="fileSize" class="text-xs text-gray-500 mt-1"></div>
</div>
<!-- Format Selection -->
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-2">Chuyển đổi sang:</label>
<div class="grid grid-cols-3 gap-2">
<button data-format="pdf" class="format-btn py-2 px-3 rounded-md border hover:bg-blue-50 hover:border-blue-300 flex flex-col items-center">
<i class="fas fa-file-pdf text-red-500 mb-1"></i>
<span>PDF</span>
</button>
<button data-format="docx" class="format-btn py-2 px-3 rounded-md border hover:bg-blue-50 hover:border-blue-300 flex flex-col items-center">
<i class="fas fa-file-word text-blue-500 mb-1"></i>
<span>DOCX</span>
</button>
<button data-format="xlsx" class="format-btn py-2 px-3 rounded-md border hover:bg-blue-50 hover:border-blue-300 flex flex-col items-center">
<i class="fas fa-file-excel text-green-500 mb-1"></i>
<span>XLSX</span>
</button>
<button data-format="pptx" class="format-btn py-2 px-3 rounded-md border hover:bg-blue-50 hover:border-blue-300 flex flex-col items-center">
<i class="fas fa-file-powerpoint text-orange-500 mb-1"></i>
<span>PPTX</span>
</button>
<button data-format="txt" class="format-btn py-2 px-3 rounded-md border hover:bg-blue-50 hover:border-blue-300 flex flex-col items-center">
<i class="fas fa-file-alt text-gray-500 mb-1"></i>
<span>TXT</span>
</button>
<button data-format="odt" class="format-btn py-2 px-3 rounded-md border hover:bg-blue-50 hover:border-blue-300 flex flex-col items-center">
<i class="fas fa-file-alt text-purple-500 mb-1"></i>
<span>ODT</span>
</button>
</div>
</div>
<!-- Advanced Options -->
<div class="mb-4">
<div class="flex items-center justify-between cursor-pointer" id="advancedToggle">
<span class="text-sm font-medium text-gray-700">Tùy chọn nâng cao</span>
<i class="fas fa-chevron-down text-gray-500 transition-transform"></i>
</div>
<div id="advancedOptions" class="hidden mt-2 space-y-2">
<div class="flex items-center">
<input type="checkbox" id="preserveFormatting" class="mr-2">
<label for="preserveFormatting" class="text-sm">Giữ nguyên định dạng</label>
</div>
<div class="flex items-center">
<input type="checkbox" id="optimizeForWeb" class="mr-2">
<label for="optimizeForWeb" class="text-sm">Tối ưu cho web</label>
</div>
<div class="flex items-center">
<input type="checkbox" id="passwordProtect" class="mr-2">
<label for="passwordProtect" class="text-sm">Bảo vệ bằng mật khẩu</label>
</div>
</div>
</div>
<!-- Convert Button -->
<button id="convertBtn" class="convert-btn w-full bg-blue-600 hover:bg-blue-700 text-white py-3 px-4 rounded-md font-medium transition disabled:opacity-70 disabled:cursor-not-allowed" disabled>
<i class="fas fa-exchange-alt mr-2"></i> Chuyển đổi
</button>
</div>
</div>
</div>
</div>
<!-- Progress Bar (Hidden by default) -->
<div id="progressContainer" class="max-w-4xl mx-auto hidden mb-8">
<div class="bg-white rounded-xl shadow-md overflow-hidden p-6">
<h3 class="text-lg font-semibold mb-4 flex items-center">
<i class="fas fa-spinner fa-spin text-blue-500 mr-2"></i> Đang xử lý...
</h3>
<div class="w-full bg-gray-200 rounded-full h-2.5">
<div id="progressBar" class="progress-bar bg-blue-600 h-2.5 rounded-full" style="width: 0%"></div>
</div>
<div class="flex justify-between text-sm text-gray-500 mt-2">
<span id="progressText">0%</span>
<span id="timeRemaining">Ước tính: vài giây</span>
</div>
</div>
</div>
<!-- Result Section (Hidden by default) -->
<div id="resultContainer" class="max-w-4xl mx-auto hidden">
<div class="bg-white rounded-xl shadow-md overflow-hidden">
<div class="p-6">
<div class="flex items-center justify-between mb-4">
<h3 class="text-lg font-semibold flex items-center">
<i class="fas fa-check-circle text-green-500 mr-2"></i> Chuyển đổi thành công!
</h3>
<button id="newConversion" class="text-blue-500 hover:text-blue-700 text-sm font-medium">
<i class="fas fa-redo mr-1"></i> Chuyển đổi mới
</button>
</div>
<div class="flex flex-col md:flex-row gap-6">
<div class="flex-1 bg-gray-50 rounded-lg p-4">
<div class="flex items-center mb-3">
<i id="originalFileIcon" class="fas fa-file text-blue-500 mr-2"></i>
<div>
<div id="originalFileName" class="font-medium"></div>
<div id="originalFileSize" class="text-xs text-gray-500"></div>
</div>
</div>
<div class="text-sm text-gray-600 mb-2">
<span class="font-medium">Loại file:</span>
<span id="originalFileType"></span>
</div>
</div>
<div class="flex items-center justify-center text-gray-400">
<i class="fas fa-arrow-right text-2xl"></i>
</div>
<div class="flex-1 bg-green-50 rounded-lg p-4">
<div class="flex items-center mb-3">
<i id="convertedFileIcon" class="fas fa-file text-green-500 mr-2"></i>
<div>
<div id="convertedFileName" class="font-medium"></div>
<div id="convertedFileSize" class="text-xs text-gray-500"></div>
</div>
</div>
<div class="text-sm text-gray-600 mb-2">
<span class="font-medium">Loại file:</span>
<span id="convertedFileType"></span>
</div>
<div class="flex gap-2 mt-4">
<button id="downloadBtn" class="bg-green-500 hover:bg-green-600 text-white py-2 px-4 rounded-md text-sm font-medium flex items-center">
<i class="fas fa-download mr-2"></i> Tải xuống
</button>
<button id="shareBtn" class="bg-blue-500 hover:bg-blue-600 text-white py-2 px-4 rounded-md text-sm font-medium flex items-center">
<i class="fas fa-share-alt mr-2"></i> Chia sẻ
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Features Section -->
<div class="max-w-4xl mx-auto mt-12 mb-8">
<h2 class="text-2xl font-bold text-center mb-8">Tính năng nổi bật</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div class="bg-white p-6 rounded-xl shadow-sm hover:shadow-md transition">
<div class="text-blue-500 mb-3">
<i class="fas fa-bolt text-2xl"></i>
</div>
<h3 class="font-semibold mb-2">Tốc độ nhanh</h3>
<p class="text-gray-600 text-sm">Xử lý file chỉ trong vài giây với công nghệ đám mây hiện đại.</p>
</div>
<div class="bg-white p-6 rounded-xl shadow-sm hover:shadow-md transition">
<div class="text-green-500 mb-3">
<i class="fas fa-lock text-2xl"></i>
</div>
<h3 class="font-semibold mb-2">Bảo mật tuyệt đối</h3>
<p class="text-gray-600 text-sm">File của bạn sẽ tự động xóa sau 1 giờ, không lưu trữ dữ liệu.</p>
</div>
<div class="bg-white p-6 rounded-xl shadow-sm hover:shadow-md transition">
<div class="text-purple-500 mb-3">
<i class="fas fa-mobile-alt text-2xl"></i>
</div>
<h3 class="font-semibold mb-2">Mọi thiết bị</h3>
<p class="text-gray-600 text-sm">Tương thích với mọi trình duyệt và thiết bị di động.</p>
</div>
</div>
</div>
<!-- Toast Notification -->
<div id="toast" class="toast fixed bottom-4 right-4 bg-green-500 text-white px-4 py-2 rounded-md shadow-lg hidden">
<div class="flex items-center">
<i class="fas fa-check-circle mr-2"></i>
<span id="toastMessage"></span>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// DOM Elements
const fileDropArea = document.getElementById('fileDropArea');
const fileInput = document.getElementById('fileInput');
const fileInfo = document.getElementById('fileInfo');
const fileName = document.getElementById('fileName');
const fileSize = document.getElementById('fileSize');
const fileTypeIcon = document.getElementById('fileTypeIcon');
const removeFile = document.getElementById('removeFile');
const formatBtns = document.querySelectorAll('.format-btn');
const convertBtn = document.getElementById('convertBtn');
const progressContainer = document.getElementById('progressContainer');
const progressBar = document.getElementById('progressBar');
const progressText = document.getElementById('progressText');
const timeRemaining = document.getElementById('timeRemaining');
const resultContainer = document.getElementById('resultContainer');
const downloadBtn = document.getElementById('downloadBtn');
const shareBtn = document.getElementById('shareBtn');
const newConversion = document.getElementById('newConversion');
const advancedToggle = document.getElementById('advancedToggle');
const advancedOptions = document.getElementById('advancedOptions');
const toast = document.getElementById('toast');
const toastMessage = document.getElementById('toastMessage');
// Variables
let selectedFile = null;
let selectedFormat = null;
const fileIcons = {
'pdf': 'file-pdf',
'docx': 'file-word',
'xlsx': 'file-excel',
'pptx': 'file-powerpoint',
'txt': 'file-alt',
'rtf': 'file-alt',
'odt': 'file-alt',
'default': 'file'
};
const fileColors = {
'pdf': 'text-red-500',
'docx': 'text-blue-500',
'xlsx': 'text-green-500',
'pptx': 'text-orange-500',
'txt': 'text-gray-500',
'rtf': 'text-gray-500',
'odt': 'text-purple-500',
'default': 'text-blue-500'
};
// Event Listeners
fileDropArea.addEventListener('dragover', (e) => {
e.preventDefault();
fileDropArea.classList.add('active');
});
fileDropArea.addEventListener('dragleave', () => {
fileDropArea.classList.remove('active');
});
fileDropArea.addEventListener('drop', (e) => {
e.preventDefault();
fileDropArea.classList.remove('active');
if (e.dataTransfer.files.length) {
handleFileSelection(e.dataTransfer.files[0]);
}
});
fileInput.addEventListener('change', () => {
if (fileInput.files.length) {
handleFileSelection(fileInput.files[0]);
}
});
removeFile.addEventListener('click', (e) => {
e.stopPropagation();
resetFileSelection();
});
formatBtns.forEach(btn => {
btn.addEventListener('click', () => {
formatBtns.forEach(b => b.classList.remove('border-blue-500', 'bg-blue-100'));
btn.classList.add('border-blue-500', 'bg-blue-100');
selectedFormat = btn.getAttribute('data-format');
updateConvertButtonState();
});
});
convertBtn.addEventListener('click', startConversion);
newConversion.addEventListener('click', resetConversion);
advancedToggle.addEventListener('click', toggleAdvancedOptions);
downloadBtn.addEventListener('click', simulateDownload);
shareBtn.addEventListener('click', showShareOptions);
// Functions
function handleFileSelection(file) {
// Check file size (max 10MB)
if (file.size > 10 * 1024 * 1024) {
showToast('File quá lớn. Vui lòng chọn file nhỏ hơn 10MB.');
return;
}
selectedFile = file;
// Update UI
fileName.textContent = file.name;
fileSize.textContent = formatFileSize(file.size);
// Set file icon based on extension
const fileExt = getFileExtension(file.name);
const iconClass = fileIcons[fileExt] || fileIcons['default'];
const colorClass = fileColors[fileExt] || fileColors['default'];
// Reset all classes and add new ones
fileTypeIcon.className = 'fas mr-2';
fileTypeIcon.classList.add(`fa-${iconClass}`, colorClass);
fileInfo.classList.remove('hidden');
updateConvertButtonState();
}
function resetFileSelection() {
selectedFile = null;
fileInput.value = '';
fileInfo.classList.add('hidden');
updateConvertButtonState();
}
function getFileExtension(filename) {
return filename.split('.').pop().toLowerCase();
}
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
function updateConvertButtonState() {
convertBtn.disabled = !(selectedFile && selectedFormat);
}
function startConversion() {
if (!selectedFile || !selectedFormat) return;
// Show progress
progressContainer.classList.remove('hidden');
resultContainer.classList.add('hidden');
// Simulate conversion progress
let progress = 0;
const interval = setInterval(() => {
progress += Math.random() * 10;
if (progress > 100) progress = 100;
progressBar.style.width = `${progress}%`;
progressText.textContent = `${Math.round(progress)}%`;
// Update time remaining
const remaining = Math.max(0, Math.round((100 - progress) / 10));
timeRemaining.textContent = remaining > 0 ?
`Ước tính: ${remaining} giây` : 'Đang hoàn tất...';
if (progress === 100) {
clearInterval(interval);
setTimeout(showResult, 500);
}
}, 300);
}
function showResult() {
progressContainer.classList.add('hidden');
resultContainer.classList.remove('hidden');
// Set original file info
document.getElementById('originalFileName').textContent = selectedFile.name;
document.getElementById('originalFileSize').textContent = formatFileSize(selectedFile.size);
const fileExt = getFileExtension(selectedFile.name);
document.getElementById('originalFileType').textContent = fileExt.toUpperCase();
const originalIconClass = fileIcons[fileExt] || fileIcons['default'];
const originalColorClass = fileColors[fileExt] || fileColors['default'];
const originalFileIcon = document.getElementById('originalFileIcon');
originalFileIcon.className = 'fas mr-2';
originalFileIcon.classList.add(`fa-${originalIconClass}`, originalColorClass);
// Set converted file info
const convertedName = selectedFile.name.replace(/\.[^/.]+$/, '') + '.' + selectedFormat;
document.getElementById('convertedFileName').textContent = convertedName;
// Simulate a different file size
const convertedSize = Math.max(selectedFile.size * 0.8, selectedFile.size * 1.2);
document.getElementById('convertedFileSize').textContent = formatFileSize(convertedSize);
document.getElementById('convertedFileType').textContent = selectedFormat.toUpperCase();
const convertedIconClass = fileIcons[selectedFormat] || fileIcons['default'];
const convertedColorClass = fileColors[selectedFormat] || fileColors['default'];
const convertedFileIcon = document.getElementById('convertedFileIcon');
convertedFileIcon.className = 'fas mr-2';
convertedFileIcon.classList.add(`fa-${convertedIconClass}`, convertedColorClass);
}
function resetConversion() {
resultContainer.classList.add('hidden');
resetFileSelection();
formatBtns.forEach(b => b.classList.remove('border-blue-500', 'bg-blue-100'));
selectedFormat = null;
}
function toggleAdvancedOptions() {
advancedOptions.classList.toggle('hidden');
const icon = advancedToggle.querySelector('i');
icon.classList.toggle('rotate-180');
}
function simulateDownload() {
showToast('Đã bắt đầu tải xuống file chuyển đổi');
}
function showShareOptions() {
showToast('Chia sẻ file thành công');
}
function showToast(message) {
toastMessage.textContent = message;
toast.classList.remove('hidden');
setTimeout(() => {
toast.classList.add('hidden');
}, 3000);
}
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=ninhdapchai/ninhmedia-com" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>