diff --git a/specs/invent_new_ui_v4.md b/specs/invent_new_ui_v4.md new file mode 100644 index 0000000..fc14fc9 --- /dev/null +++ b/specs/invent_new_ui_v4.md @@ -0,0 +1,360 @@ +# Themed Hybrid UI Component Specification v4 + +## Evolution from v3: Modular Architecture + +This specification builds upon v3's successful themed hybrid component approach with a critical architectural improvement: **separation of concerns through modular file structure**. While v3 delivered powerful themed components in single HTML files, v4 embraces modern development practices by splitting each component into three distinct files within organized directories. + +### Key Improvements in v4: +- **Maintainability**: Styles and scripts can be modified without touching HTML structure +- **Reusability**: CSS themes and JavaScript behaviors can be extended or shared +- **Performance**: Better browser caching, conditional loading, and optimization opportunities +- **Collaboration**: Teams can work on styling, structure, and behavior independently +- **Scalability**: Components are ready for integration into larger systems +- **Developer Experience**: Clean separation follows industry best practices + +## Core Challenge (Enhanced) +Create a **uniquely themed UI component** that combines multiple existing UI elements into one elegant solution, now with **professional-grade file organization** that demonstrates mastery of modern web development practices. + +Apply a distinctive design language while solving multiple interface problems in a single, cohesive component - achieving "two birds with one stone" efficiency through both functional integration and architectural excellence. + +## Output Requirements + +**Directory Structure**: `ui_hybrid_[iteration_number]/` + +Each iteration creates its own directory containing exactly three files: +``` +ui_hybrid_[iteration_number]/ +├── index.html # Semantic HTML structure +├── styles.css # Complete styling and theme implementation +└── script.js # All JavaScript functionality and interactions +``` + +**File Naming**: +- Directory: `ui_hybrid_[iteration_number]` (e.g., `ui_hybrid_1`, `ui_hybrid_2`) +- Files: Always `index.html`, `styles.css`, `script.js` (consistent naming) + +## Content Structure + +### **index.html** - Semantic Structure +```html + + +
+ + +Let your search grow organically
+Smart form interactions with minimal design
+FILE: ${item.name}
+TYPE: ${item.type}
+SIZE: ${item.size}
+DATE: ${item.modified}
+${item.rawData}
+ `;
+
+ // Show preview panel on mobile
+ const preview = document.querySelector('.data-preview');
+ preview.classList.add('active');
+ }
+
+ closePreview() {
+ const preview = document.querySelector('.data-preview');
+ preview.classList.remove('active');
+ }
+
+ executeCommand(command) {
+ const cmd = command.toUpperCase().trim();
+
+ switch (cmd) {
+ case 'CLS':
+ case 'CLEAR':
+ this.filteredData = [];
+ this.updateDisplay();
+ this.showMessage('SCREEN CLEARED');
+ break;
+ case 'DIR':
+ case 'LS':
+ this.showMessage(`${this.data.length} FILES IN DIRECTORY`);
+ break;
+ case 'HELP':
+ this.showMessage('COMMANDS: CLS, DIR, SORT, FILTER, EXIT');
+ break;
+ case 'EXIT':
+ this.showMessage('CANNOT EXIT - SYSTEM LOCKED');
+ break;
+ default:
+ if (cmd.startsWith('FILTER ')) {
+ const query = cmd.substring(7);
+ document.getElementById('search-filter').value = query;
+ this.handleSearch(query);
+ } else if (cmd.startsWith('SORT ')) {
+ const column = cmd.substring(5).toLowerCase();
+ if (this.columns.includes(column)) {
+ this.handleSort(column);
+ }
+ } else {
+ this.showMessage('UNKNOWN COMMAND - TYPE HELP');
+ }
+ }
+ }
+
+ showMessage(message) {
+ const commandInput = document.querySelector('.command-input');
+ const originalPlaceholder = commandInput.placeholder;
+ commandInput.placeholder = message;
+
+ setTimeout(() => {
+ commandInput.placeholder = originalPlaceholder;
+ }, 3000);
+ }
+
+ initColumnResizing() {
+ let isResizing = false;
+ let currentColumn = null;
+ let startX = 0;
+ let startWidth = 0;
+
+ document.querySelectorAll('.resize-handle').forEach(handle => {
+ handle.addEventListener('mousedown', (e) => {
+ isResizing = true;
+ currentColumn = handle.parentElement;
+ startX = e.pageX;
+ startWidth = currentColumn.offsetWidth;
+
+ document.body.style.cursor = 'col-resize';
+ e.preventDefault();
+ });
+ });
+
+ document.addEventListener('mousemove', (e) => {
+ if (!isResizing) return;
+
+ const width = startWidth + (e.pageX - startX);
+ if (width > 50) {
+ currentColumn.style.width = `${width}px`;
+ }
+ });
+
+ document.addEventListener('mouseup', () => {
+ isResizing = false;
+ currentColumn = null;
+ document.body.style.cursor = 'default';
+ });
+ }
+
+ startSystemClock() {
+ const updateClock = () => {
+ const now = new Date();
+ const hours = String(now.getHours()).padStart(2, '0');
+ const minutes = String(now.getMinutes()).padStart(2, '0');
+ const seconds = String(now.getSeconds()).padStart(2, '0');
+
+ document.getElementById('system-time').textContent = `${hours}:${minutes}:${seconds}`;
+ };
+
+ updateClock();
+ setInterval(updateClock, 1000);
+ }
+
+ simulateMemoryUsage() {
+ const memoryBar = document.querySelector('.memory-used');
+ const memoryText = document.querySelector('.memory-text');
+
+ setInterval(() => {
+ const used = 640 + Math.floor(Math.random() * 100);
+ const percentage = (used / 1024) * 100;
+
+ memoryBar.style.width = `${percentage}%`;
+ memoryText.textContent = `${used}K/1024K`;
+
+ if (percentage > 90) {
+ memoryBar.style.backgroundColor = 'var(--error-red)';
+ } else if (percentage > 75) {
+ memoryBar.style.backgroundColor = 'var(--warning-yellow)';
+ } else {
+ memoryBar.style.backgroundColor = 'var(--terminal-text)';
+ }
+ }, 2000);
+ }
+}
+
+// Initialize on DOM ready
+document.addEventListener('DOMContentLoaded', () => {
+ window.dataExplorer = new DataExplorer();
+
+ // Add keyboard shortcuts
+ document.addEventListener('keydown', (e) => {
+ if (e.ctrlKey || e.metaKey) {
+ switch (e.key) {
+ case 'f':
+ e.preventDefault();
+ document.getElementById('search-filter').focus();
+ break;
+ case 'e':
+ e.preventDefault();
+ window.dataExplorer.handleAction('export');
+ break;
+ case 'r':
+ e.preventDefault();
+ window.dataExplorer.handleAction('refresh');
+ break;
+ }
+ }
+ });
+});
+
+// Add some retro console messages
+console.log('%c╔════════════════════════════╗', 'color: #00ff00');
+console.log('%c║ DATACOM-3000 SYSTEM v2.31 ║', 'color: #00ff00');
+console.log('%c║ (C) 1990 RETROTECH CORP ║', 'color: #00ff00');
+console.log('%c╚════════════════════════════╝', 'color: #00ff00');
+console.log('%cSYSTEM INITIALIZED', 'color: #ffb000');
+console.log('%cMEMORY: 640K OK', 'color: #00ff00');
+console.log('%cREADY.', 'color: #00ff00');
\ No newline at end of file
diff --git a/src_group/ui_hybrid_3/styles.css b/src_group/ui_hybrid_3/styles.css
new file mode 100644
index 0000000..80607b5
--- /dev/null
+++ b/src_group/ui_hybrid_3/styles.css
@@ -0,0 +1,518 @@
+/* DATACOM-3000 Retro Computing Theme */
+:root {
+ /* Terminal Colors */
+ --terminal-green: #00ff00;
+ --terminal-amber: #ffb000;
+ --terminal-bg: #0a0a0a;
+ --terminal-bg-light: #1a1a1a;
+ --terminal-border: #333333;
+ --terminal-glow: rgba(0, 255, 0, 0.5);
+ --terminal-text: #00ff00;
+ --terminal-dim: #00aa00;
+
+ /* System Colors */
+ --error-red: #ff0040;
+ --warning-yellow: #ffff00;
+ --info-cyan: #00ffff;
+
+ /* Typography */
+ --font-mono: 'Courier New', Courier, monospace;
+ --font-size-base: 14px;
+ --line-height: 1.4;
+
+ /* Spacing */
+ --spacing-xs: 4px;
+ --spacing-sm: 8px;
+ --spacing-md: 16px;
+ --spacing-lg: 24px;
+
+ /* Effects */
+ --scanline-opacity: 0.05;
+ --crt-curve: 0.02;
+}
+
+/* Global Reset and Base Styles */
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: var(--font-mono);
+ font-size: var(--font-size-base);
+ line-height: var(--line-height);
+ background-color: #000;
+ color: var(--terminal-text);
+ overflow: hidden;
+ text-transform: uppercase;
+}
+
+/* CRT Effect Container */
+.terminal-container {
+ position: relative;
+ width: 100vw;
+ height: 100vh;
+ background-color: var(--terminal-bg);
+ border: 2px solid var(--terminal-border);
+ overflow: hidden;
+ box-shadow:
+ inset 0 0 20px rgba(0, 255, 0, 0.1),
+ 0 0 40px var(--terminal-glow);
+}
+
+/* Terminal Header */
+.terminal-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: var(--spacing-sm) var(--spacing-md);
+ background-color: var(--terminal-bg-light);
+ border-bottom: 2px solid var(--terminal-border);
+}
+
+.terminal-title {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+}
+
+.terminal-icon {
+ color: var(--terminal-amber);
+ animation: blink 2s infinite;
+}
+
+.terminal-title h1 {
+ font-size: 16px;
+ font-weight: normal;
+ letter-spacing: 2px;
+}
+
+.terminal-controls {
+ display: flex;
+ gap: var(--spacing-xs);
+}
+
+.terminal-btn {
+ width: 20px;
+ height: 20px;
+ background-color: transparent;
+ border: 1px solid var(--terminal-text);
+ color: var(--terminal-text);
+ cursor: pointer;
+ font-family: inherit;
+ font-size: 12px;
+ transition: all 0.2s;
+}
+
+.terminal-btn:hover {
+ background-color: var(--terminal-text);
+ color: var(--terminal-bg);
+ box-shadow: 0 0 10px var(--terminal-glow);
+}
+
+/* Command Bar */
+.command-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: var(--spacing-sm) var(--spacing-md);
+ background-color: var(--terminal-bg-light);
+ border-bottom: 1px solid var(--terminal-border);
+}
+
+.command-prompt {
+ display: flex;
+ align-items: center;
+ flex: 1;
+}
+
+.prompt-symbol {
+ color: var(--terminal-amber);
+ margin-right: var(--spacing-sm);
+}
+
+.command-input {
+ flex: 1;
+ background-color: transparent;
+ border: none;
+ color: var(--terminal-text);
+ font-family: inherit;
+ font-size: inherit;
+ outline: none;
+}
+
+.command-input::placeholder {
+ color: var(--terminal-dim);
+}
+
+.status-indicators {
+ display: flex;
+ gap: var(--spacing-md);
+}
+
+.indicator {
+ padding: 2px 8px;
+ border: 1px solid var(--terminal-text);
+ font-size: 12px;
+}
+
+.indicator[data-status="active"] {
+ background-color: var(--terminal-text);
+ color: var(--terminal-bg);
+ animation: pulse 2s infinite;
+}
+
+.indicator[data-status="idle"] {
+ color: var(--terminal-dim);
+ border-color: var(--terminal-dim);
+}
+
+/* Data Explorer Main Area */
+.data-explorer {
+ display: flex;
+ flex-direction: column;
+ height: calc(100vh - 120px);
+}
+
+/* Controls Panel */
+.controls-panel {
+ display: flex;
+ gap: var(--spacing-lg);
+ padding: var(--spacing-md);
+ background-color: var(--terminal-bg-light);
+ border-bottom: 1px solid var(--terminal-border);
+}
+
+.filter-group,
+.sort-group,
+.action-group {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+}
+
+.control-label {
+ color: var(--terminal-amber);
+ font-size: 12px;
+}
+
+.filter-input,
+.sort-select {
+ background-color: var(--terminal-bg);
+ border: 1px solid var(--terminal-border);
+ color: var(--terminal-text);
+ padding: var(--spacing-xs) var(--spacing-sm);
+ font-family: inherit;
+ font-size: inherit;
+ outline: none;
+}
+
+.filter-input:focus,
+.sort-select:focus {
+ border-color: var(--terminal-text);
+ box-shadow: 0 0 5px var(--terminal-glow);
+}
+
+.sort-direction {
+ background-color: transparent;
+ border: 1px solid var(--terminal-border);
+ color: var(--terminal-text);
+ padding: var(--spacing-xs);
+ cursor: pointer;
+ font-family: inherit;
+}
+
+.action-btn {
+ background-color: var(--terminal-bg);
+ border: 1px solid var(--terminal-border);
+ color: var(--terminal-text);
+ padding: var(--spacing-xs) var(--spacing-md);
+ cursor: pointer;
+ font-family: inherit;
+ font-size: 12px;
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-xs);
+ transition: all 0.2s;
+}
+
+.action-btn:hover {
+ border-color: var(--terminal-text);
+ box-shadow: 0 0 10px var(--terminal-glow);
+ transform: translateY(-1px);
+}
+
+.btn-icon {
+ color: var(--terminal-amber);
+}
+
+/* Data Viewport */
+.data-viewport {
+ flex: 1;
+ display: flex;
+ overflow: hidden;
+}
+
+/* Data Table */
+.data-table-wrapper {
+ flex: 1;
+ overflow: auto;
+ background-color: var(--terminal-bg);
+}
+
+.data-table {
+ width: 100%;
+ border-collapse: collapse;
+}
+
+.column-header {
+ position: relative;
+ padding: var(--spacing-sm) var(--spacing-md);
+ background-color: var(--terminal-bg-light);
+ border: 1px solid var(--terminal-border);
+ color: var(--terminal-amber);
+ text-align: left;
+ cursor: pointer;
+ user-select: none;
+}
+
+.column-header:hover {
+ background-color: #2a2a2a;
+}
+
+.header-text {
+ display: inline-block;
+}
+
+.resize-handle {
+ position: absolute;
+ right: 0;
+ top: 0;
+ width: 4px;
+ height: 100%;
+ cursor: col-resize;
+ background-color: transparent;
+}
+
+.resize-handle:hover {
+ background-color: var(--terminal-text);
+}
+
+.data-table tbody tr {
+ border-bottom: 1px solid var(--terminal-border);
+ transition: background-color 0.2s;
+}
+
+.data-table tbody tr:hover {
+ background-color: var(--terminal-bg-light);
+}
+
+.data-table tbody tr.selected {
+ background-color: rgba(0, 255, 0, 0.1);
+ box-shadow: inset 0 0 20px var(--terminal-glow);
+}
+
+.data-table td {
+ padding: var(--spacing-sm) var(--spacing-md);
+ color: var(--terminal-text);
+ font-size: 13px;
+}
+
+/* Data Preview */
+.data-preview {
+ width: 300px;
+ background-color: var(--terminal-bg-light);
+ border-left: 2px solid var(--terminal-border);
+ display: flex;
+ flex-direction: column;
+}
+
+.preview-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: var(--spacing-sm) var(--spacing-md);
+ border-bottom: 1px solid var(--terminal-border);
+}
+
+.preview-header h3 {
+ font-size: 14px;
+ font-weight: normal;
+ color: var(--terminal-amber);
+}
+
+.preview-close {
+ background-color: transparent;
+ border: 1px solid var(--terminal-text);
+ color: var(--terminal-text);
+ padding: 2px 6px;
+ cursor: pointer;
+ font-family: inherit;
+ font-size: 12px;
+}
+
+.preview-content {
+ flex: 1;
+ padding: var(--spacing-md);
+ overflow: auto;
+}
+
+.ascii-art {
+ color: var(--terminal-dim);
+ font-size: 12px;
+ line-height: 1.2;
+}
+
+/* Status Bar */
+.status-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: var(--spacing-sm) var(--spacing-md);
+ background-color: var(--terminal-bg-light);
+ border-top: 2px solid var(--terminal-border);
+}
+
+.memory-usage {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+}
+
+.memory-bar {
+ width: 100px;
+ height: 10px;
+ background-color: var(--terminal-bg);
+ border: 1px solid var(--terminal-border);
+ position: relative;
+ overflow: hidden;
+}
+
+.memory-used {
+ position: absolute;
+ left: 0;
+ top: 0;
+ height: 100%;
+ width: 62.5%;
+ background-color: var(--terminal-text);
+ animation: memory-pulse 3s infinite;
+}
+
+.label {
+ color: var(--terminal-amber);
+ font-size: 12px;
+}
+
+.memory-text,
+#record-count,
+#system-time {
+ font-size: 12px;
+}
+
+/* CRT Scanlines Effect */
+.scanlines {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+ background: linear-gradient(
+ transparent 50%,
+ rgba(0, 255, 0, var(--scanline-opacity)) 50%
+ );
+ background-size: 100% 4px;
+ animation: scanlines 8s linear infinite;
+}
+
+/* Animations */
+@keyframes blink {
+ 0%, 50% { opacity: 1; }
+ 51%, 100% { opacity: 0; }
+}
+
+@keyframes pulse {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0.6; }
+}
+
+@keyframes memory-pulse {
+ 0%, 100% { opacity: 0.8; }
+ 50% { opacity: 1; }
+}
+
+@keyframes scanlines {
+ 0% { transform: translateY(0); }
+ 100% { transform: translateY(4px); }
+}
+
+/* Scrollbar Styling */
+::-webkit-scrollbar {
+ width: 12px;
+ height: 12px;
+}
+
+::-webkit-scrollbar-track {
+ background-color: var(--terminal-bg);
+ border: 1px solid var(--terminal-border);
+}
+
+::-webkit-scrollbar-thumb {
+ background-color: var(--terminal-dim);
+ border: 1px solid var(--terminal-border);
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background-color: var(--terminal-text);
+}
+
+/* Responsive Design */
+@media (max-width: 1024px) {
+ .data-preview {
+ position: absolute;
+ right: 0;
+ top: 0;
+ height: 100%;
+ transform: translateX(100%);
+ transition: transform 0.3s;
+ }
+
+ .data-preview.active {
+ transform: translateX(0);
+ }
+}
+
+@media (max-width: 768px) {
+ .controls-panel {
+ flex-wrap: wrap;
+ }
+
+ .action-group {
+ width: 100%;
+ justify-content: space-between;
+ }
+}
+
+/* Accessibility Focus Styles */
+*:focus {
+ outline: 2px solid var(--terminal-amber);
+ outline-offset: 2px;
+}
+
+/* Print Styles */
+@media print {
+ .terminal-container {
+ box-shadow: none;
+ border: 1px solid #000;
+ }
+
+ .scanlines {
+ display: none;
+ }
+
+ * {
+ color: #000 !important;
+ background-color: #fff !important;
+ }
+}
\ No newline at end of file
diff --git a/src_group/ui_hybrid_4/index.html b/src_group/ui_hybrid_4/index.html
new file mode 100644
index 0000000..25f1b2a
--- /dev/null
+++ b/src_group/ui_hybrid_4/index.html
@@ -0,0 +1,145 @@
+
+
+
+
+
+ No Artist
+ +Your Elegant Time Companion
+Please select a time to convert
'; + return; + } + + const [hours, minutes] = time.split(':').map(Number); + const date = new Date(); + date.setHours(hours, minutes, 0, 0); + + const zones = [ + { name: 'New York', tz: 'America/New_York' }, + { name: 'London', tz: 'Europe/London' }, + { name: 'Paris', tz: 'Europe/Paris' }, + { name: 'Tokyo', tz: 'Asia/Tokyo' } + ]; + + results.innerHTML = '${zone.name}: ${convertedTime}
`; + }); + } + + // Deadlines Functionality + setupDeadlines() { + const form = document.getElementById('deadlineForm'); + form.addEventListener('submit', (e) => { + e.preventDefault(); + this.addDeadline(); + }); + + this.renderDeadlines(); + setInterval(() => this.updateDeadlineCountdowns(), 60000); // Update every minute + } + + addDeadline() { + const title = document.getElementById('deadlineTitle').value; + const date = document.getElementById('deadlineDate').value; + const priority = document.getElementById('deadlinePriority').value; + + if (title && date) { + const deadline = { + id: Date.now(), + title, + date: new Date(date), + priority + }; + + this.deadlines.push(deadline); + this.deadlines.sort((a, b) => a.date - b.date); + this.saveToStorage('deadlines', this.deadlines); + this.renderDeadlines(); + + // Reset form + document.getElementById('deadlineForm').reset(); + } + } + + renderDeadlines() { + const list = document.getElementById('deadlinesList'); + list.innerHTML = ''; + + if (this.deadlines.length === 0) { + list.innerHTML = '