Bundles a stretch of in-progress work across the SPA tools so the
tree returns to a coherent shippable state ahead of cutting a new
zddc-server stable image:
- landing: substantial rework of the project picker (sortable/filterable
table, presets refactor, ?projects= filter, ?v= channel propagation,
loading/error states)
- archive: presets cleanup, source.js refactor, filtering/url-state
alignment with the landing page
- mdedit: file-system module split, resizer, file-tree improvements,
base/toc styling tweaks
- transmittal/classifier: small template touch-ups for shared chrome
- shared: build-lib.sh helpers, new favicon.svg
- bootstrap, build.sh: pick up the channel-aware install/track zip
generation
- tests: new landing.spec.js, expanded archive/mdedit/build-label specs
- docs: CLAUDE.md picks up the zddc-server section and freshens the
alpha-build exception note
- regenerated artifacts: install.zip, track-{alpha,beta,stable}.zip,
*_alpha.html — these are produced by `sh build.sh` and per project
convention are committed alongside the source changes
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
113 lines
2.6 KiB
JavaScript
113 lines
2.6 KiB
JavaScript
/**
|
|
* Utility functions
|
|
*/
|
|
|
|
/**
|
|
* HTML-escape a string for safe insertion into innerHTML.
|
|
*/
|
|
function escapeHtml(text) {
|
|
const div = document.createElement('div');
|
|
div.textContent = text == null ? '' : String(text);
|
|
return div.innerHTML;
|
|
}
|
|
|
|
/**
|
|
* Debounce function calls
|
|
* @param {Function} func - Function to debounce
|
|
* @param {number} wait - Wait time in milliseconds
|
|
* @returns {Function} Debounced function
|
|
*/
|
|
function debounce(func, wait) {
|
|
let timeout;
|
|
return function () {
|
|
const context = this;
|
|
const args = arguments;
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(() => func.apply(context, args), wait);
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get file type icon based on file extension
|
|
* @param {string} fileName - Name of the file
|
|
* @returns {string} Emoji icon for the file type
|
|
*/
|
|
function getFileTypeIcon(fileName) {
|
|
const extension = zddc.splitExtension(fileName).extension;
|
|
|
|
const iconMap = {
|
|
// Documents
|
|
'md': '📝',
|
|
'markdown': '📝',
|
|
'txt': '📄',
|
|
'rtf': '📄',
|
|
'doc': '📘',
|
|
'docx': '📘',
|
|
'odt': '📘',
|
|
|
|
// Web files
|
|
'html': '🌐',
|
|
'htm': '🌐',
|
|
'css': '🎨',
|
|
'js': '⚡',
|
|
'json': '📋',
|
|
'xml': '📊',
|
|
'yaml': '⚙️',
|
|
'yml': '⚙️',
|
|
|
|
// PDFs and presentations
|
|
'pdf': '📕',
|
|
'ppt': '📊',
|
|
'pptx': '📊',
|
|
'odp': '📊',
|
|
|
|
// Spreadsheets
|
|
'xls': '📗',
|
|
'xlsx': '📗',
|
|
'csv': '📊',
|
|
'ods': '📗',
|
|
|
|
// Images
|
|
'png': '🖼️',
|
|
'jpg': '🖼️',
|
|
'jpeg': '🖼️',
|
|
'gif': '🖼️',
|
|
'svg': '🖼️',
|
|
'webp': '🖼️',
|
|
'bmp': '🖼️',
|
|
|
|
// Archives
|
|
'zip': '📦',
|
|
'rar': '📦',
|
|
'tar': '📦',
|
|
'gz': '📦',
|
|
'7z': '📦',
|
|
|
|
// Code files
|
|
'py': '🐍',
|
|
'java': '☕',
|
|
'cpp': '⚙️',
|
|
'c': '⚙️',
|
|
'h': '⚙️',
|
|
'php': '🔧',
|
|
'rb': '💎',
|
|
'go': '🔵',
|
|
'rs': '🦀',
|
|
'swift': '🧡',
|
|
'kt': '💜',
|
|
|
|
// Configuration
|
|
'ini': '⚙️',
|
|
'conf': '⚙️',
|
|
'cfg': '⚙️',
|
|
'env': '⚙️',
|
|
|
|
// Other
|
|
'log': '📃',
|
|
'sql': '🗄️',
|
|
'db': '🗄️',
|
|
'sqlite': '🗄️',
|
|
};
|
|
|
|
return iconMap[extension] || '📄';
|
|
}
|