docs: consolidate documentation into organized structure

- Move 12 markdown files from root to docs/ subdirectories
- Organize documentation by category:
  • docs/troubleshooting/ (1 file)  - Technical troubleshooting guides
  • docs/deployment/      (4 files) - Deployment and security documentation
  • docs/guides/          (3 files) - Feature-specific guides
  • docs/planning/        (4 files) - Planning and improvement proposals

Root directory cleanup:
- Reduced from 16 to 4 markdown files in root
- Only essential project files remain:
  • CLAUDE.md (AI instructions)
  • README.md (Main project readme)
  • CLEANUP_PLAN.md (Current cleanup plan)
  • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements)

This improves:
 Documentation discoverability
 Logical organization by purpose
 Clean root directory
 Better maintainability
This commit is contained in:
2025-10-05 11:05:04 +02:00
parent 887847dde6
commit 5050c7d73a
36686 changed files with 196456 additions and 12398919 deletions

152
public/js/test-upload.js Normal file
View File

@@ -0,0 +1,152 @@
/**
* Test script for JavaScript upload functionality
*/
import uploadManager, { FileValidator } from './utils/upload.js';
// Wait for DOM to be ready
document.addEventListener('DOMContentLoaded', () => {
const fileInput = document.getElementById('test-upload');
const uploadButton = document.getElementById('upload-button');
const progressBar = document.getElementById('progress-bar');
const progressText = document.getElementById('progress-text');
const results = document.getElementById('results');
if (!fileInput || !uploadButton) {
console.log('Upload test elements not found on this page');
return;
}
uploadButton.addEventListener('click', async () => {
const files = Array.from(fileInput.files);
if (files.length === 0) {
showMessage('Please select at least one file', 'error');
return;
}
// Validate files
for (const file of files) {
const errors = FileValidator.validateImage(file);
if (errors.length > 0) {
showMessage(`File ${file.name}: ${errors.join(', ')}`, 'error');
return;
}
}
try {
uploadButton.disabled = true;
showMessage('Starting upload...', 'info');
if (files.length === 1) {
// Single file upload
await uploadSingleFile(files[0]);
} else {
// Multiple file upload
await uploadMultipleFiles(files);
}
} catch (error) {
showMessage(`Upload failed: ${error.message}`, 'error');
} finally {
uploadButton.disabled = false;
progressBar.style.width = '0%';
progressText.textContent = '';
}
});
async function uploadSingleFile(file) {
const result = await uploadManager.uploadImage(file, {
altText: `Uploaded image: ${file.name}`,
onProgress: (percent, loaded, total) => {
updateProgress(percent, `Uploading ${file.name}...`);
}
});
showUploadResult(result, file.name);
}
async function uploadMultipleFiles(files) {
const results = await uploadManager.uploadMultipleImages(files, {
onProgress: (overallPercent, currentIndex, totalFiles) => {
updateProgress(overallPercent, `Uploading file ${currentIndex + 1} of ${totalFiles}...`);
},
onFileComplete: (result, index, total) => {
showMessage(`Completed ${index + 1}/${total}: ${files[index].name}`, 'success');
}
});
showMessage(`Upload completed. ${results.filter(r => r.success).length}/${results.length} files successful`, 'info');
results.forEach(result => {
showUploadResult(result.success ? result.data : null, result.file, result.error);
});
}
function updateProgress(percent, text) {
progressBar.style.width = `${percent}%`;
progressText.textContent = `${text} (${Math.round(percent)}%)`;
}
function showMessage(message, type = 'info') {
const messageDiv = document.createElement('div');
messageDiv.className = `message message-${type}`;
messageDiv.textContent = message;
results.insertBefore(messageDiv, results.firstChild);
// Remove after 5 seconds
setTimeout(() => {
if (messageDiv.parentNode) {
messageDiv.remove();
}
}, 5000);
}
function showUploadResult(uploadData, fileName, error = null) {
const resultDiv = document.createElement('div');
resultDiv.className = 'upload-result';
if (error) {
resultDiv.innerHTML = `
<h4>❌ ${fileName}</h4>
<p class="error">Error: ${error}</p>
`;
} else {
resultDiv.innerHTML = `
<h4>✅ ${fileName}</h4>
<div class="result-details">
<p><strong>ULID:</strong> ${uploadData.ulid}</p>
<p><strong>Filename:</strong> ${uploadData.filename}</p>
<p><strong>Size:</strong> ${uploadData.file_size.human_readable}</p>
<p><strong>Dimensions:</strong> ${uploadData.dimensions.width}x${uploadData.dimensions.height}</p>
<p><strong>MIME Type:</strong> ${uploadData.mime_type}</p>
<img src="${uploadData.thumbnail_url}" alt="${uploadData.alt_text}" style="max-width: 150px; margin-top: 10px;">
</div>
`;
}
results.appendChild(resultDiv);
}
});
// Test CSRF token functionality
async function testCsrfTokens() {
try {
console.log('Testing CSRF token generation...');
const tokens = await uploadManager.getCsrfTokens('/api/images', 'post');
console.log('CSRF tokens received:', {
form_id: tokens.form_id,
token: tokens.token.substring(0, 10) + '...',
headers: tokens.headers
});
return tokens;
} catch (error) {
console.error('CSRF token test failed:', error);
throw error;
}
}
// Make test function available globally for console testing
window.testCsrfTokens = testCsrfTokens;
window.uploadManager = uploadManager;
window.FileValidator = FileValidator;