anycoder-1464269c / index.html
HI7RAI's picture
Upload folder using huggingface_hub
10114d5 verified
<!DOCTYPE html>
<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 !important; }
.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