cloud-compiler

A real-time, low-latency code ...
Log | Files | Refs | README | LICENSE

c.html (48865B)


      1 <!DOCTYPE html>
      2 <html lang="en">
      3 <head>
      4     <meta charset="UTF-8">
      5     <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
      6     <title>Amit Dutta // C Compiler</title>
      7     <link rel="icon" type="image/x-icon" href="https://compiler.aranag.site/logo.png">
      8     
      9     <!-- Fonts & Icons -->
     10     <link rel="preconnect" href="https://fonts.googleapis.com">
     11     <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
     12     <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=Inter:wght@300;400;500&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet">
     13     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css">
     14     
     15     <!-- Tailwind CSS -->
     16     <script src="https://cdn.tailwindcss.com"></script>
     17     
     18     <!-- CodeMirror 5 (Professional Editor) -->
     19     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.css">
     20     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/theme/dracula.min.css">
     21     <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.js"></script>
     22     <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/clike/clike.min.js"></script>
     23     <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/edit/closebrackets.min.js"></script>
     24     <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/edit/matchbrackets.min.js"></script>
     25     <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/selection/active-line.min.js"></script>
     26 
     27     <!-- Xterm.js -->
     28     <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css" />
     29     <script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.js"></script>
     30     <script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.js"></script>
     31 
     32     <!-- LZ-String Compression -->
     33     <script src="https://cdn.jsdelivr.net/npm/lz-string@1.5.0/libs/lz-string.min.js"></script>
     34 
     35     <style>
     36         :root {
     37             --bg-main: #050505;
     38             --accent: #bef264; /* Lime 300 */
     39             --text-muted: #737373;
     40             --border-color: rgba(255, 255, 255, 0.1);
     41         }
     42 
     43         body {
     44             font-family: 'Inter', sans-serif;
     45             background-color: var(--bg-main);
     46             color: #f5f5f5;
     47             height: 100vh;
     48             height: 100dvh;
     49             overflow: hidden;
     50             display: flex;
     51             flex-direction: column;
     52         }
     53 
     54         /* Portfolio Aesthetic */
     55         .font-mono { font-family: 'JetBrains Mono', monospace; }
     56         .font-heading { font-family: 'Space Grotesk', sans-serif; }
     57         
     58         /* Noise Overlay */
     59         .bg-noise {
     60             position: fixed; top: 0; left: 0; width: 100%; height: 100%;
     61             pointer-events: none; z-index: 0; opacity: 0.03;
     62             background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E");
     63         }
     64 
     65         /* CRT Scanline */
     66         .crt-scanline {
     67             position: fixed; top: 0; left: 0; width: 100%; height: 2px;
     68             background: rgba(190, 242, 100, 0.1); opacity: 0.5;
     69             pointer-events: none; z-index: 50;
     70             animation: scanline 8s linear infinite;
     71         }
     72         @keyframes scanline { 0% { top: -10vh; } 100% { top: 110vh; } }
     73 
     74         /* CodeMirror Customization */
     75         .CodeMirror {
     76             height: 100% !important;
     77             font-family: 'JetBrains Mono', monospace;
     78             font-size: 13px;
     79             background-color: #0c0f16 !important; /* Slightly lighter than pure black */
     80             color: #f8f8f2;
     81         }
     82         .CodeMirror-gutters {
     83             background-color: #0c0f16 !important;
     84             border-right: 1px solid rgba(255,255,255,0.05) !important;
     85         }
     86         .CodeMirror-linenumber {
     87             color: #555 !important;
     88         }
     89         .CodeMirror-cursor {
     90             border-left: 2px solid var(--accent) !important;
     91         }
     92         .CodeMirror-selected {
     93             background: rgba(190, 242, 100, 0.2) !important;
     94         }
     95         .cm-s-dracula .CodeMirror-activeline-background {
     96             background: rgba(255, 255, 255, 0.03) !important;
     97         }
     98 
     99         /* Custom Scrollbar styling */
    100         ::-webkit-scrollbar {
    101             width: 8px;
    102             height: 8px;
    103         }
    104         ::-webkit-scrollbar-track {
    105             background: #0c0f16; 
    106         }
    107         ::-webkit-scrollbar-thumb {
    108             background: #333; 
    109             border-radius: 4px;
    110             border: 2px solid #0c0f16; /* Creates padding effect */
    111         }
    112         ::-webkit-scrollbar-thumb:hover {
    113             background: #bef264; /* Lime on hover */
    114         }
    115 
    116         /* Specifically for CodeMirror to ensure it takes the custom style */
    117         .CodeMirror-scroll::-webkit-scrollbar,
    118         .xterm-viewport::-webkit-scrollbar {
    119             width: 8px;
    120             height: 8px;
    121         }
    122         .CodeMirror-scroll::-webkit-scrollbar-track,
    123         .xterm-viewport::-webkit-scrollbar-track {
    124             background: #050505;
    125         }
    126         .CodeMirror-scroll::-webkit-scrollbar-thumb,
    127         .xterm-viewport::-webkit-scrollbar-thumb {
    128             background: #2a2a2a;
    129             border-radius: 4px;
    130             border: 1px solid #050505;
    131         }
    132         .CodeMirror-scroll::-webkit-scrollbar-thumb:hover,
    133         .xterm-viewport::-webkit-scrollbar-thumb:hover {
    134             background: var(--accent);
    135         }
    136 
    137         /* Mobile Helper Bar */
    138         #mobile-helper-bar {
    139             display: none; /* Shown via JS on mobile */
    140             background: #151515;
    141             border-top: 1px solid rgba(255,255,255,0.1);
    142             padding: 8px;
    143             overflow-x: auto;
    144             white-space: nowrap;
    145             -webkit-overflow-scrolling: touch;
    146         }
    147         @media (max-width: 768px) {
    148             #mobile-helper-bar { display: flex; gap: 8px; }
    149         }
    150         .helper-key {
    151             background: rgba(255,255,255,0.1);
    152             color: var(--accent);
    153             border: 1px solid rgba(255,255,255,0.1);
    154             border-radius: 4px;
    155             padding: 6px 12px;
    156             font-family: 'JetBrains Mono', monospace;
    157             font-size: 12px;
    158             font-weight: bold;
    159             cursor: pointer;
    160             user-select: none;
    161         }
    162         .helper-key:active { background: var(--accent); color: black; }
    163 
    164         /* Toast Notification */
    165         .toast {
    166             position: fixed;
    167             bottom: 2rem;
    168             left: 50%;
    169             transform: translateX(-50%) translateY(100px);
    170             background: #1a1a1a;
    171             border: 1px solid var(--accent);
    172             color: var(--accent);
    173             padding: 0.5rem 1.5rem;
    174             border-radius: 9999px;
    175             font-family: 'JetBrains Mono', monospace;
    176             font-size: 0.8rem;
    177             transition: transform 0.3s ease;
    178             z-index: 100;
    179         }
    180         .toast.show { transform: translateX(-50%) translateY(0); }
    181         
    182         /* Connection Dot Pulse */
    183         .pulse-dot {
    184             width: 8px;
    185             height: 8px;
    186             border-radius: 50%;
    187             display: inline-block;
    188             box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.7);
    189             animation: pulse-white 2s infinite;
    190         }
    191         .pulse-dot.connected {
    192             background-color: #bef264; /* Lime */
    193             box-shadow: 0 0 0 0 rgba(190, 242, 100, 0.7);
    194             animation: pulse-lime 2s infinite;
    195         }
    196         .pulse-dot.disconnected {
    197             background-color: #ef4444; /* Red */
    198             box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7);
    199             animation: pulse-red 2s infinite;
    200         }
    201         
    202         @keyframes pulse-lime {
    203             0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(190, 242, 100, 0.7); }
    204             70% { transform: scale(1); box-shadow: 0 0 0 6px rgba(190, 242, 100, 0); }
    205             100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(190, 242, 100, 0); }
    206         }
    207         @keyframes pulse-red {
    208             0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); }
    209             70% { transform: scale(1); box-shadow: 0 0 0 6px rgba(239, 68, 68, 0); }
    210             100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); }
    211         }
    212 
    213         /* AI Text Overlay */
    214         .ai-overlay {
    215             position: absolute;
    216             bottom: 10px;
    217             right: 20px;
    218             background: rgba(20, 20, 20, 0.9);
    219             border: 1px solid #ef4444;
    220             color: #fca5a5;
    221             padding: 8px 12px;
    222             border-radius: 6px;
    223             font-family: 'JetBrains Mono', monospace;
    224             font-size: 12px;
    225             z-index: 60;
    226             display: none;
    227             backdrop-filter: blur(4px);
    228             animation: slideIn 0.3s ease-out;
    229             box-shadow: 0 4px 12px rgba(0,0,0,0.5);
    230         }
    231         .ai-overlay.visible { display: flex; align-items: center; gap: 8px; }
    232         
    233         .ai-link {
    234             color: #fff;
    235             text-decoration: underline;
    236             text-decoration-style: dotted;
    237             text-underline-offset: 4px;
    238             cursor: pointer;
    239             font-weight: bold;
    240             transition: color 0.2s;
    241         }
    242         .ai-link:hover { color: #bef264; text-decoration-style: solid; }
    243 
    244         @keyframes slideIn {
    245             from { transform: translateY(20px); opacity: 0; }
    246             to { transform: translateY(0); opacity: 1; }
    247         }
    248 
    249         /* Modals (AI & Clear) */
    250         .modal-overlay {
    251             position: fixed; top: 0; left: 0; width: 100%; height: 100%;
    252             background: rgba(0,0,0,0.8); backdrop-filter: blur(5px);
    253             z-index: 200; display: none; align-items: center; justify-content: center;
    254         }
    255         .modal-overlay.open { display: flex; }
    256 
    257         .modal-content {
    258             background: #0f0f0f;
    259             border: 1px solid var(--accent);
    260             width: 90%; max-width: 600px;
    261             border-radius: 12px;
    262             display: flex; flex-direction: column;
    263             box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.5), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
    264             overflow: hidden;
    265             animation: modalPop 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
    266         }
    267 
    268         @keyframes modalPop {
    269             0% { transform: scale(0.9); opacity: 0; }
    270             100% { transform: scale(1); opacity: 1; }
    271         }
    272 
    273         /* Editor Toolbar Buttons */
    274         .editor-btn {
    275             background: rgba(255,255,255,0.05);
    276             border: 1px solid rgba(255,255,255,0.1);
    277             color: #737373;
    278             width: 32px;
    279             height: 32px;
    280             display: flex;
    281             align-items: center;
    282             justify-content: center;
    283             border-radius: 4px;
    284             transition: all 0.2s;
    285             cursor: pointer;
    286         }
    287         .editor-btn:hover {
    288             background: rgba(255,255,255,0.1);
    289             color: #fff;
    290             border-color: rgba(255,255,255,0.3);
    291         }
    292         .editor-btn.danger:hover {
    293             background: rgba(239, 68, 68, 0.1);
    294             color: #ef4444;
    295             border-color: #ef4444;
    296         }
    297 
    298         /* RESIZER STYLES */
    299         #resizer {
    300             background-color: rgba(255,255,255,0.05);
    301             cursor: col-resize;
    302             transition: background-color 0.2s;
    303             z-index: 50;
    304             display: none; /* hidden on mobile */
    305         }
    306         #resizer:hover, #resizer.resizing {
    307             background-color: var(--accent);
    308         }
    309         @media (min-width: 768px) {
    310             #resizer {
    311                 display: flex;
    312                 width: 8px;
    313                 align-items: center;
    314                 justify-content: center;
    315             }
    316         }
    317         /* Prevent selection during drag */
    318         body.resizing {
    319             user-select: none;
    320             cursor: col-resize;
    321         }
    322         /* Cover iframes during drag to prevent event stealing */
    323         .iframe-shield {
    324             position: absolute;
    325             inset: 0;
    326             z-index: 999;
    327             display: none;
    328         }
    329         body.resizing .iframe-shield {
    330             display: block;
    331         }
    332     </style>
    333 </head>
    334 <body class="antialiased selection:bg-lime-300 selection:text-black">
    335 
    336     <div class="bg-noise"></div>
    337     <div class="crt-scanline"></div>
    338     <div id="toast" class="toast">Link Copied to Clipboard!</div>
    339 
    340     <!-- AI Overlay in Terminal -->
    341     <div id="ai-suggestion" class="ai-overlay">
    342         <i class="fas fa-exclamation-triangle text-red-500"></i>
    343         <span>Error detected. <span id="ask-ai-link" class="ai-link">Ask AI</span> to fix it.</span>
    344     </div>
    345 
    346     <!-- Clear Confirmation Modal -->
    347     <div id="clear-modal" class="modal-overlay">
    348         <div class="modal-content max-w-[320px] p-0 border-red-500/50">
    349             <div class="bg-red-500/10 px-6 py-4 border-b border-red-500/20">
    350                 <h3 class="font-heading font-bold text-lg text-red-500 flex items-center gap-2">
    351                     <i class="fas fa-exclamation-circle"></i> CLEAR CODE
    352                 </h3>
    353             </div>
    354             <div class="p-6 text-center">
    355                 <p class="text-neutral-300 text-sm font-sans mb-6">Are you sure you want to clear the editor? This action will remove all current code.</p>
    356                 <div class="flex justify-center gap-3">
    357                     <button id="cancel-clear-btn" class="px-4 py-2 rounded text-xs font-mono font-bold uppercase text-neutral-400 hover:text-white hover:bg-white/10 transition-all border border-transparent">Cancel</button>
    358                     <button id="confirm-clear-btn" class="bg-red-500/10 hover:bg-red-500 hover:text-black text-red-500 border border-red-500/20 px-4 py-2 rounded text-xs font-mono font-bold uppercase transition-all flex items-center gap-2">
    359                         <i class="fas fa-trash-alt"></i> Confirm
    360                     </button>
    361                 </div>
    362             </div>
    363         </div>
    364     </div>
    365 
    366     <!-- AI Fix Modal -->
    367     <div id="ai-modal" class="modal-overlay">
    368         <div class="modal-content max-h-[80vh]">
    369             <!-- Modal Header -->
    370             <div class="bg-white/5 px-6 py-4 border-b border-white/10 flex justify-between items-center">
    371                 <h3 class="font-heading font-bold text-lg text-lime-300 flex items-center gap-2">
    372                     <i class="fas fa-robot"></i> AI Diagnosis
    373                 </h3>
    374                 <button id="close-modal" class="text-neutral-500 hover:text-white transition-colors">
    375                     <i class="fas fa-times"></i>
    376                 </button>
    377             </div>
    378             
    379             <!-- Modal Body -->
    380             <div class="p-6 overflow-y-auto custom-scrollbar flex-1">
    381                 <div id="ai-loading" class="hidden flex flex-col items-center justify-center py-8 gap-4">
    382                     <div class="pulse-dot connected" style="width: 12px; height: 12px;"></div>
    383                     <p class="font-mono text-neutral-400 text-sm animate-pulse">Analyzing compile error...</p>
    384                 </div>
    385 
    386                 <div id="ai-result" class="hidden space-y-4">
    387                     <div>
    388                         <h4 class="font-mono text-xs uppercase text-neutral-500 mb-2">Explanation</h4>
    389                         <p id="ai-explanation" class="text-sm text-neutral-200 leading-relaxed font-sans"></p>
    390                     </div>
    391                     
    392                     <div>
    393                         <h4 class="font-mono text-xs uppercase text-neutral-500 mb-2">Suggested Fix</h4>
    394                         <div class="relative group">
    395                             <pre id="ai-code-preview" class="bg-black/30 border border-white/10 p-3 rounded text-xs font-mono text-lime-100 overflow-x-auto custom-scrollbar"></pre>
    396                         </div>
    397                     </div>
    398                 </div>
    399                 
    400                 <div id="ai-error-msg" class="hidden text-red-400 text-sm font-mono text-center py-4"></div>
    401             </div>
    402 
    403             <!-- Modal Footer -->
    404             <div class="bg-white/5 px-6 py-4 border-t border-white/10 flex justify-end gap-3">
    405                 <button id="cancel-fix-btn" class="px-4 py-2 rounded text-xs font-mono font-bold uppercase text-neutral-400 hover:text-white hover:bg-white/10 transition-all">Dismiss</button>
    406                 <button id="apply-fix-btn" disabled class="bg-lime-300/10 hover:bg-lime-300 hover:text-black text-lime-300 border border-lime-300/20 px-4 py-2 rounded text-xs font-mono font-bold uppercase transition-all flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed">
    407                     <i class="fas fa-check"></i> Apply Fix
    408                 </button>
    409             </div>
    410         </div>
    411     </div>
    412 
    413     <!-- Header (Responsive) -->
    414     <header class="h-auto md:h-16 flex flex-col md:flex-row items-center justify-between px-4 py-3 md:px-6 shrink-0 border-b border-white/10 z-20 bg-neutral-900/50 backdrop-blur-md gap-3 md:gap-4">
    415         
    416         <!-- Top Row: Title & Editor Tools -->
    417         <div class="flex items-center justify-between w-full md:w-auto gap-6">
    418             <h1 class="text-lg md:text-xl font-heading font-bold text-white tracking-tight flex items-center">
    419                 <span class="text-lime-300 mr-2">//</span>C.COMPILER
    420                 <span id="conn-dot" class="pulse-dot disconnected ml-3" title="Disconnected"></span>
    421             </h1>
    422             
    423             <!-- Editor Tools -->
    424             <div class="flex items-center gap-2">
    425                 <button id="undo-btn" class="editor-btn" title="Undo (Ctrl+Z)">
    426                     <i class="fas fa-undo text-xs"></i>
    427                 </button>
    428                 <button id="redo-btn" class="editor-btn" title="Redo (Ctrl+Y)">
    429                     <i class="fas fa-redo text-xs"></i>
    430                 </button>
    431                 <div class="w-px h-4 bg-white/10 mx-1"></div>
    432                 <button id="clear-code-btn" class="editor-btn danger" title="Clear Code">
    433                     <i class="fas fa-times text-xs"></i>
    434                 </button>
    435             </div>
    436             
    437             <!-- Mobile Only: Exit Link -->
    438             <a href="./index.html" class="md:hidden font-mono text-[10px] text-neutral-500 hover:text-white uppercase tracking-wider transition-colors ml-auto">[ EXIT ]</a>
    439         </div>
    440         
    441         <!-- Middle: Connection Text -->
    442         <div class="hidden md:flex items-center gap-2 font-mono text-xs text-neutral-500">
    443              <span id="connection-status">Connecting to server...</span>
    444         </div>
    445 
    446         <!-- Bottom/Right: Buttons -->
    447         <div class="flex items-center gap-2 w-full md:w-auto justify-end">
    448             <a href="./index.html" class="hidden md:inline font-mono text-[10px] text-neutral-500 hover:text-white uppercase tracking-wider transition-colors mr-2">[ EXIT ]</a>
    449             
    450             <button id="download-btn" class="bg-white/5 hover:bg-neutral-800 text-white border border-white/10 px-3 py-2 rounded font-mono text-[10px] font-bold uppercase tracking-wider flex items-center justify-center transition-all" title="Download .c">
    451                 <i class="fas fa-download"></i>
    452             </button>
    453             
    454             <button id="reset-btn" class="bg-white/5 hover:bg-neutral-800 text-white border border-white/10 px-3 py-2 rounded font-mono text-[10px] font-bold uppercase tracking-wider flex items-center justify-center transition-all" title="Reset Terminal">
    455                 <i class="fas fa-rotate-left"></i>
    456             </button>
    457 
    458             <button id="share-btn" class="bg-white/5 hover:bg-neutral-800 text-white border border-white/10 px-3 py-2 rounded font-mono text-[10px] font-bold uppercase tracking-wider flex items-center justify-center transition-all" title="Share Code">
    459                 <i class="fas fa-share-alt"></i>
    460             </button>
    461             
    462             <button id="run-btn" disabled class="bg-white/5 hover:bg-lime-300 hover:text-black disabled:opacity-50 disabled:cursor-not-allowed text-white border border-white/10 px-4 py-2 rounded font-mono text-xs font-bold uppercase tracking-wider flex items-center gap-2 transition-all flex-1 md:flex-none justify-center shadow-lg shadow-black/50">
    463                 <i class="fas fa-play text-[10px]"></i> <span class="md:hidden lg:inline">EXECUTE</span><span class="hidden md:inline lg:hidden">RUN</span>
    464             </button>
    465         </div>
    466     </header>
    467 
    468     <!-- Main Workspace -->
    469     <div id="workspace-container" class="flex-1 flex flex-col md:flex-row min-h-0 z-10 relative">
    470         
    471         <!-- Code Editor Pane -->
    472         <div id="editor-pane" class="flex-1 flex flex-col h-[60%] md:h-auto min-h-0 border-b md:border-b-0 border-white/10 relative group min-w-[200px]">
    473             <div class="iframe-shield"></div>
    474             <div class="bg-black/20 px-4 py-2 text-[10px] font-mono text-lime-300 uppercase border-b border-white/10 flex justify-between items-center shrink-0">
    475                 <span>SRC // main.c</span>
    476                 <span class="text-neutral-600">GCC 9.4.0</span>
    477             </div>
    478             
    479             <!-- CodeMirror Container -->
    480             <div id="editor-container" class="relative bg-[#0c0f16] flex-1 overflow-hidden">
    481                 <textarea id="code-input" class="hidden">#include <stdio.h>
    482 
    483 int main() {
    484     printf("Hello C Compiler!\n");
    485     return 0;
    486 }</textarea>
    487             </div>
    488             
    489             <!-- Mobile Helper Bar -->
    490             <div id="mobile-helper-bar">
    491                 <div class="helper-key" data-char="    ">Tab</div>
    492                 <div class="helper-key" data-char=";">;</div>
    493                 <div class="helper-key" data-char="=">=</div>
    494                 <div class="helper-key" data-char="()">()</div>
    495                 <div class="helper-key" data-char="[]">[]</div>
    496                 <div class="helper-key" data-char="{}">{}</div>
    497                 <div class="helper-key" data-char='""'>""</div>
    498                 <div class="helper-key" data-char="''">''</div>
    499                 <div class="helper-key" data-char="#">#</div>
    500                 <div class="helper-key" data-char="+">+</div>
    501                 <div class="helper-key" data-char="-">-</div>
    502                 <div class="helper-key" data-char="printf()">printf</div>
    503             </div>
    504         </div>
    505 
    506         <!-- Resizer Handle -->
    507         <div id="resizer">
    508             <i class="fas fa-grip-lines-vertical text-neutral-600 text-xs"></i>
    509         </div>
    510 
    511         <!-- Terminal Pane -->
    512         <div id="terminal-pane" class="flex-1 flex flex-col h-[40%] md:h-auto min-h-0 bg-[#050505] min-w-[200px]">
    513             <div class="iframe-shield"></div>
    514             <div class="bg-black/20 px-4 py-2 text-[10px] font-mono text-lime-300 uppercase border-b border-white/10 flex justify-between items-center shrink-0">
    515                 <span>OUT // TERMINAL</span>
    516                 <div class="flex gap-2">
    517                     <button id="copy-btn" class="text-neutral-500 hover:text-white transition-colors" title="Copy Output"><i class="fas fa-copy"></i></button>
    518                     <span class="text-neutral-600">XTERM.JS</span>
    519                 </div>
    520             </div>
    521             <div class="flex-1 relative">
    522                 <div id="terminal-container" class="absolute inset-0 w-full h-full p-2 overflow-hidden"></div>
    523             </div>
    524         </div>
    525     </div>
    526 
    527     <script type="module">
    528         import { initializeApp } from "https://www.gstatic.com/firebasejs/10.7.1/firebase-app.js";
    529         import { getFirestore, doc, getDoc, setDoc } from "https://www.gstatic.com/firebasejs/10.7.1/firebase-firestore.js";
    530         import { getAuth, signInAnonymously } from "https://www.gstatic.com/firebasejs/10.7.1/firebase-auth.js";
    531 
    532         // --- Firebase Config ---
    533         const firebaseConfig = {
    534             apiKey: "AIzaSyC8U49NgW7EtYBeKL0Sw08-QvM_Bl59zDw",
    535             authDomain: "compiler-aranag-site.firebaseapp.com",
    536             projectId: "compiler-aranag-site",
    537             storageBucket: "compiler-aranag-site.firebasestorage.app",
    538             messagingSenderId: "558890639400",
    539             appId: "1:558890639400:web:125525d10ab51696a5951d",
    540             measurementId: "G-KH9BGSRRGY"
    541         };
    542 
    543         // Initialize Firebase
    544         const app = initializeApp(firebaseConfig);
    545         const db = getFirestore(app);
    546         const auth = getAuth(app);
    547 
    548         // Attempt initial sign-in
    549         signInAnonymously(auth).catch((error) => {
    550             console.warn("Auto-Auth failed. App will try unauthenticated access.", error.code);
    551         });
    552 
    553         // --- Helper: Generate ID ---
    554         function generateId(length = 7) {
    555             const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    556             let result = '';
    557             for (let i = 0; i < length; i++) {
    558                 result += chars.charAt(Math.floor(Math.random() * chars.length));
    559             }
    560             return result;
    561         }
    562 
    563         // --- DOM Elements ---
    564         const runBtn = document.getElementById('run-btn');
    565         const resetBtn = document.getElementById('reset-btn');
    566         const shareBtn = document.getElementById('share-btn');
    567         const copyBtn = document.getElementById('copy-btn');
    568         const downloadBtn = document.getElementById('download-btn');
    569         const connDot = document.getElementById('conn-dot');
    570         const connectionStatus = document.getElementById('connection-status');
    571         const toast = document.getElementById('toast');
    572         
    573         // Editor Tool Elements
    574         const undoBtn = document.getElementById('undo-btn');
    575         const redoBtn = document.getElementById('redo-btn');
    576         const clearCodeBtn = document.getElementById('clear-code-btn');
    577         const clearModal = document.getElementById('clear-modal');
    578         const cancelClearBtn = document.getElementById('cancel-clear-btn');
    579         const confirmClearBtn = document.getElementById('confirm-clear-btn');
    580 
    581         // AI Elements
    582         const aiSuggestion = document.getElementById('ai-suggestion');
    583         const askAiLink = document.getElementById('ask-ai-link');
    584         const aiModal = document.getElementById('ai-modal');
    585         const closeModal = document.getElementById('close-modal');
    586         const cancelFixBtn = document.getElementById('cancel-fix-btn');
    587         const applyFixBtn = document.getElementById('apply-fix-btn');
    588         const aiLoading = document.getElementById('ai-loading');
    589         const aiResult = document.getElementById('ai-result');
    590         const aiExplanation = document.getElementById('ai-explanation');
    591         const aiCodePreview = document.getElementById('ai-code-preview');
    592         const aiErrorMsg = document.getElementById('ai-error-msg');
    593 
    594         // Layout Elements
    595         const resizer = document.getElementById('resizer');
    596         const editorPane = document.getElementById('editor-pane');
    597         const terminalPane = document.getElementById('terminal-pane');
    598         const workspaceContainer = document.getElementById('workspace-container');
    599 
    600         // --- State ---
    601         let socket = null;
    602         let currentLine = ""; 
    603         let startTime = 0;
    604         let lastSuggestedCode = "";
    605         let outputBuffer = "";
    606 
    607         // --- Resizer Logic ---
    608         let isResizing = false;
    609 
    610         resizer.addEventListener('mousedown', (e) => {
    611             isResizing = true;
    612             document.body.classList.add('resizing');
    613             resizer.classList.add('resizing');
    614         });
    615 
    616         document.addEventListener('mousemove', (e) => {
    617             if (!isResizing) return;
    618             
    619             // Only resize on desktop (horizontal layout)
    620             if (window.innerWidth >= 768) {
    621                 const containerWidth = workspaceContainer.clientWidth;
    622                 const newLeftWidth = (e.clientX / containerWidth) * 100;
    623                 
    624                 // Constraints (min 20%, max 80%)
    625                 if (newLeftWidth > 20 && newLeftWidth < 80) {
    626                     editorPane.style.flex = `0 0 ${newLeftWidth}%`;
    627                     terminalPane.style.flex = `1`;
    628                     // Trigger resize for XTerm and CodeMirror
    629                     editor.refresh();
    630                     fitAddon.fit();
    631                 }
    632             }
    633         });
    634 
    635         document.addEventListener('mouseup', () => {
    636             if (isResizing) {
    637                 isResizing = false;
    638                 document.body.classList.remove('resizing');
    639                 resizer.classList.remove('resizing');
    640                 editor.refresh();
    641                 fitAddon.fit();
    642             }
    643         });
    644 
    645 
    646         // --- CodeMirror Setup ---
    647         const editor = CodeMirror.fromTextArea(document.getElementById("code-input"), {
    648             mode: "text/x-csrc",
    649             theme: "dracula",
    650             lineNumbers: true,
    651             indentUnit: 4,
    652             matchBrackets: true,
    653             autoCloseBrackets: true,
    654             styleActiveLine: true,
    655             inputStyle: "contenteditable",
    656             viewportMargin: Infinity,
    657             scrollbarStyle: "native", // Explicitly use native for custom styling
    658             extraKeys: {
    659                 "Backspace": function(cm) {
    660                     if (cm.somethingSelected()) {
    661                         cm.execCommand("delCharBefore");
    662                         return;
    663                     }
    664                     var cursor = cm.getCursor();
    665                     var line = cm.getLine(cursor.line);
    666                     // If cursor is not at start, and everything before it is whitespace
    667                     if (cursor.ch > 0 && /^\s+$/.test(line.slice(0, cursor.ch))) {
    668                         cm.execCommand("indentLess");
    669                     } else {
    670                         cm.execCommand("delCharBefore");
    671                     }
    672                 }
    673             },
    674         });
    675 
    676         // Fix resize issues
    677         window.addEventListener('resize', () => {
    678              editor.refresh();
    679              fitAddon.fit();
    680         });
    681 
    682         // Local Auto-Save
    683         const LOCAL_STORAGE_KEY = 'c_compiler_code_autosave';
    684         editor.on('change', () => {
    685             localStorage.setItem(LOCAL_STORAGE_KEY, editor.getValue());
    686         });
    687 
    688         // Load Auto-Save on Start (if not shared)
    689         const savedCode = localStorage.getItem(LOCAL_STORAGE_KEY);
    690         if (savedCode && !window.location.search.includes('share') && !window.location.search.includes('code')) {
    691             editor.setValue(savedCode);
    692         }
    693 
    694         // --- Editor Toolbar Logic ---
    695         undoBtn.addEventListener('click', () => { editor.undo(); editor.focus(); });
    696         redoBtn.addEventListener('click', () => { editor.redo(); editor.focus(); });
    697 
    698         clearCodeBtn.addEventListener('click', () => {
    699             clearModal.classList.add('open');
    700         });
    701 
    702         cancelClearBtn.addEventListener('click', () => {
    703             clearModal.classList.remove('open');
    704         });
    705 
    706         confirmClearBtn.addEventListener('click', () => {
    707             editor.setValue('');
    708             editor.clearHistory();
    709             editor.focus();
    710             clearModal.classList.remove('open');
    711             showToast("Editor Cleared");
    712         });
    713 
    714         clearModal.addEventListener('click', (e) => {
    715             if (e.target === clearModal) clearModal.classList.remove('open');
    716         });
    717 
    718         // --- Mobile Helper Bar ---
    719         document.querySelectorAll('.helper-key').forEach(key => {
    720             key.addEventListener('click', (e) => {
    721                 const char = key.getAttribute('data-char');
    722                 const doc = editor.getDoc();
    723                 const cursor = doc.getCursor();
    724                 
    725                 if (char === '()') {
    726                     doc.replaceRange('()', cursor);
    727                     doc.setCursor({line: cursor.line, ch: cursor.ch + 1});
    728                 } else if (char === '[]') {
    729                     doc.replaceRange('[]', cursor);
    730                     doc.setCursor({line: cursor.line, ch: cursor.ch + 1});
    731                 } else if (char === '{}') {
    732                     doc.replaceRange('{}', cursor);
    733                     doc.setCursor({line: cursor.line, ch: cursor.ch + 1});
    734                 } else if (char === '""') {
    735                     doc.replaceRange('""', cursor);
    736                     doc.setCursor({line: cursor.line, ch: cursor.ch + 1});
    737                 } else if (char === "''") {
    738                     doc.replaceRange("''", cursor);
    739                     doc.setCursor({line: cursor.line, ch: cursor.ch + 1});
    740                 } else if (char === "printf()") {
    741                     doc.replaceRange('printf("")', cursor);
    742                     doc.setCursor({line: cursor.line, ch: cursor.ch + 8});
    743                 } else {
    744                     doc.replaceRange(char, cursor);
    745                 }
    746                 editor.focus();
    747             });
    748         });
    749 
    750         // --- Download Button ---
    751         downloadBtn.addEventListener('click', () => {
    752             const code = editor.getValue();
    753             const blob = new Blob([code], { type: 'text/x-csrc' });
    754             const url = window.URL.createObjectURL(blob);
    755             const a = document.createElement('a');
    756             a.href = url;
    757             a.download = 'main.c';
    758             document.body.appendChild(a);
    759             a.click();
    760             window.URL.revokeObjectURL(url);
    761             document.body.removeChild(a);
    762             showToast("Downloaded main.c");
    763         });
    764 
    765         window.addEventListener('load', async () => {
    766             const params = new URLSearchParams(window.location.search);
    767             const shareId = params.get('share');
    768             const sharedCodeOld = params.get('code');
    769 
    770             if (shareId) {
    771                 // Fetch from Firebase
    772                 try {
    773                     toast.textContent = "Loading shared code...";
    774                     toast.classList.add('show');
    775                     
    776                     const docRef = doc(db, "shares", shareId);
    777                     const docSnap = await getDoc(docRef);
    778 
    779                     if (docSnap.exists()) {
    780                         const data = docSnap.data();
    781                         editor.setValue(data.code);
    782                         
    783                         // Restore Output if it exists
    784                         if (data.output && term) {
    785                             term.write('\r\n\x1b[38;2;115;115;115m> PREVIOUS OUTPUT:\x1b[0m\r\n');
    786                             term.write(data.output.replace(/\n/g, '\r\n'));
    787                             term.write('\r\n\x1b[38;2;115;115;115m> ----------------\x1b[0m\r\n');
    788                         }
    789 
    790                         toast.textContent = "Code loaded successfully";
    791                     } else {
    792                         toast.textContent = "Shared code not found";
    793                     }
    794                     setTimeout(() => toast.classList.remove('show'), 3000);
    795                 } catch (e) {
    796                     console.error("Fetch error:", e);
    797                     if (e.code === 'permission-denied') {
    798                          toast.textContent = "Error: Database Access Denied";
    799                     } else {
    800                          toast.textContent = "Error loading code";
    801                     }
    802                     setTimeout(() => toast.classList.remove('show'), 3000);
    803                 }
    804             } else if (sharedCodeOld) {
    805                 // Decryption Support: Try LZString first, then fallback to Base64
    806                 let decoded = null;
    807                 try {
    808                     decoded = LZString.decompressFromEncodedURIComponent(sharedCodeOld);
    809                 } catch (e) { console.warn("LZString failed:", e); }
    810 
    811                 if (!decoded) {
    812                     try { decoded = atob(sharedCodeOld); } catch(e) { console.warn("Base64 failed:", e); }
    813                 }
    814 
    815                 if (decoded) {
    816                     editor.setValue(decoded);
    817                 }
    818             }
    819             setTimeout(connect, 500); 
    820         });
    821 
    822         // --- Terminal Setup ---
    823         const term = new Terminal({
    824             theme: {
    825                 background: '#050505',
    826                 foreground: '#f5f5f5',
    827                 cursor: '#bef264',
    828                 selectionBackground: 'rgba(190, 242, 100, 0.3)',
    829                 black: '#050505',
    830                 green: '#bef264', 
    831                 yellow: '#facc15',
    832                 red: '#ef4444',
    833             },
    834             fontFamily: "'JetBrains Mono', monospace",
    835             fontSize: 12, 
    836             cursorBlink: true,
    837             convertEol: true
    838         });
    839         const fitAddon = new FitAddon.FitAddon();
    840         term.loadAddon(fitAddon);
    841         term.open(document.getElementById('terminal-container'));
    842         fitAddon.fit();
    843         
    844         // Helper: Get Clean Terminal Output
    845         function getTerminalContent() {
    846             if (!term) return "";
    847             const buffer = term.buffer.active;
    848             let text = "";
    849             for (let i = 0; i < buffer.length; i++) {
    850                 const line = buffer.getLine(i);
    851                 if (line) {
    852                     let lineText = line.translateToString(true);
    853                     // Filter system messages
    854                     if(lineText.trim().startsWith("> [") || 
    855                        lineText.includes("SYSTEM READY") || 
    856                        lineText.includes("ATTEMPTING") || 
    857                        lineText.includes("CONNECTION") || 
    858                        lineText.includes("PREVIOUS OUTPUT") || 
    859                        lineText.includes("> ----------------") ||
    860                        lineText.includes("> ./a.out")
    861                        ) {
    862                         continue;
    863                     }
    864                     text += lineText + "\n";
    865                 }
    866             }
    867             return text.trim();
    868         }
    869 
    870         // Custom Key Handler for Ctrl+C Copy
    871         term.attachCustomKeyEventHandler((arg) => {
    872             if (arg.ctrlKey && arg.code === "KeyC" && arg.type === "keydown") {
    873                 const selection = term.getSelection();
    874                 if (selection) {
    875                     fallbackCopyTextToClipboard(selection);
    876                     return false; 
    877                 }
    878             }
    879             return true;
    880         });
    881 
    882         term.write('\x1b[38;2;115;115;115m> SYSTEM READY.\r\n> ATTEMPTING CONNECTION...\x1b[0m\r\n');
    883 
    884         // --- WebSocket Logic ---
    885         function connect() {
    886             const url = "wss://compiler-z4x4.onrender.com"; 
    887             try { socket = new WebSocket(url); } catch (e) {
    888                 term.write(`\r\n\x1b[31m> INVALID URL.\x1b[0m\r\n`);
    889                 return;
    890             }
    891 
    892             socket.onopen = () => {
    893                 connDot.className = "pulse-dot connected ml-3";
    894                 if(connectionStatus) connectionStatus.textContent = "Connected to Server";
    895                 if(connectionStatus) connectionStatus.className = "hidden md:flex items-center gap-2 font-mono text-xs text-lime-300";
    896                 
    897                 term.write(`\x1b[38;2;190;242;100m> CONNECTION ESTABLISHED.\x1b[0m\r\n> ./a.out\r\n`);
    898                 runBtn.disabled = false;
    899             };
    900 
    901             socket.onclose = () => {
    902                 connDot.className = "pulse-dot disconnected ml-3";
    903                 if(connectionStatus) connectionStatus.textContent = "Disconnected";
    904                 if(connectionStatus) connectionStatus.className = "hidden md:flex items-center gap-2 font-mono text-xs text-red-500";
    905                 
    906                 term.write(`\r\n\x1b[31m> CONNECTION LOST. RECONNECTING...\x1b[0m\r\n`);
    907                 runBtn.disabled = true;
    908                 setTimeout(connect, 3000); 
    909                 socket = null;
    910             };
    911 
    912             socket.onmessage = (event) => {
    913                 const msg = JSON.parse(event.data);
    914                 if (msg.type === 'stdout') {
    915                     let text = msg.data;
    916                     outputBuffer += text;
    917 
    918                     // Trigger AI Overlay on Error
    919                     if (outputBuffer.toLowerCase().includes("error") || outputBuffer.toLowerCase().includes("warning")) {
    920                         aiSuggestion.classList.add('visible');
    921                     }
    922 
    923                     if (!text.includes('\r')) {
    924                          text = text.replace(/\n/g, '\r\n');
    925                     }
    926                     term.write(text);
    927                 } else if (msg.type === 'status') {
    928                     if (msg.msg.includes("Program finished")) {
    929                         const duration = (Date.now() - startTime) / 1000;
    930                         term.write(`\r\n\x1b[38;2;115;115;115m[Finished in ${duration.toFixed(3)}s]\x1b[0m\r\n`);
    931                     }
    932                 } else if (msg.type === 'ai_response') {
    933                     handleAiResponse(msg.data);
    934                 } else if (msg.type === 'ai_error') {
    935                     showAiError(msg.msg);
    936                 }
    937             };
    938         }
    939 
    940         // --- Run Logic ---
    941         runBtn.addEventListener('click', () => {
    942             if (!socket || socket.readyState !== WebSocket.OPEN) return;
    943             if (document.activeElement) document.activeElement.blur();
    944             
    945             term.reset();
    946             currentLine = ""; 
    947             outputBuffer = ""; 
    948             aiSuggestion.classList.remove('visible'); 
    949             
    950             let code = editor.getValue();
    951             code = code.replace(/\u00A0/g, " ").replace(/[\u2018\u2019]/g, "'").replace(/[\u201C\u201D]/g, '"');
    952             
    953             // Auto-Flush Injection: Fixes buffered output issues for students
    954             function injectAutoFlush(source) {
    955                 const mainRegex = /(int|void)\s+main\s*\([^)]*\)\s*\{/;
    956                 const match = source.match(mainRegex);
    957                 if (match) {
    958                     const insertionPoint = match.index + match[0].length;
    959                     return source.slice(0, insertionPoint) + "\n    setbuf(stdout, NULL);" + source.slice(insertionPoint);
    960                 }
    961                 return source;
    962             }
    963             code = injectAutoFlush(code);
    964 
    965             startTime = Date.now();
    966             term.write('\x1b[32m> gcc main.c -o main -lm -pthread && ./main\x1b[0m\r\n');
    967 
    968             socket.send(JSON.stringify({
    969                 type: 'run',
    970                 code: code,
    971                 language: 'c'
    972             }));
    973             
    974             term.focus();
    975         });
    976 
    977         // --- AI Feature Logic ---
    978         askAiLink.addEventListener('click', () => {
    979             const errorContext = getTerminalContent();
    980             const currentCode = editor.getValue();
    981             
    982             aiModal.classList.add('open');
    983             aiLoading.classList.remove('hidden');
    984             aiResult.classList.add('hidden');
    985             aiErrorMsg.classList.add('hidden');
    986             applyFixBtn.disabled = true;
    987 
    988             socket.send(JSON.stringify({
    989                 type: 'ai_fix',
    990                 code: currentCode,
    991                 error: errorContext,
    992                 language: 'c'
    993             }));
    994         });
    995 
    996         function handleAiResponse(data) {
    997             aiLoading.classList.add('hidden');
    998             aiResult.classList.remove('hidden');
    999             aiExplanation.textContent = data.explanation;
   1000             aiCodePreview.textContent = data.fixed_code;
   1001             lastSuggestedCode = data.fixed_code;
   1002             applyFixBtn.disabled = false;
   1003         }
   1004 
   1005         function showAiError(msg) {
   1006             aiLoading.classList.add('hidden');
   1007             aiErrorMsg.textContent = msg;
   1008             aiErrorMsg.classList.remove('hidden');
   1009         }
   1010 
   1011         applyFixBtn.addEventListener('click', () => {
   1012             if (lastSuggestedCode) {
   1013                 editor.setValue(lastSuggestedCode);
   1014                 closeAiModal();
   1015                 showToast("Fix Applied Successfully!");
   1016                 aiSuggestion.classList.remove('visible');
   1017             }
   1018         });
   1019 
   1020         function closeAiModal() {
   1021             aiModal.classList.remove('open');
   1022         }
   1023         closeModal.addEventListener('click', closeAiModal);
   1024         cancelFixBtn.addEventListener('click', closeAiModal);
   1025         aiModal.addEventListener('click', (e) => {
   1026             if (e.target === aiModal) closeAiModal();
   1027         });
   1028 
   1029         // --- Reset Logic ---
   1030         resetBtn.addEventListener('click', () => {
   1031             term.reset();
   1032             currentLine = "";
   1033             outputBuffer = ""; 
   1034             aiSuggestion.classList.remove('visible');
   1035             term.write(`\x1b[38;2;190;242;100m> CONNECTION ESTABLISHED.\x1b[0m\r\n> ./a.out\r\n`);
   1036         });
   1037 
   1038         // --- Share Functionality with Firebase ---
   1039         shareBtn.addEventListener('click', async () => {
   1040             const originalIcon = shareBtn.innerHTML;
   1041             shareBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
   1042             shareBtn.disabled = true;
   1043 
   1044             try {
   1045                 if (!auth.currentUser) {
   1046                     try {
   1047                         await signInAnonymously(auth);
   1048                     } catch (authError) {
   1049                         console.warn("Anonymous auth failed:", authError.code);
   1050                     }
   1051                 }
   1052 
   1053                 const code = editor.getValue();
   1054                 const output = getTerminalContent();
   1055                 const shareId = generateId();
   1056                 
   1057                 await setDoc(doc(db, "shares", shareId), {
   1058                     code: code,
   1059                     language: 'c',
   1060                     output: output,
   1061                     createdAt: new Date().toISOString()
   1062                 });
   1063 
   1064                 const url = new URL(window.location.href);
   1065                 url.searchParams.delete('code');
   1066                 url.searchParams.set('share', shareId);
   1067                 const shareUrl = url.toString();
   1068 
   1069                 if (navigator.share) {
   1070                     try {
   1071                         await navigator.share({
   1072                             title: document.title,
   1073                             text: 'Check out my C code!',
   1074                             url: shareUrl
   1075                         });
   1076                     } catch (err) {
   1077                         fallbackCopyTextToClipboard(shareUrl);
   1078                     }
   1079                 } else {
   1080                     fallbackCopyTextToClipboard(shareUrl);
   1081                 }
   1082             } catch (error) {
   1083                 console.error("Share failed:", error);
   1084                 if (error.code === 'permission-denied') {
   1085                     showToast("Share Failed: Access Denied");
   1086                 } else {
   1087                     showToast("Share Failed: " + error.message);
   1088                 }
   1089             } finally {
   1090                 shareBtn.innerHTML = originalIcon;
   1091                 shareBtn.disabled = false;
   1092             }
   1093         });
   1094 
   1095         function showToast(msg) {
   1096             toast.textContent = msg;
   1097             toast.classList.add('show');
   1098             setTimeout(() => toast.classList.remove('show'), 3000);
   1099         }
   1100 
   1101         // --- Smart Copy Function ---
   1102         copyBtn.addEventListener('click', () => {
   1103             const text = getTerminalContent();
   1104             fallbackCopyTextToClipboard(text);
   1105         });
   1106 
   1107         function fallbackCopyTextToClipboard(text) {
   1108             const textArea = document.createElement("textarea");
   1109             textArea.value = text;
   1110             textArea.style.position = "fixed";
   1111             textArea.style.top = "0";
   1112             textArea.style.left = "0";
   1113             textArea.style.opacity = "0"; 
   1114             document.body.appendChild(textArea);
   1115             textArea.focus();
   1116             textArea.select();
   1117             try {
   1118                 document.execCommand('copy');
   1119                 showToast("Copied to Clipboard!");
   1120             } catch (err) {
   1121                 showToast("Copy Failed");
   1122             }
   1123             document.body.removeChild(textArea);
   1124         }
   1125 
   1126         // Terminal Input
   1127         term.onData((data) => {
   1128             if (!socket || socket.readyState !== WebSocket.OPEN) return;
   1129 
   1130             if (data === '\r') { 
   1131                 term.write('\r\n'); 
   1132                 socket.send(JSON.stringify({ type: 'input', data: currentLine + '\n' }));
   1133                 currentLine = "";
   1134             } else if (data === '\x7f' || data === '\b') { 
   1135                 if (currentLine.length > 0) {
   1136                     currentLine = currentLine.slice(0, -1);
   1137                     term.write('\b \b'); 
   1138                 }
   1139             } else { 
   1140                 currentLine += data;
   1141                 term.write(data); 
   1142             }
   1143         });
   1144     </script>
   1145 </body>
   1146 </html>
© notamitgamer • Site Built: 2026-07-21 13:58:23 UTC • git-mirror commit: 1037f62 [view raw info]
Originally created with stagit • modified by notamitgamer
Forked from github.com/notamitgamer/git-mirror