Spaces:
Running
Running
| <html lang="de"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Live ScriptForge IDE</title> | |
| <!-- Icons --> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <!-- Modern Fonts --> | |
| <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;700&family=Fira+Code:wght@300;400;500;600&display=swap" rel="stylesheet"> | |
| <!-- CodeMirror --> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/codemirror.min.css"> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/theme/dracula.min.css"> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/hint/show-hint.min.css"> | |
| <style> | |
| :root { | |
| --bg: #08090d; | |
| --panel: #0d0f14; | |
| --panel-alt: #12151c; | |
| --accent: #22d3ee; | |
| --accent-secondary: #f472b6; | |
| --accent-tertiary: #a78bfa; | |
| --text: #e2e8f0; | |
| --text-muted: #64748b; | |
| --border: rgba(34, 211, 238, 0.15); | |
| --border-strong: rgba(34, 211, 238, 0.3); | |
| --success: #34d399; | |
| --warning: #fbbf24; | |
| --error: #f87171; | |
| --glass: rgba(13, 15, 20, 0.9); | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: 'Space Grotesk', sans-serif; | |
| background: var(--bg); | |
| color: var(--text); | |
| height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| overflow: hidden; | |
| } | |
| /* Background Pattern */ | |
| body::before { | |
| content: ''; | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: | |
| radial-gradient(ellipse at 20% 20%, rgba(34, 211, 238, 0.08) 0%, transparent 50%), | |
| radial-gradient(ellipse at 80% 80%, rgba(167, 139, 250, 0.06) 0%, transparent 50%), | |
| radial-gradient(ellipse at 50% 50%, rgba(244, 114, 182, 0.04) 0%, transparent 60%); | |
| pointer-events: none; | |
| z-index: 0; | |
| } | |
| /* --- Header --- */ | |
| header { | |
| background: linear-gradient(180deg, rgba(13, 15, 20, 0.98), rgba(13, 15, 20, 0.95)); | |
| padding: 12px 20px; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| border-bottom: 1px solid var(--border); | |
| backdrop-filter: blur(20px); | |
| z-index: 100; | |
| position: relative; | |
| } | |
| .brand { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| } | |
| .brand-icon { | |
| width: 36px; | |
| height: 36px; | |
| background: linear-gradient(135deg, var(--accent), var(--accent-tertiary)); | |
| border-radius: 8px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 1rem; | |
| color: #000; | |
| box-shadow: 0 4px 15px rgba(34, 211, 238, 0.3); | |
| animation: iconFloat 3s ease-in-out infinite; | |
| } | |
| @keyframes iconFloat { | |
| 0%, 100% { transform: translateY(0); } | |
| 50% { transform: translateY(-3px); } | |
| } | |
| .brand h1 { | |
| font-size: 1.1rem; | |
| font-weight: 700; | |
| letter-spacing: -0.5px; | |
| } | |
| .brand h1 span { | |
| background: linear-gradient(135deg, var(--accent), var(--accent-tertiary)); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| } | |
| .header-center { | |
| display: flex; | |
| gap: 8px; | |
| align-items: center; | |
| } | |
| .url-input-wrapper { | |
| position: relative; | |
| display: flex; | |
| align-items: center; | |
| } | |
| input[type="text"], | |
| input[type="number"] { | |
| background: rgba(0, 0, 0, 0.4); | |
| border: 1px solid var(--border); | |
| color: var(--text); | |
| padding: 10px 14px; | |
| border-radius: 8px; | |
| font-family: 'Fira Code', monospace; | |
| font-size: 0.85rem; | |
| outline: none; | |
| transition: all 0.25s ease; | |
| } | |
| input[type="text"]:focus, | |
| input[type="number"]:focus { | |
| border-color: var(--accent); | |
| box-shadow: 0 0 0 3px rgba(34, 211, 238, 0.15), inset 0 0 20px rgba(34, 211, 238, 0.05); | |
| } | |
| input::placeholder { | |
| color: var(--text-muted); | |
| } | |
| /* Buttons */ | |
| button { | |
| background: linear-gradient(135deg, rgba(34, 211, 238, 0.15), rgba(34, 211, 238, 0.05)); | |
| color: var(--accent); | |
| border: 1px solid var(--border-strong); | |
| padding: 10px 18px; | |
| border-radius: 8px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.25s ease; | |
| font-size: 0.8rem; | |
| font-family: 'Space Grotesk', sans-serif; | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 8px; | |
| text-transform: uppercase; | |
| letter-spacing: 0.5px; | |
| } | |
| button:hover { | |
| background: linear-gradient(135deg, var(--accent), var(--accent-tertiary)); | |
| color: #000; | |
| transform: translateY(-2px); | |
| box-shadow: 0 8px 25px rgba(34, 211, 238, 0.25); | |
| border-color: transparent; | |
| } | |
| button:active { | |
| transform: translateY(0); | |
| } | |
| button.primary { | |
| background: linear-gradient(135deg, var(--accent), #06b6d4); | |
| color: #000; | |
| border: none; | |
| font-weight: 700; | |
| } | |
| button.primary:hover { | |
| box-shadow: 0 8px 30px rgba(34, 211, 238, 0.4); | |
| } | |
| button.danger { | |
| background: rgba(248, 113, 113, 0.1); | |
| color: var(--error); | |
| border-color: rgba(248, 113, 113, 0.3); | |
| } | |
| button.danger:hover { | |
| background: var(--error); | |
| color: #000; | |
| border-color: transparent; | |
| } | |
| button.small { | |
| padding: 6px 12px; | |
| font-size: 0.7rem; | |
| } | |
| button.icon-only { | |
| padding: 10px; | |
| min-width: 40px; | |
| justify-content: center; | |
| } | |
| .header-right { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| } | |
| .status-badge { | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| font-size: 0.75rem; | |
| color: var(--text-muted); | |
| padding: 6px 12px; | |
| background: rgba(0, 0, 0, 0.3); | |
| border-radius: 20px; | |
| border: 1px solid var(--border); | |
| } | |
| .status-dot { | |
| width: 8px; | |
| height: 8px; | |
| border-radius: 50%; | |
| background: var(--success); | |
| animation: statusPulse 2s ease-in-out infinite; | |
| } | |
| .status-dot.editing { | |
| background: var(--warning); | |
| } | |
| @keyframes statusPulse { | |
| 0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(52, 211, 153, 0.4); } | |
| 50% { opacity: 0.7; box-shadow: 0 0 0 4px rgba(52, 211, 153, 0); } | |
| } | |
| /* --- Main Layout --- */ | |
| main { | |
| display: flex; | |
| flex: 1; | |
| height: calc(100vh - 60px); | |
| position: relative; | |
| z-index: 1; | |
| } | |
| /* Resizer */ | |
| .resizer { | |
| width: 5px; | |
| background: var(--border); | |
| cursor: col-resize; | |
| transition: background 0.2s; | |
| position: relative; | |
| z-index: 10; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .resizer:hover, | |
| .resizer.dragging { | |
| background: var(--accent); | |
| } | |
| .resizer::after { | |
| content: ''; | |
| width: 2px; | |
| height: 30px; | |
| background: var(--text-muted); | |
| border-radius: 2px; | |
| opacity: 0.5; | |
| } | |
| /* Editor Side */ | |
| .editor-container { | |
| width: 50%; | |
| display: flex; | |
| flex-direction: column; | |
| background: var(--panel); | |
| min-width: 300px; | |
| } | |
| .panel-header { | |
| padding: 12px 16px; | |
| background: var(--panel-alt); | |
| border-bottom: 1px solid var(--border); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .panel-title { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| font-size: 0.75rem; | |
| text-transform: uppercase; | |
| letter-spacing: 1.5px; | |
| color: var(--text-muted); | |
| font-weight: 600; | |
| } | |
| .panel-title i { | |
| color: var(--accent); | |
| } | |
| .panel-actions { | |
| display: flex; | |
| gap: 6px; | |
| } | |
| /* Injection Panel */ | |
| .injection-panel { | |
| padding: 12px 16px; | |
| background: linear-gradient(90deg, rgba(34, 211, 238, 0.05), rgba(167, 139, 250, 0.05)); | |
| border-bottom: 1px solid var(--border); | |
| display: flex; | |
| gap: 12px; | |
| align-items: center; | |
| flex-wrap: wrap; | |
| } | |
| .injection-panel .label { | |
| font-size: 0.75rem; | |
| color: var(--text-muted); | |
| font-family: 'Fira Code', monospace; | |
| text-transform: uppercase; | |
| letter-spacing: 1px; | |
| } | |
| .injection-group { | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| } | |
| .injection-panel input[type="number"] { | |
| width: 70px; | |
| padding: 8px 10px; | |
| text-align: center; | |
| } | |
| /* CodeMirror Customization */ | |
| .CodeMirror { | |
| flex: 1; | |
| height: auto ; | |
| font-family: 'Fira Code', monospace; | |
| font-size: 13px; | |
| line-height: 1.6; | |
| background: var(--panel) ; | |
| } | |
| .CodeMirror-gutters { | |
| background: rgba(0, 0, 0, 0.3) ; | |
| border-right: 1px solid var(--border) ; | |
| } | |
| .CodeMirror-linenumber { | |
| color: var(--text-muted) ; | |
| } | |
| .injected-line { | |
| background: rgba(34, 211, 238, 0.1) ; | |
| animation: injectFlash 1s ease-out; | |
| } | |
| @keyframes injectFlash { | |
| 0% { background: rgba(34, 211, 238, 0.3) ; } | |
| 100% { background: rgba(34, 211, 238, 0.1) ; } | |
| } | |
| /* Preview Side */ | |
| .preview-container { | |
| width: 50%; | |
| position: relative; | |
| background: #000; | |
| display: flex; | |
| flex-direction: column; | |
| min-width: 300px; | |
| } | |
| .preview-header { | |
| padding: 12px 16px; | |
| background: var(--panel-alt); | |
| border-bottom: 1px solid var(--border); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .device-selector { | |
| display: flex; | |
| gap: 4px; | |
| background: rgba(0, 0, 0, 0.3); | |
| padding: 4px; | |
| border-radius: 6px; | |
| } | |
| .device-btn { | |
| padding: 6px 10px; | |
| font-size: 0.7rem; | |
| background: transparent; | |
| border: none; | |
| color: var(--text-muted); | |
| cursor: pointer; | |
| border-radius: 4px; | |
| transition: all 0.2s; | |
| } | |
| .device-btn:hover, | |
| .device-btn.active { | |
| background: rgba(34, 211, 238, 0.15); | |
| color: var(--accent); | |
| } | |
| .preview-frame-wrapper { | |
| flex: 1; | |
| position: relative; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| background: repeating-conic-gradient(#1a1a1a 0% 25%, #111 0% 50%) 50% / 20px 20px; | |
| overflow: hidden; | |
| } | |
| .preview-frame-wrapper.responsive { | |
| padding: 20px; | |
| } | |
| .preview-frame-wrapper.responsive iframe { | |
| max-width: 100%; | |
| max-height: 100%; | |
| border-radius: 8px; | |
| box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5); | |
| } | |
| iframe { | |
| width: 100%; | |
| height: 100%; | |
| border: none; | |
| background: #fff; | |
| } | |
| /* Overlay Tools */ | |
| .overlay-tools { | |
| position: absolute; | |
| bottom: 20px; | |
| right: 20px; | |
| display: flex; | |
| gap: 8px; | |
| background: var(--glass); | |
| padding: 10px; | |
| border-radius: 10px; | |
| backdrop-filter: blur(15px); | |
| border: 1px solid var(--border); | |
| box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); | |
| } | |
| .overlay-tools button { | |
| padding: 8px 14px; | |
| font-size: 0.7rem; | |
| } | |
| /* Console Panel */ | |
| .console-panel { | |
| background: var(--panel); | |
| border-top: 1px solid var(--border); | |
| max-height: 200px; | |
| overflow: hidden; | |
| display: flex; | |
| flex-direction: column; | |
| transition: max-height 0.3s ease; | |
| } | |
| .console-panel.collapsed { | |
| max-height: 36px; | |
| } | |
| .console-header { | |
| padding: 8px 16px; | |
| background: var(--panel-alt); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| cursor: pointer; | |
| user-select: none; | |
| } | |
| .console-title { | |
| font-size: 0.7rem; | |
| text-transform: uppercase; | |
| letter-spacing: 1px; | |
| color: var(--text-muted); | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .console-count { | |
| background: var(--accent); | |
| color: #000; | |
| padding: 2px 6px; | |
| border-radius: 10px; | |
| font-size: 0.65rem; | |
| font-weight: 700; | |
| } | |
| .console-output { | |
| flex: 1; | |
| overflow-y: auto; | |
| padding: 10px; | |
| font-family: 'Fira Code', monospace; | |
| font-size: 0.8rem; | |
| } | |
| .console-line { | |
| padding: 4px 8px; | |
| border-radius: 4px; | |
| margin-bottom: 4px; | |
| display: flex; | |
| align-items: flex-start; | |
| gap: 8px; | |
| } | |
| .console-line.log { | |
| background: rgba(255, 255, 255, 0.03); | |
| color: var(--text); | |
| } | |
| .console-line.error { | |
| background: rgba(248, 113, 113, 0.1); | |
| color: var(--error); | |
| border-left: 2px solid var(--error); | |
| } | |
| .console-line.warn { | |
| background: rgba(251, 191, 36, 0.1); | |
| color: var(--warning); | |
| border-left: 2px solid var(--warning); | |
| } | |
| .console-line .timestamp { | |
| color: var(--text-muted); | |
| font-size: 0.7rem; | |
| min-width: 60px; | |
| } | |
| /* Notification Toast */ | |
| .notification { | |
| position: fixed; | |
| bottom: 24px; | |
| left: 24px; | |
| background: var(--glass); | |
| border: 1px solid var(--border); | |
| padding: 14px 20px; | |
| border-radius: 10px; | |
| box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4); | |
| backdrop-filter: blur(20px); | |
| transform: translateX(-150%); | |
| transition: transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); | |
| z-index: 1000; | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| font-size: 0.85rem; | |
| max-width: 350px; | |
| } | |
| .notification.show { | |
| transform: translateX(0); | |
| } | |
| .notification-icon { | |
| width: 32px; | |
| height: 32px; | |
| border-radius: 8px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 0.9rem; | |
| } | |
| .notification.success .notification-icon { | |
| background: rgba(52, 211, 153, 0.2); | |
| color: var(--success); | |
| } | |
| .notification.error .notification-icon { | |
| background: rgba(248, 113, 113, 0.2); | |
| color: var(--error); | |
| } | |
| .notification.warning .notification-icon { | |
| background: rgba(251, 191, 36, 0.2); | |
| color: var(--warning); | |
| } | |
| .notification.info .notification-icon { | |
| background: rgba(34, 211, 238, 0.2); | |
| color: var(--accent); | |
| } | |
| /* Templates Modal */ | |
| .modal-overlay { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: rgba(0, 0, 0, 0.8); | |
| backdrop-filter: blur(5px); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| z-index: 1000; | |
| opacity: 0; | |
| visibility: hidden; | |
| transition: all 0.3s ease; | |
| } | |
| .modal-overlay.show { | |
| opacity: 1; | |
| visibility: visible; | |
| } | |
| .modal { | |
| background: var(--panel); | |
| border: 1px solid var(--border); | |
| border-radius: 16px; | |
| width: 90%; | |
| max-width: 600px; | |
| max-height: 80vh; | |
| overflow: hidden; | |
| transform: scale(0.9) translateY(20px); | |
| transition: transform 0.3s ease; | |
| } | |
| .modal-overlay.show .modal { | |
| transform: scale(1) translateY(0); | |
| } | |
| .modal-header { | |
| padding: 20px 24px; | |
| border-bottom: 1px solid var(--border); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .modal-header h2 { | |
| font-size: 1.1rem; | |
| font-weight: 600; | |
| } | |
| .modal-body { | |
| padding: 20px; | |
| overflow-y: auto; | |
| max-height: calc(80vh - 140px); | |
| } | |
| .template-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); | |
| gap: 12px; | |
| } | |
| .template-card { | |
| background: var(--panel-alt); | |
| border: 1px solid var(--border); | |
| border-radius: 10px; | |
| padding: 16px; | |
| cursor: pointer; | |
| transition: all 0.25s ease; | |
| } | |
| .template-card:hover { | |
| border-color: var(--accent); | |
| transform: translateY(-2px); | |
| box-shadow: 0 8px 25px rgba(34, 211, 238, 0.15); | |
| } | |
| .template-card h3 { | |
| font-size: 0.9rem; | |
| margin-bottom: 6px; | |
| color: var(--text); | |
| } | |
| .template-card p { | |
| font-size: 0.75rem; | |
| color: var(--text-muted); | |
| } | |
| /* Keyboard Shortcuts Hint */ | |
| .shortcuts-hint { | |
| position: fixed; | |
| bottom: 24px; | |
| right: 24px; | |
| font-size: 0.7rem; | |
| color: var(--text-muted); | |
| background: var(--glass); | |
| padding: 8px 12px; | |
| border-radius: 6px; | |
| border: 1px solid var(--border); | |
| opacity: 0.6; | |
| transition: opacity 0.2s; | |
| } | |
| .shortcuts-hint:hover { | |
| opacity: 1; | |
| } | |
| .shortcuts-hint kbd { | |
| background: rgba(0, 0, 0, 0.3); | |
| padding: 2px 6px; | |
| border-radius: 4px; | |
| margin: 0 2px; | |
| font-family: 'Fira Code', monospace; | |
| } | |
| /* Attribution Link */ | |
| .attribution-link { | |
| font-size: 0.75rem; | |
| color: var(--text-muted); | |
| text-decoration: none; | |
| padding: 4px 10px; | |
| border-radius: 4px; | |
| transition: color 0.2s; | |
| border: 1px solid transparent; | |
| } | |
| .attribution-link:hover { | |
| color: var(--accent); | |
| border-color: var(--border); | |
| } | |
| /* Responsive */ | |
| @media (max-width: 1024px) { | |
| .header-center { | |
| display: none; | |
| } | |
| main { | |
| flex-direction: column; | |
| } | |
| .editor-container, | |
| .preview-container { | |
| width: 100% ; | |
| height: 50%; | |
| min-width: unset; | |
| } | |
| .resizer { | |
| display: none; | |
| } | |
| .shortcuts-hint { | |
| display: none; | |
| } | |
| } | |
| @media (max-width: 600px) { | |
| header { | |
| padding: 10px 12px; | |
| } | |
| .brand h1 { | |
| font-size: 0.9rem; | |
| } | |
| .injection-panel { | |
| padding: 10px; | |
| gap: 8px; | |
| } | |
| .injection-panel input[type="number"] { | |
| width: 55px; | |
| padding: 6px 8px; | |
| } | |
| .overlay-tools { | |
| bottom: 10px; | |
| right: 10px; | |
| padding: 8px; | |
| } | |
| } | |
| /* Scrollbar */ | |
| ::-webkit-scrollbar { | |
| width: 8px; | |
| height: 8px; | |
| } | |
| ::-webkit-scrollbar-track { | |
| background: transparent; | |
| } | |
| ::-webkit-scrollbar-thumb { | |
| background: var(--border); | |
| border-radius: 4px; | |
| } | |
| ::-webkit-scrollbar-thumb:hover { | |
| background: var(--border-strong); | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <div class="brand"> | |
| <div class="brand-icon"> | |
| <i class="fa-solid fa-bolt"></i> | |
| </div> | |
| <h1><span>ScriptForge</span> IDE</h1> | |
| </div> | |
| <div class="header-center"> | |
| <div class="url-input-wrapper"> | |
| <input type="text" id="targetUrl" placeholder="URL zum Mergen eingeben..." style="width: 280px;"> | |
| </div> | |
| <button id="fetchBtn" class="primary"> | |
| <i class="fa-solid fa-code-merge"></i> Merge | |
| </button> | |
| </div> | |
| <div class="header-right"> | |
| <button id="templatesBtn" class="small" title="Templates"> | |
| <i class="fa-solid fa-folder-open"></i> | |
| </button> | |
| <button id="refreshBtn" title="Aktualisieren"> | |
| <i class="fa-solid fa-play"></i> Run | |
| </button> | |
| <div class="status-badge"> | |
| <div class="status-dot" id="statusDot"></div> | |
| <span id="statusText">Bereit</span> | |
| </div> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="attribution-link"> | |
| Built with anycoder | |
| </a> | |
| </div> | |
| </header> | |
| <main> | |
| <!-- Editor Side --> | |
| <div class="editor-container" id="editorPanel"> | |
| <div class="panel-header"> | |
| <div class="panel-title"> | |
| <i class="fa-solid fa-code"></i> | |
| Editor | |
| </div> | |
| <div class="panel-actions"> | |
| <button class="small icon-only" id="formatBtn" title="Formatieren"> | |
| <i class="fa-solid fa-align-left"></i> | |
| </button> | |
| <button class="small icon-only" id="clearBtn" title="Löschen"> | |
| <i class="fa-solid fa-trash"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="injection-panel"> | |
| <span class="label">Injection Position:</span> | |
| <div class="injection-group"> | |
| <input type="number" id="injectLine" value="10" min="1"> | |
| <span class="label">Line</span> | |
| </div> | |
| <button id="injectBtn" class="small"> | |
| <i class="fa-solid fa-code-branch"></i> Inject | |
| </button> | |
| </div> | |
| <div id="codeEditor" style="flex: 1; overflow: hidden;"></div> | |
| <div class="console-panel" id="consolePanel"> | |
| <div class="console-header" id="consoleToggle"> | |
| <div class="console-title"> | |
| <i class="fa-solid fa-terminal"></i> | |
| Console | |
| <span class="console-count" id="logCount">0</span> | |
| </div> | |
| <i class="fa-solid fa-chevron-down"></i> | |
| </div> | |
| <div class="console-output" id="consoleOutput"> | |
| <!-- Logs go here --> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Resizer --> | |
| <div class="resizer" id="resizer"></div> | |
| <!-- Preview Side --> | |
| <div class="preview-container" id="previewPanel"> | |
| <div class="preview-header"> | |
| <div class="panel-title"> | |
| <i class="fa-solid fa-desktop"></i> | |
| Preview | |
| </div> | |
| <div class="device-selector"> | |
| <button class="device-btn active" data-device="desktop"><i class="fa-solid fa-desktop"></i></button> | |
| <button class="device-btn" data-device="tablet"><i class="fa-solid fa-tablet-screen-button"></i></button> | |
| <button class="device-btn" data-device="mobile"><i class="fa-solid fa-mobile-screen-button"></i></button> | |
| </div> | |
| </div> | |
| <div class="preview-frame-wrapper responsive" id="previewWrapper"> | |
| <iframe id="previewFrame" sandbox="allow-scripts allow-same-origin allow-modals"></iframe> | |
| </div> | |
| <div class="overlay-tools"> | |
| <button id="downloadBtn" title="Download HTML"> | |
| <i class="fa-solid fa-download"></i> | |
| </button> | |
| <button id="shareBtn" title="Share"> | |
| <i class="fa-solid fa-share-nodes"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </main> | |
| <!-- Templates Modal --> | |
| <div class="modal-overlay" id="templatesModal"> | |
| <div class="modal"> | |
| <div class="modal-header"> | |
| <h2><i class="fa-solid fa-folder-tree"></i> Templates wählen</h2> | |
| <button class="icon-only" id="closeModalBtn" style="background: transparent; border: none; color: var(--text-muted);"> | |
| <i class="fa-solid fa-xmark"></i> | |
| </button> | |
| </div> | |
| <div class="modal-body"> | |
| <div class="template-grid"> | |
| <div class="template-card" data-template="hello"> | |
| <h3>Hello World</h3> | |
| <p>Basis Script für Konsolenausgabe.</p> | |
| </div> | |
| <div class="template-card" data-template="dom-manip"> | |
| <h3>DOM Manipulation</h3> | |
| <p>Elemente ändern und Styling hinzufügen.</p> | |
| </div> | |
| <div class="template-card" data-template="api-fetch"> | |
| <h3>API Fetch</h3> | |
| <p>Daten von einer externen API laden.</p> | |
| </div> | |
| <div class="template-card" data-template="style-inject"> | |
| <h3>CSS Injection</h3> | |
| <p>Neues Stylesheet in die Seite injizieren.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Notification Toast --> | |
| <div class="notification" id="notification"> | |
| <div class="notification-icon"> | |
| <i class="fa-solid fa-check"></i> | |
| </div> | |
| <span class="notification-text">Action completed successfully!</span> | |
| </div> | |
| <div class="shortcuts-hint"> | |
| <kbd>Ctrl</kbd> + <kbd>Enter</kbd> Run | <kbd>Ctrl</kbd> + <kbd>S</kbd> Save | |
| </div> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/codemirror.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/mode/xml/xml.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/mode/javascript/javascript.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/mode/css/css.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/mode/htmlmixed/htmlmixed.min.js"></script> | |
| <script> | |
| // --- Initialization --- | |
| const editor = CodeMirror(document.getElementById('codeEditor'), { | |
| mode: 'htmlmixed', | |
| theme: 'dracula', | |
| lineNumbers: true, | |
| lineWrapping: true, | |
| autoCloseTags: true, | |
| autoCloseBrackets: true, | |
| value: `<!-- ScriptForge Initialisiert -->\n<script>\n console.log("ScriptForge bereit!");\n document.body.style.background = '#f0f0f0';\n<\/script>\n\n<div style="padding: 20px; font-family: sans-serif;">\n <h1>Hallo Welt!</h1>\n <p>Dies ist eine Vorschau deines injizierten Codes.</p>\n <button onclick="alert('Klick registriert!')">Test Button</button>\n</div>` | |
| }); | |
| // --- State Management --- | |
| const state = { | |
| logs: [], | |
| isConsoleOpen: true | |
| }; | |
| // --- DOM Elements --- | |
| const resizer = document.getElementById('resizer'); | |
| const editorPanel = document.getElementById('editorPanel'); | |
| const previewPanel = document.getElementById('previewPanel'); | |
| const previewFrame = document.getElementById('previewFrame'); | |
| const consolePanel = document.getElementById('consolePanel'); | |
| const consoleOutput = document.getElementById('consoleOutput'); | |
| const logCountEl = document.getElementById('logCount'); | |
| const notification = document.getElementById('notification'); | |
| // --- Resize Logic --- | |
| let isResizing = false; | |
| resizer.addEventListener('mousedown', (e) => { | |
| isResizing = true; | |
| resizer.classList.add('dragging'); | |
| document.body.style.cursor = 'col-resize'; | |
| document.body.style.userSelect = 'none'; | |
| }); | |
| document.addEventListener('mousemove', (e) => { | |
| if (!isResizing) return; | |
| const containerWidth = document.querySelector('main').offsetWidth; | |
| const newWidth = (e.clientX / containerWidth) * 100; | |
| if (newWidth > 20 && newWidth < 80) { | |
| editorPanel.style.width = `${newWidth}%`; | |
| previewPanel.style.width = `${100 - newWidth}%`; | |
| } | |
| }); | |
| document.addEventListener('mouseup', () => { | |
| isResizing = false; | |
| resizer.classList.remove('dragging'); | |
| document.body.style.cursor = 'default'; | |
| document.body.style.userSelect = 'auto'; | |
| }); | |
| // --- Console Logic --- | |
| function addLog(type, message) { | |
| const timestamp = new Date().toLocaleTimeString(); | |
| const logLine = document.createElement('div'); | |
| logLine.className = `console-line ${type}`; | |
| logLine.innerHTML = `<span class="timestamp">${timestamp}</span> <span>${message}</span>`; | |
| consoleOutput.appendChild(logLine); | |
| consoleOutput.scrollTop = consoleOutput.scrollHeight; | |
| state.logs.push({ type, message, timestamp }); | |
| logCountEl.textContent = state.logs.length; | |
| // Update status | |
| const statusDot = document.getElementById('statusDot'); | |
| const statusText = document.getElementById('statusText'); | |
| if(type === 'error') { | |
| statusDot.style.background = 'var(--error)'; | |
| statusText.textContent = 'Fehler'; | |
| } else { | |
| statusDot.style.background = 'var(--success)'; | |
| statusText.textContent = 'Aktiv'; | |
| } | |
| } | |
| // Intercept console.log in iframe | |
| function updatePreview() { | |
| const code = editor.getValue(); | |
| const doc = previewFrame.contentDocument || previewFrame.contentWindow.document; | |
| // Create a proxy for console | |
| const consoleProxy = ` | |
| <script> | |
| (function() { | |
| const originalLog = console.log; | |
| const originalError = console.error; | |
| const originalWarn = console.warn; | |
| function sendToParent(type, args) { | |
| const message = Array.from(args).map(arg => | |
| typeof arg === 'object' ? JSON.stringify(arg) : String(arg |