Spaces:
Running
Running
| <html lang="de"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>CodeFlow Pro - CSS Playground & Archiv</title> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| /* ===== MODERN CSS RESET & BASE ===== */ | |
| *, *::before, *::after { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| :root { | |
| --primary: #6366f1; | |
| --primary-dark: #4f46e5; | |
| --secondary: #10b981; | |
| --danger: #ef4444; | |
| --warning: #f59e0b; | |
| --dark: #1f2937; | |
| --darker: #111827; | |
| --light: #f9fafb; | |
| --gray: #9ca3af; | |
| --border-radius: 12px; | |
| --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); | |
| --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); | |
| --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1); | |
| --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1); | |
| --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1); | |
| } | |
| html { scroll-behavior: smooth; } | |
| body { | |
| font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | |
| background: linear-gradient(135deg, var(--darker) 0%, var(--dark) 100%); | |
| color: var(--light); | |
| min-height: 100vh; | |
| display: grid; | |
| grid-template-rows: auto 1fr; | |
| line-height: 1.6; | |
| } | |
| /* ===== HEADER ===== */ | |
| .header { | |
| background: rgba(31, 41, 55, 0.95); | |
| backdrop-filter: blur(10px); | |
| border-bottom: 1px solid rgba(255, 255, 255, 0.1); | |
| padding: 1rem 2rem; | |
| position: sticky; | |
| top: 0; | |
| z-index: 100; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| flex-wrap: wrap; | |
| gap: 1rem; | |
| } | |
| .logo-section { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.75rem; | |
| } | |
| .logo { | |
| width: 40px; | |
| height: 40px; | |
| background: linear-gradient(135deg, var(--primary), var(--secondary)); | |
| border-radius: 10px; | |
| display: grid; | |
| place-items: center; | |
| font-weight: bold; | |
| font-size: 1.25rem; | |
| } | |
| .brand { | |
| font-size: 1.5rem; | |
| font-weight: 700; | |
| background: linear-gradient(135deg, var(--primary), var(--secondary)); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| } | |
| .anycoder-link { | |
| background: var(--primary); | |
| color: white; | |
| padding: 0.5rem 1rem; | |
| border-radius: 20px; | |
| text-decoration: none; | |
| font-size: 0.875rem; | |
| font-weight: 600; | |
| transition: var(--transition); | |
| box-shadow: var(--shadow-md); | |
| } | |
| .anycoder-link:hover { | |
| background: var(--primary-dark); | |
| transform: translateY(-2px); | |
| box-shadow: var(--shadow-lg); | |
| } | |
| /* ===== NAVIGATION TABS ===== */ | |
| .nav-tabs { | |
| display: flex; | |
| gap: 0.5rem; | |
| overflow-x: auto; | |
| scrollbar-width: none; | |
| } | |
| .nav-tabs::-webkit-scrollbar { display: none; } | |
| .tab-btn { | |
| background: rgba(255, 255, 255, 0.05); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| color: var(--gray); | |
| padding: 0.75rem 1.5rem; | |
| border-radius: 8px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| transition: var(--transition); | |
| white-space: nowrap; | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .tab-btn:hover { | |
| background: rgba(255, 255, 255, 0.1); | |
| color: var(--light); | |
| } | |
| .tab-btn.active { | |
| background: var(--primary); | |
| color: white; | |
| border-color: var(--primary); | |
| box-shadow: var(--shadow-md); | |
| } | |
| .tab-btn .badge { | |
| background: var(--danger); | |
| color: white; | |
| padding: 0.125rem 0.5rem; | |
| border-radius: 10px; | |
| font-size: 0.75rem; | |
| font-weight: 700; | |
| } | |
| /* ===== MAIN CONTENT ===== */ | |
| .main-content { | |
| padding: 2rem; | |
| container-type: inline-size; | |
| overflow-y: auto; | |
| } | |
| .tab-panel { | |
| display: none; | |
| animation: fadeIn 0.3s ease-in-out; | |
| } | |
| .tab-panel.active { display: block; } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| /* ===== UPLOAD SECTION ===== */ | |
| .upload-zone { | |
| background: rgba(255, 255, 255, 0.03); | |
| border: 2px dashed rgba(255, 255, 255, 0.2); | |
| border-radius: var(--border-radius); | |
| padding: 3rem; | |
| text-align: center; | |
| transition: var(--transition); | |
| cursor: pointer; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .upload-zone:hover { | |
| border-color: var(--primary); | |
| background: rgba(99, 102, 241, 0.05); | |
| } | |
| .upload-zone.dragover { | |
| border-color: var(--secondary); | |
| background: rgba(16, 185, 129, 0.1); | |
| transform: scale(1.02); | |
| } | |
| .upload-icon { | |
| font-size: 3rem; | |
| color: var(--gray); | |
| margin-bottom: 1rem; | |
| } | |
| .upload-text { | |
| font-size: 1.25rem; | |
| margin-bottom: 0.5rem; | |
| } | |
| .upload-hint { | |
| color: var(--gray); | |
| font-size: 0.875rem; | |
| } | |
| .file-input { display: none; } | |
| .action-buttons { | |
| display: flex; | |
| gap: 1rem; | |
| margin-top: 2rem; | |
| flex-wrap: wrap; | |
| } | |
| .btn { | |
| background: var(--primary); | |
| color: white; | |
| border: none; | |
| padding: 0.75rem 1.5rem; | |
| border-radius: 8px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| transition: var(--transition); | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| box-shadow: var(--shadow-sm); | |
| } | |
| .btn:hover { | |
| background: var(--primary-dark); | |
| transform: translateY(-2px); | |
| box-shadow: var(--shadow-md); | |
| } | |
| .btn-secondary { background: var(--secondary); } | |
| .btn-secondary:hover { background: #059669; } | |
| .btn-danger { background: var(--danger); } | |
| .btn-danger:hover { background: #dc2626; } | |
| .btn-warning { background: var(--warning); } | |
| .btn-warning:hover { background: #d97706; } | |
| /* ===== MODULE GRID & CSS CARDS ===== */ | |
| .module-grid { | |
| display: grid; | |
| gap: 1.5rem; | |
| grid-template-columns: repeat(auto-fill, minmax(450px, 1fr)); | |
| margin-top: 2rem; | |
| } | |
| @container (max-width: 1000px) { | |
| .module-grid { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| .module-card { | |
| background: rgba(255, 255, 255, 0.05); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| border-radius: var(--border-radius); | |
| overflow: hidden; | |
| transition: var(--transition); | |
| position: relative; | |
| } | |
| .module-card:hover { | |
| transform: translateY(-4px); | |
| box-shadow: var(--shadow-xl); | |
| border-color: rgba(99, 102, 241, 0.3); | |
| } | |
| .module-card.selected { | |
| border-color: var(--secondary); | |
| background: rgba(16, 185, 129, 0.05); | |
| } | |
| .module-header { | |
| background: rgba(255, 255, 255, 0.03); | |
| padding: 1rem 1.5rem; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| border-bottom: 1px solid rgba(255, 255, 255, 0.05); | |
| gap: 1rem; | |
| } | |
| .module-title { | |
| font-weight: 700; | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| flex: 1; | |
| } | |
| .module-checkbox { | |
| width: 18px; | |
| height: 18px; | |
| cursor: pointer; | |
| accent-color: var(--secondary); | |
| } | |
| .module-status { | |
| width: 8px; | |
| height: 8px; | |
| border-radius: 50%; | |
| background: var(--secondary); | |
| animation: pulse 2s infinite; | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { opacity: 1; } | |
| 50% { opacity: 0.5; } | |
| } | |
| .module-actions { | |
| display: flex; | |
| gap: 0.5rem; | |
| } | |
| .icon-btn { | |
| background: rgba(255, 255, 255, 0.1); | |
| border: none; | |
| color: var(--light); | |
| width: 32px; | |
| height: 32px; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| display: grid; | |
| place-items: center; | |
| transition: var(--transition); | |
| } | |
| .icon-btn:hover { | |
| background: var(--primary); | |
| transform: scale(1.1); | |
| } | |
| .module-content { | |
| padding: 1.5rem; | |
| } | |
| .css-preview { | |
| background: rgba(0, 0, 0, 0.3); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| border-radius: 8px; | |
| padding: 1rem; | |
| margin-bottom: 1rem; | |
| min-height: 100px; | |
| max-height: 250px; | |
| overflow-y: auto; | |
| } | |
| .css-editor { | |
| background: rgba(0, 0, 0, 0.3); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| border-radius: 8px; | |
| padding: 1rem; | |
| font-family: 'Fira Code', 'Courier New', monospace; | |
| font-size: 0.875rem; | |
| min-height: 150px; | |
| max-height: 300px; | |
| overflow-y: auto; | |
| position: relative; | |
| white-space: pre-wrap; | |
| word-wrap: break-word; | |
| } | |
| .css-editor:focus { | |
| outline: 2px solid var(--primary); | |
| outline-offset: 2px; | |
| } | |
| .css-controls { | |
| display: grid; | |
| gap: 0.75rem; | |
| margin-top: 1rem; | |
| grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
| } | |
| .control-group { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.25rem; | |
| } | |
| .control-group label { | |
| font-size: 0.875rem; | |
| color: var(--gray); | |
| display: flex; | |
| justify-content: space-between; | |
| } | |
| .control-group input[type="range"], | |
| .control-group input[type="text"], | |
| .control-group input[type="color"], | |
| .control-group select { | |
| background: rgba(255, 255, 255, 0.05); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| border-radius: 6px; | |
| padding: 0.5rem; | |
| color: var(--light); | |
| transition: var(--transition); | |
| } | |
| .control-group input:focus { | |
| border-color: var(--primary); | |
| outline: none; | |
| } | |
| .control-group input[type="range"] { | |
| padding: 0; | |
| height: 6px; | |
| -webkit-appearance: none; | |
| background: rgba(255, 255, 255, 0.1); | |
| } | |
| .control-group input[type="range"]::-webkit-slider-thumb { | |
| -webkit-appearance: none; | |
| width: 16px; | |
| height: 16px; | |
| border-radius: 50%; | |
| background: var(--primary); | |
| cursor: pointer; | |
| } | |
| .copy-indicator { | |
| position: absolute; | |
| top: 0.5rem; | |
| right: 0.5rem; | |
| background: var(--secondary); | |
| color: white; | |
| padding: 0.25rem 0.75rem; | |
| border-radius: 4px; | |
| font-size: 0.75rem; | |
| opacity: 0; | |
| transition: opacity 0.3s; | |
| pointer-events: none; | |
| } | |
| .copy-indicator.show { opacity: 1; } | |
| /* ===== CSS PLAYGROUND MODAL ===== */ | |
| .playground-modal { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(0, 0, 0, 0.8); | |
| backdrop-filter: blur(5px); | |
| z-index: 1000; | |
| display: none; | |
| place-items: center; | |
| padding: 2rem; | |
| } | |
| .playground-modal.active { display: grid; } | |
| .playground-content { | |
| background: var(--darker); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| border-radius: var(--border-radius); | |
| max-width: 1200px; | |
| width: 100%; | |
| max-height: 90vh; | |
| overflow-y: auto; | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 2rem; | |
| padding: 2rem; | |
| } | |
| @media (max-width: 900px) { | |
| .playground-content { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| .playground-editor, | |
| .playground-preview { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 1rem; | |
| } | |
| .preview-iframe { | |
| background: white; | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| border-radius: 8px; | |
| min-height: 400px; | |
| width: 100%; | |
| } | |
| .modal-close { | |
| position: absolute; | |
| top: 1rem; | |
| right: 1rem; | |
| background: var(--danger); | |
| color: white; | |
| border: none; | |
| width: 40px; | |
| height: 40px; | |
| border-radius: 50%; | |
| cursor: pointer; | |
| font-size: 1.25rem; | |
| transition: var(--transition); | |
| } | |
| .modal-close:hover { | |
| transform: rotate(90deg); | |
| background: #dc2626; | |
| } | |
| /* ===== TOOLBAR ===== */ | |
| .css-toolbar { | |
| background: rgba(255, 255, 255, 0.05); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| border-radius: var(--border-radius); | |
| padding: 1rem; | |
| margin-bottom: 2rem; | |
| display: flex; | |
| gap: 1rem; | |
| flex-wrap: wrap; | |
| align-items: center; | |
| } | |
| .toolbar-group { | |
| display: flex; | |
| gap: 0.5rem; | |
| align-items: center; | |
| } | |
| .toolbar-group label { | |
| font-size: 0.875rem; | |
| color: var(--gray); | |
| } | |
| .selected-counter { | |
| background: var(--warning); | |
| color: var(--darker); | |
| padding: 0.25rem 0.75rem; | |
| border-radius: 20px; | |
| font-weight: 700; | |
| font-size: 0.875rem; | |
| } | |
| /* ===== ARCHIVE LIST ===== */ | |
| .archive-list { | |
| display: grid; | |
| gap: 1rem; | |
| margin-top: 2rem; | |
| } | |
| .archive-item { | |
| background: rgba(255, 255, 255, 0.05); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| border-radius: 8px; | |
| padding: 1.5rem; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| transition: var(--transition); | |
| } | |
| .archive-item:hover { | |
| background: rgba(255, 255, 255, 0.08); | |
| transform: translateX(4px); | |
| } | |
| .archive-info h4 { margin-bottom: 0.25rem; } | |
| .archive-meta { | |
| color: var(--gray); | |
| font-size: 0.875rem; | |
| } | |
| .search-box { | |
| width: 100%; | |
| max-width: 400px; | |
| background: rgba(255, 255, 255, 0.05); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| border-radius: 8px; | |
| padding: 0.75rem 1rem; | |
| color: var(--light); | |
| font-size: 1rem; | |
| transition: var(--transition); | |
| } | |
| .search-box:focus { | |
| outline: none; | |
| border-color: var(--primary); | |
| box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2); | |
| } | |
| .search-container { | |
| position: relative; | |
| max-width: 400px; | |
| } | |
| /* ===== SETTINGS ===== */ | |
| .settings-grid { | |
| display: grid; | |
| gap: 2rem; | |
| grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); | |
| margin-top: 2rem; | |
| } | |
| .setting-card { | |
| background: rgba(255, 255, 255, 0.05); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| border-radius: var(--border-radius); | |
| padding: 1.5rem; | |
| } | |
| .setting-title { | |
| font-size: 1.125rem; | |
| font-weight: 700; | |
| margin-bottom: 1rem; | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .toggle-switch { | |
| position: relative; | |
| width: 50px; | |
| height: 24px; | |
| background: rgba(255, 255, 255, 0.2); | |
| border-radius: 12px; | |
| cursor: pointer; | |
| transition: background 0.3s; | |
| } | |
| .toggle-switch.active { background: var(--primary); } | |
| .toggle-slider { | |
| position: absolute; | |
| top: 2px; | |
| left: 2px; | |
| width: 20px; | |
| height: 20px; | |
| background: white; | |
| border-radius: 50%; | |
| transition: transform 0.3s; | |
| box-shadow: var(--shadow-sm); | |
| } | |
| .toggle-switch.active .toggle-slider { transform: translateX(26px); } | |
| .setting-row { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| padding: 0.75rem 0; | |
| border-bottom: 1px solid rgba(255, 255, 255, 0.05); | |
| } | |
| .setting-row:last-child { border-bottom: none; } | |
| /* ===== PROGRESS BAR ===== */ | |
| .progress-bar { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 3px; | |
| background: var(--primary); | |
| transform: scaleX(0); | |
| transform-origin: left; | |
| transition: transform 0.3s; | |
| z-index: 200; | |
| } | |
| .progress-bar.active { transform: scaleX(1); } | |
| /* ===== NOTIFICATIONS ===== */ | |
| .notification { | |
| position: fixed; | |
| bottom: 2rem; | |
| right: 2rem; | |
| background: var(--darker); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| border-radius: 8px; | |
| padding: 1rem 1.5rem; | |
| box-shadow: var(--shadow-xl); | |
| transform: translateY(100px); | |
| opacity: 0; | |
| transition: var(--transition); | |
| z-index: 150; | |
| max-width: 400px; | |
| } | |
| .notification.show { | |
| transform: translateY(0); | |
| opacity: 1; | |
| } | |
| .notification.success { border-left: 4px solid var(--secondary); } | |
| .notification.error { border-left: 4px solid var(--danger); } | |
| .notification.info { border-left: 4px solid var(--primary); } | |
| /* ===== LOADING SPINNER ===== */ | |
| .spinner { | |
| width: 40px; | |
| height: 40px; | |
| border: 3px solid rgba(255, 255, 255, 0.1); | |
| border-top-color: var(--primary); | |
| border-radius: 50%; | |
| animation: spin 1s linear infinite; | |
| margin: 2rem auto; | |
| } | |
| @keyframes spin { to { transform: rotate(360deg); } } | |
| /* ===== RESPONSIVE ===== */ | |
| @media (max-width: 768px) { | |
| .header { padding: 1rem; } | |
| .main-content { padding: 1rem; } | |
| .module-grid { grid-template-columns: 1fr; } | |
| .action-buttons { flex-direction: column; } | |
| .btn { width: 100%; justify-content: center; } | |
| .css-toolbar { flex-direction: column; align-items: stretch; } | |
| .toolbar-group { justify-content: space-between; } | |
| } | |
| /* ===== UTILITY CLASSES ===== */ | |
| .hidden { display: none ; } | |
| .fade-in { animation: fadeIn 0.3s ease-in-out; } | |
| .text-muted { color: var(--gray); } | |
| .mb-2 { margin-bottom: 0.5rem; } | |
| .mb-4 { margin-bottom: 1rem; } | |
| .mt-4 { margin-top: 1rem; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="progress-bar" id="progressBar"></div> | |
| <header class="header"> | |
| <div class="logo-section"> | |
| <div class="logo">CF</div> | |
| <div class="brand">CodeFlow Pro CSS</div> | |
| </div> | |
| <nav class="nav-tabs"> | |
| <button class="tab-btn active" data-tab="files"> | |
| <i class="fas fa-folder-open"></i> Dateien | |
| <span class="badge" id="fileCount">0</span> | |
| </button> | |
| <button class="tab-btn" data-tab="modules"> | |
| <i class="fas fa-puzzle-piece"></i> CSS Module | |
| <span class="badge" id="moduleCount">0</span> | |
| </button> | |
| <button class="tab-btn" data-tab="archive"> | |
| <i class="fas fa-archive"></i> Archiv | |
| <span class="badge" id="archiveCount">0</span> | |
| </button> | |
| <button class="tab-btn" data-tab="settings"> | |
| <i class="fas fa-cog"></i> Einstellungen | |
| </button> | |
| </nav> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link"> | |
| Built with anycoder | |
| </a> | |
| </header> | |
| <main class="main-content"> | |
| <!-- FILES TAB --> | |
| <div class="tab-panel active" id="files-tab"> | |
| <h2 class="mb-4">CSS Dateien verarbeiten</h2> | |
| <div class="upload-zone" id="uploadZone"> | |
| <div class="upload-icon"> | |
| <i class="fas fa-cloud-upload-alt"></i> | |
| </div> | |
| <div class="upload-text">CSS Dateien hier ablegen oder klicken</div> | |
| <div class="upload-hint">Unterstützt: .css Dateien oder CSS Code</div> | |
| <input type="file" id="fileInput" class="file-input" accept=".css" multiple> | |
| </div> | |
| <div class="action-buttons"> | |
| <button class="btn" id="selectFilesBtn"> | |
| <i class="fas fa-file"></i> Dateien auswählen | |
| </button> | |
| <button class="btn btn-secondary" id="pasteCssBtn"> | |
| <i class="fas fa-paste"></i> CSS Einfügen | |
| </button> | |
| <button class="btn btn-secondary" id="processBtn" disabled> | |
| <i class="fas fa-cogs"></i> Verarbeiten | |
| </button> | |
| <button class="btn btn-danger" id="clearBtn"> | |
| <i class="fas fa-trash"></i> Alle löschen | |
| </button> | |
| </div> | |
| <div id="fileList" class="mt-4"></div> | |
| </div> | |
| <!-- MODULES TAB --> | |
| <div class="tab-panel" id="modules-tab"> | |
| <h2 class="mb-4">CSS Module & Playground</h2> | |
| <div class="css-toolbar"> | |
| <div class="toolbar-group"> | |
| <label>Ausgewählt:</label> | |
| <span class="selected-counter" id="selectedCount">0</span> | |
| </div> | |
| <div class="toolbar-group"> | |
| <button class="btn btn-secondary" id="selectAllBtn"> | |
| <i class="fas fa-check-square"></i> Alle | |
| </button> | |
| <button class="btn btn-secondary" id="deselectAllBtn"> | |
| <i class="fas fa-square"></i> Keine | |
| </button> | |
| </div> | |
| <div class="toolbar-group"> | |
| <button class="btn" id="combineSelectedBtn"> | |
| <i class="fas fa-object-group"></i> Zusammenführen | |
| </button> | |
| </div> | |
| <div class="toolbar-group"> | |
| <button class="btn btn-secondary" id="exportHtmlViewBtn"> | |
| <i class="fas fa-file-code"></i> HTML View | |
| </button> | |
| <button class="btn btn-secondary" id="recodeStylesheetBtn"> | |
| <i class="fas fa-sync-alt"></i> Stylesheet Recode | |
| </button> | |
| </div> | |
| <div class="toolbar-group"> | |
| <button class="btn btn-danger" id="removeDuplicatesBtn"> | |
| <i class="fas fa-clone"></i> Duplikate | |
| </button> | |
| </div> | |
| </div> | |
| <div class="search-container"> | |
| <input type="text" class="search-box" id="moduleSearch" placeholder="Module suchen..."> | |
| </div> | |
| <div class="module-grid" id="moduleGrid"></div> | |
| </div> | |
| <!-- ARCHIVE TAB --> | |
| <div class="tab-panel" id="archive-tab"> | |
| <h2 class="mb-4">CSS Archiv</h2> | |
| <div class="search-container"> | |
| <input type="text" class="search-box" id="archiveSearch" placeholder="Archiv durchsuchen..."> | |
| </div> | |
| <div class="action-buttons"> | |
| <button class="btn" id="exportArchiveBtn"> | |
| <i class="fas fa-file-archive"></i> Archiv exportieren | |
| </button> | |
| <button class="btn btn-danger" id="clearArchiveBtn"> | |
| <i class="fas fa-broom"></i> Archiv leeren | |
| </button> | |
| </div> | |
| <div class="archive-list" id="archiveList"></div> | |
| </div> | |
| <!-- SETTINGS TAB --> | |
| <div class="tab-panel" id="settings-tab"> | |
| <h2 class="mb-4">CSS Playground Einstellungen</h2> | |
| <div class="settings-grid"> | |
| <div class="setting-card"> | |
| <h3 class="setting-title"> | |
| <i class="fas fa-magic"></i> Automatisierung | |
| </h3> | |
| <div class="setting-row"> | |
| <span>Auto-Speicherung</span> | |
| <div class="toggle-switch active" data-setting="autoSave"></div> | |
| </div> | |
| <div class="setting-row"> | |
| <span>Auto-Benennung</span> | |
| <div class="toggle-switch active" data-setting="autoNaming"></div> | |
| </div> | |
| <div class="setting-row"> | |
| <span>Duplikat-Prüfung</span> | |
| <div class="toggle-switch active" data-setting="duplicateCheck"></div> | |
| </div> | |
| </div> | |
| <div class="setting-card"> | |
| <h3 class="setting-title"> | |
| <i class="fas fa-palette"></i> CSS Verarbeitung | |
| </h3> | |
| <div class="setting-row"> | |
| <span>CSS-Variablen extrahieren</span> | |
| <div class="toggle-switch active" data-setting="extractCssVars"></div> | |
| </div> | |
| <div class="setting-row"> | |
| <span>Farben optimieren</span> | |
| <div class="toggle-switch" data-setting="optimizeColors"></div> | |
| </div> | |
| <div class="setting-row"> | |
| <span>Responsive Regeln</span> | |
| <div class="toggle-switch active" data-setting="responsiveRules"></div> | |
| </div> | |
| </div> | |
| <div class="setting-card"> | |
| <h3 class="setting-title"> | |
| <i class="fas fa-history"></i> Historie | |
| </h3> | |
| <div class="setting-row"> | |
| <span>Such-Historie speichern</span> | |
| <div class="toggle-switch active" data-setting="searchHistory"></div> | |
| </div> | |
| <div class="setting-row"> | |
| <span>Letzte Sitzung wiederherstellen</span> | |
| <div class="toggle-switch active" data-setting="restoreSession"></div> | |
| </div> | |
| <div class="setting-row"> | |
| <button class="btn" id="clearHistoryBtn" style="width: 100%;"> | |
| <i class="fas fa-eraser"></i> Historie leeren | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <!-- CSS Playground Modal --> | |
| <div class="playground-modal" id="playgroundModal"> | |
| <button class="modal-close" id="closePlayground"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| <div class="playground-content"> | |
| <div class="playground-editor"> | |
| <h3>CSS Editor</h3> | |
| <div class="css-editor" id="playgroundEditor" contenteditable="true"></div> | |
| <div class="css-controls" id="cssControls"></div> | |
| </div> | |
| <div class="playground-preview"> | |
| <h3>Live Vorschau</h3> | |
| <iframe class="preview-iframe" id="previewFrame"></iframe> | |
| <div class="action-buttons"> | |
| <button class="btn" id="applyPlaygroundChanges"> | |
| <i class="fas fa-check"></i> Änderungen übernehmen | |
| </button> | |
| <button class="btn btn-secondary" id="resetPlayground"> | |
| <i class="fas fa-undo"></i> Zurücksetzen | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- CSS Paste Modal --> | |
| <div class="playground-modal" id="pasteModal"> | |
| <button class="modal-close" id="closePasteModal"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| <div class="playground-content" style="grid-template-columns: 1fr;"> | |
| <div> | |
| <h3>CSS Code Einfügen</h3> | |
| <div class="css-editor" id="pasteEditor" contenteditable="true" style="min-height: 300px;"></div> | |
| <div class="action-buttons"> | |
| <button class="btn" id="processPastedCss"> | |
| <i class="fas fa-cogs"></i> Verarbeiten | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="notification" id="notification"></div> | |
| <script> | |
| // ===== MODERN JAVASCRIPT ES2022+ ===== | |
| class CodeFlowApp { | |
| #files = new Map(); | |
| #modules = new Map(); | |
| #archive = new Map(); | |
| #selectedModules = new Set(); | |
| #settings = new Map([ | |
| ['autoSave', true], | |
| ['autoNaming', true], | |
| ['duplicateCheck', true], | |
| ['extractCssVars', true], | |
| ['optimizeColors', false], | |
| ['responsiveRules', true], | |
| ['searchHistory', true], | |
| ['restoreSession', true] | |
| ]); | |
| #history = { searches: [], processedFiles: [] }; | |
| #currentPlaygroundId = null; | |
| constructor() { | |
| this.#init(); | |
| this.#loadFromStorage(); | |
| this.#setupEventListeners(); | |
| this.#setupAutoSave(); | |
| } | |
| // ===== INITIALIZATION ===== | |
| #init() { | |
| console.log('🚀 CodeFlow Pro CSS Playground initialisiert'); | |
| this.#updateBadgeCounts(); | |
| this.#renderArchive(); | |
| } | |
| // ===== STORAGE MANAGEMENT ===== | |
| #saveToStorage() { | |
| if (!this.#settings.get('autoSave')) return; | |
| const data = { | |
| modules: Array.from(this.#modules.entries()), | |
| archive: Array.from(this.#archive.entries()), | |
| settings: Array.from(this.#settings.entries()), | |
| history: this.#history, | |
| timestamp: Date.now() | |
| }; | |
| localStorage.setItem('codeflow-css-data', JSON.stringify(data)); | |
| this.#showNotification('Auto-gespeichert', 'info'); | |
| } | |
| #loadFromStorage() { | |
| if (!this.#settings.get('restoreSession')) return; | |
| const saved = localStorage.getItem('codeflow-css-data'); | |
| if (!saved) return; | |
| try { | |
| const data = JSON.parse(saved); | |
| this.#modules = new Map(data.modules || []); | |
| this.#archive = new Map(data.archive || []); | |
| this.#settings = new Map(data.settings || this.#settings); | |
| this.#history = data.history || this.#history; | |
| this.#updateBadgeCounts(); | |
| this.#renderArchive(); | |
| this.#applySettings(); | |
| } catch (e) { | |
| console.error('Fehler beim Laden:', e); | |
| } | |
| } | |
| // ===== EVENT LISTENERS ===== | |
| #setupEventListeners() { | |
| // Tabs | |
| document.querySelectorAll('.tab-btn').forEach(btn => { | |
| btn.addEventListener('click', (e) => this.#switchTab(e.target.dataset.tab)); | |
| }); | |
| // Upload Zone | |
| const zone = document.getElementById('uploadZone'); | |
| zone.addEventListener('click', () => document.getElementById('fileInput').click()); | |
| zone.addEventListener('dragover', this.#handleDragOver.bind(this)); | |
| zone.addEventListener('dragleave', this.#handleDragLeave.bind(this)); | |
| zone.addEventListener('drop', this.#handleDrop.bind(this)); | |
| // File Input | |
| document.getElementById('fileInput').addEventListener('change', this.#handleFileSelect.bind(this)); | |
| document.getElementById('selectFilesBtn').addEventListener('click', () => { | |
| document.getElementById('fileInput').click(); | |
| }); | |
| document.getElementById('pasteCssBtn').addEventListener('click', () => { | |
| document.getElementById('pasteModal').classList.add('active'); | |
| }); | |
| // Action Buttons | |
| document.getElementById('processBtn').addEventListener('click', () => this.#processFiles()); | |
| document.getElementById('clearBtn').addEventListener('click', () => this.#clearFiles()); | |
| document.getElementById('selectAllBtn').addEventListener('click', () => this.#selectAllModules()); | |
| document.getElementById('deselectAllBtn').addEventListener('click', () => this.#deselectAllModules()); | |
| document.getElementById('combineSelectedBtn').addEventListener('click', () => this.#combineSelected()); | |
| document.getElementById('exportHtmlViewBtn').addEventListener('click', () => this.#exportHtmlView()); | |
| document.getElementById('recodeStylesheetBtn').addEventListener('click', () => this.#recodeStylesheet()); | |
| document.getElementById('removeDuplicatesBtn').addEventListener('click', () => this.#removeDuplicates()); | |
| document.getElementById('clearArchiveBtn').addEventListener('click', () => this.#clearArchive()); | |
| document.getElementById('exportArchiveBtn').addEventListener('click', () => this.#exportArchive()); | |
| document.getElementById('clearHistoryBtn').addEventListener('click', () => this.#clearHistory()); | |
| // Search | |
| document.getElementById('moduleSearch').addEventListener('input', (e) => this.#handleSearch(e.target.value)); | |
| // Settings | |
| document.querySelectorAll('.toggle-switch').forEach(toggle => { | |
| toggle.addEventListener('click', (e) => this.#toggleSetting(e.target.dataset.setting)); | |
| }); | |
| // Playground | |
| document.getElementById('closePlayground').addEventListener('click', () => { | |
| document.getElementById('playgroundModal').classList.remove('active'); | |
| }); | |
| document.getElementById('applyPlaygroundChanges').addEventListener('click', () => this.#applyPlaygroundChanges()); | |
| document.getElementById('resetPlayground').addEventListener('click', () => this.#resetPlayground()); | |
| document.getElementById('playgroundEditor').addEventListener('input', () => this.#updatePreview()); | |
| // Paste Modal | |
| document.getElementById('closePasteModal').addEventListener('click', () => { | |
| document.getElementById('pasteModal').classList.remove('active'); | |
| }); | |
| document.getElementById('processPastedCss').addEventListener('click', () => this.#processPastedCss()); | |
| // Auto-save on input | |
| document.addEventListener('input', () => this.#debouncedSave()); | |
| } | |
| // ===== FILE HANDLING ===== | |
| async #handleFileSelect(e) { | |
| const files = Array.from(e.target.files); | |
| await this.#addFiles(files); | |
| } | |
| #handleDragOver(e) { | |
| e.preventDefault(); | |
| e.currentTarget.classList.add('dragover'); | |
| } | |
| #handleDragLeave(e) { | |
| e.currentTarget.classList.remove('dragover'); | |
| } | |
| async #handleDrop(e) { | |
| e.preventDefault(); | |
| e.currentTarget.classList.remove('dragover'); | |
| const items = Array.from(e.dataTransfer.items); | |
| const files = []; | |
| for (const item of items) { | |
| if (item.kind === 'file') { | |
| const file = item.getAsFile(); | |
| if (item.webkitGetAsEntry) { | |
| const entry = item.webkitGetAsEntry(); | |
| if (entry?.isDirectory) { | |
| await this.#readDirectory(entry, files); | |
| } else { | |
| files.push(file); | |
| } | |
| } else { | |
| files.push(file); | |
| } | |
| } | |
| } | |
| await this.#addFiles(files); | |
| } | |
| async #readDirectory(entry, files) { | |
| const reader = entry.createReader(); | |
| const entries = await new Promise(resolve => reader.readEntries(resolve)); | |
| for (const subEntry of entries) { | |
| if (subEntry.isDirectory) { | |
| await this.#readDirectory(subEntry, files); | |
| } else { | |
| const file = await new Promise(resolve => subEntry.file(resolve)); | |
| files.push(file); | |
| } | |
| } | |
| } | |
| async #addFiles(files) { | |
| const cssFiles = files.filter(f => f.type === 'text/css' || f.name.endsWith('.css')); | |
| for (const file of cssFiles) { | |
| this.#files.set(file.name, { | |
| file, | |
| id: crypto.randomUUID(), | |
| processed: false, | |
| timestamp: Date.now() | |
| }); | |
| } | |
| this.#renderFileList(); | |
| this.#updateBadgeCounts(); | |
| this.#showNotification(`${cssFiles.length} CSS-Dateien hinzugefügt`, 'success'); | |
| } | |
| #renderFileList() { | |
| const container = document.getElementById('fileList'); | |
| if (this.#files.size === 0) { | |
| container.innerHTML = '<p class="text-muted">Keine CSS-Dateien ausgewählt</p>'; | |
| document.getElementById('processBtn').disabled = true; | |
| return; | |
| } | |
| container.innerHTML = Array.from(this.#files.values()).map(fileObj => ` | |
| <div class="archive-item fade-in"> | |
| <div class="archive-info"> | |
| <h4>${fileObj.file.name}</h4> | |
| <div class="archive-meta"> | |
| ${this.#formatBytes(fileObj.file.size)} • ${new Date(fileObj.timestamp).toLocaleString()} | |
| </div> | |
| </div> | |
| <button class="icon-btn" onclick="app.#removeFile('${fileObj.id}')"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| `).join(''); | |
| document.getElementById('processBtn').disabled = false; | |
| } | |
| #removeFile(id) { | |
| const entry = Array.from(this.#files.entries()).find(([, v]) => v |