CoolFace
Apppublic

akhaliq/North-Mini-Code-1.0

sourceHugging Faceupdated 4mo agoView on Hugging Face
0likes
index.html1601 linesDownload Raw Back to root
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">6<title>North Mini Code 1.0</title>7<meta name="description" content="Terminal-style coding assistant powered by North Mini Code 1.0">8<link rel="preconnect" href="https://fonts.googleapis.com">9<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>10<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600;700&display=swap" rel="stylesheet">11<style>12/* ═══════════════════════════════════════════════════════13   RESET & BASE14   ═══════════════════════════════════════════════════════ */15*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }16 17:root {18  --bg-deep: #0a0e14;19  --bg-panel: #0d1117;20  --bg-code: #161b22;21  --border: #1e2a3a;22  --border-focus: #2d4a6a;23  --green: #39ff14;24  --green-dim: #1a7a0a;25  --cyan: #00d4ff;26  --amber: #ffb300;27  --gray-light: #e0e0e0;28  --gray-mid: #8b949e;29  --gray-dim: #484f58;30  --red: #ff5555;31  --success: #50fa7b;32  --code-text: #f8f8f2;33  --glow-green: 0 0 8px rgba(57,255,20,0.3);34  --glow-cyan: 0 0 8px rgba(0,212,255,0.3);35  --glow-amber: 0 0 8px rgba(255,179,0,0.2);36  --font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace;37  --radius: 4px;38  --transition: 0.2s ease;39}40 41html, body {42  height: 100%;43  background: var(--bg-deep);44  color: var(--gray-light);45  font-family: var(--font-mono);46  font-size: 13px;47  line-height: 1.6;48  overflow: hidden;49}50 51/* CRT scanline overlay */52body::after {53  content: '';54  position: fixed;55  inset: 0;56  pointer-events: none;57  z-index: 9999;58  background: repeating-linear-gradient(59    0deg,60    transparent,61    transparent 2px,62    rgba(0, 0, 0, 0.03) 2px,63    rgba(0, 0, 0, 0.03) 4px64  );65}66 67::selection {68  background: rgba(57, 255, 20, 0.25);69  color: #fff;70}71 72::-webkit-scrollbar { width: 6px; height: 6px; }73::-webkit-scrollbar-track { background: transparent; }74::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }75::-webkit-scrollbar-thumb:hover { background: var(--gray-dim); }76 77a { color: var(--cyan); text-decoration: none; }78a:hover { text-decoration: underline; text-shadow: var(--glow-cyan); }79 80/* ═══════════════════════════════════════════════════════81   APP SHELL82   ═══════════════════════════════════════════════════════ */83#app {84  display: flex;85  flex-direction: column;86  height: 100vh;87  max-height: 100vh;88}89 90/* ═══════════════════════════════════════════════════════91   CONFIG WARNING92   ═══════════════════════════════════════════════════════ */93#config-warning {94  display: none;95  background: linear-gradient(90deg, rgba(255,85,85,0.1), rgba(255,179,0,0.1));96  border-bottom: 1px solid var(--red);97  padding: 8px 16px;98  font-size: 12px;99  color: var(--amber);100  text-align: center;101  text-shadow: var(--glow-amber);102}103#config-warning.visible { display: block; }104 105/* ═══════════════════════════════════════════════════════106   HEADER107   ═══════════════════════════════════════════════════════ */108#header {109  display: flex;110  align-items: center;111  justify-content: space-between;112  padding: 12px 20px;113  background: var(--bg-panel);114  border-bottom: 1px solid var(--border);115  flex-shrink: 0;116  gap: 16px;117}118 119.header-title {120  display: flex;121  flex-direction: column;122  gap: 2px;123}124 125.header-ascii {126  color: var(--green);127  font-size: 11px;128  line-height: 1.3;129  text-shadow: var(--glow-green);130  white-space: pre;131  letter-spacing: 0.5px;132}133 134.header-subtitle {135  color: var(--gray-mid);136  font-size: 11px;137  padding-left: 3px;138}139 140.header-actions {141  display: flex;142  align-items: center;143  gap: 10px;144  flex-shrink: 0;145}146 147.pill {148  display: inline-flex;149  align-items: center;150  gap: 5px;151  padding: 4px 10px;152  border: 1px solid var(--border);153  border-radius: 12px;154  font-size: 11px;155  color: var(--gray-mid);156  text-decoration: none;157  transition: all var(--transition);158}159.pill:hover {160  border-color: var(--cyan);161  color: var(--cyan);162  text-decoration: none;163  text-shadow: var(--glow-cyan);164}165.pill .dot {166  width: 6px;167  height: 6px;168  border-radius: 50%;169  background: var(--success);170  box-shadow: 0 0 6px var(--success);171}172 173#btn-new-chat {174  background: transparent;175  border: 1px solid var(--border);176  color: var(--amber);177  font-family: var(--font-mono);178  font-size: 11px;179  padding: 5px 12px;180  border-radius: var(--radius);181  cursor: pointer;182  transition: all var(--transition);183  letter-spacing: 1px;184}185#btn-new-chat:hover {186  border-color: var(--amber);187  background: rgba(255,179,0,0.08);188  text-shadow: var(--glow-amber);189}190 191/* ═══════════════════════════════════════════════════════192   MAIN LAYOUT193   ═══════════════════════════════════════════════════════ */194#main {195  display: flex;196  flex: 1;197  min-height: 0;198  overflow: hidden;199}200 201/* ═══════════════════════════════════════════════════════202   TERMINAL (LEFT PANEL)203   ═══════════════════════════════════════════════════════ */204#terminal-panel {205  display: flex;206  flex-direction: column;207  flex: 1;208  min-width: 0;209  border-right: 1px solid var(--border);210}211 212.panel-label {213  padding: 6px 16px;214  font-size: 10px;215  letter-spacing: 2px;216  color: var(--gray-dim);217  border-bottom: 1px solid var(--border);218  background: rgba(13,17,23,0.6);219  text-transform: uppercase;220  flex-shrink: 0;221}222 223#chat-messages {224  flex: 1;225  overflow-y: auto;226  padding: 16px;227  scroll-behavior: smooth;228}229 230/* Message styles */231.msg {232  margin-bottom: 14px;233  line-height: 1.65;234  animation: msgFadeIn 0.25s ease;235}236 237@keyframes msgFadeIn {238  from { opacity: 0; transform: translateY(6px); }239  to { opacity: 1; transform: translateY(0); }240}241 242.msg-prefix {243  font-weight: 600;244  margin-right: 4px;245}246 247.msg-user .msg-prefix {248  color: var(--green);249  text-shadow: var(--glow-green);250}251.msg-user .msg-content {252  color: var(--green);253  text-shadow: var(--glow-green);254}255 256.msg-assistant .msg-prefix {257  color: var(--cyan);258  text-shadow: var(--glow-cyan);259}260.msg-assistant .msg-content {261  color: var(--gray-light);262}263 264.msg-system .msg-prefix {265  color: var(--amber);266  text-shadow: var(--glow-amber);267}268.msg-system .msg-content {269  color: var(--amber);270  opacity: 0.85;271}272 273/* Markdown elements */274.msg-content strong { color: #fff; font-weight: 600; }275.msg-content em { font-style: italic; color: var(--gray-mid); }276.msg-content code:not(pre code) {277  background: var(--bg-code);278  color: var(--code-text);279  padding: 1px 5px;280  border-radius: 3px;281  font-size: 12px;282  border: 1px solid var(--border);283}284.msg-content a { color: var(--cyan); }285.msg-content ul, .msg-content ol {286  margin: 6px 0 6px 20px;287}288.msg-content li { margin-bottom: 3px; }289.msg-content h1, .msg-content h2, .msg-content h3 {290  color: var(--cyan);291  margin: 10px 0 6px;292  font-size: 14px;293  text-shadow: var(--glow-cyan);294}295.msg-content h1 { font-size: 16px; }296.msg-content h2 { font-size: 15px; }297.msg-content p { margin: 4px 0; }298 299/* Code blocks */300.code-block-wrap {301  margin: 8px 0;302  border: 1px solid var(--border);303  border-radius: var(--radius);304  overflow: hidden;305  background: var(--bg-code);306}307.code-block-header {308  display: flex;309  align-items: center;310  justify-content: space-between;311  padding: 4px 10px;312  background: rgba(30,42,58,0.5);313  border-bottom: 1px solid var(--border);314  font-size: 11px;315}316.code-lang {317  color: var(--amber);318  text-transform: uppercase;319  letter-spacing: 1px;320}321.btn-copy {322  background: transparent;323  border: 1px solid var(--border);324  color: var(--gray-mid);325  font-family: var(--font-mono);326  font-size: 10px;327  padding: 2px 8px;328  border-radius: 3px;329  cursor: pointer;330  transition: all var(--transition);331}332.btn-copy:hover {333  border-color: var(--green);334  color: var(--green);335}336.btn-copy.copied {337  border-color: var(--success);338  color: var(--success);339}340.code-block-wrap pre {341  margin: 0;342  padding: 10px 12px;343  overflow-x: auto;344  font-size: 12px;345  line-height: 1.5;346  color: var(--code-text);347}348.code-block-wrap pre code {349  font-family: var(--font-mono);350  background: none;351  border: none;352  padding: 0;353}354 355/* Thinking blocks */356.think-block {357  margin: 8px 0;358  border: 1px solid rgba(255,179,0,0.15);359  border-radius: var(--radius);360  background: rgba(255,179,0,0.03);361}362.think-block summary {363  padding: 6px 10px;364  cursor: pointer;365  font-size: 12px;366  color: var(--gray-dim);367  user-select: none;368  transition: color var(--transition);369}370.think-block summary:hover { color: var(--amber); }371.think-block .think-content {372  padding: 6px 12px 10px;373  font-size: 12px;374  color: var(--gray-dim);375  line-height: 1.55;376  border-top: 1px solid rgba(255,179,0,0.1);377}378 379/* Streaming cursor */380.streaming-cursor::after {381  content: '█';382  animation: blink 0.8s step-end infinite;383  color: var(--green);384  margin-left: 2px;385}386@keyframes blink {387  50% { opacity: 0; }388}389 390/* ═══════════════════════════════════════════════════════391   INPUT AREA392   ═══════════════════════════════════════════════════════ */393#input-area {394  flex-shrink: 0;395  border-top: 1px solid var(--border);396  background: var(--bg-panel);397  padding: 10px 16px 8px;398}399 400/* Target toggle */401#target-toggle {402  display: flex;403  gap: 14px;404  margin-bottom: 8px;405  align-items: center;406}407 408.target-label {409  font-size: 10px;410  color: var(--gray-dim);411  letter-spacing: 1px;412  text-transform: uppercase;413}414 415.target-btn {416  background: transparent;417  border: none;418  font-family: var(--font-mono);419  font-size: 12px;420  color: var(--gray-dim);421  cursor: pointer;422  padding: 2px 0;423  border-bottom: 2px solid transparent;424  transition: all var(--transition);425  letter-spacing: 0.5px;426}427.target-btn:hover { color: var(--gray-mid); }428.target-btn.active {429  color: var(--green);430  border-bottom-color: var(--green);431  text-shadow: var(--glow-green);432}433 434#input-row {435  display: flex;436  gap: 8px;437  align-items: flex-end;438}439 440.input-prompt-symbol {441  color: var(--green);442  font-weight: 700;443  font-size: 14px;444  line-height: 36px;445  text-shadow: var(--glow-green);446  flex-shrink: 0;447}448 449#chat-input {450  flex: 1;451  background: var(--bg-deep);452  border: 1px solid var(--border);453  border-radius: var(--radius);454  color: var(--green);455  font-family: var(--font-mono);456  font-size: 13px;457  padding: 8px 12px;458  resize: none;459  outline: none;460  min-height: 36px;461  max-height: 120px;462  line-height: 1.5;463  transition: border-color var(--transition);464  caret-color: var(--green);465  text-shadow: var(--glow-green);466}467#chat-input::placeholder {468  color: var(--gray-dim);469  text-shadow: none;470}471#chat-input:focus {472  border-color: var(--border-focus);473}474 475#btn-send, #btn-stop {476  font-family: var(--font-mono);477  font-size: 12px;478  padding: 8px 14px;479  border-radius: var(--radius);480  cursor: pointer;481  transition: all var(--transition);482  letter-spacing: 1px;483  flex-shrink: 0;484  height: 36px;485  display: flex;486  align-items: center;487  gap: 4px;488}489 490#btn-send {491  background: transparent;492  border: 1px solid var(--green);493  color: var(--green);494}495#btn-send:hover:not(:disabled) {496  background: var(--green);497  color: var(--bg-deep);498  box-shadow: 0 0 12px rgba(57,255,20,0.3);499}500#btn-send:disabled {501  opacity: 0.3;502  cursor: not-allowed;503}504 505#btn-stop {506  background: transparent;507  border: 1px solid var(--red);508  color: var(--red);509  display: none;510}511#btn-stop:hover {512  background: var(--red);513  color: var(--bg-deep);514  box-shadow: 0 0 12px rgba(255,85,85,0.3);515}516 517/* Examples */518#examples-row {519  display: flex;520  align-items: center;521  gap: 8px;522  margin-top: 8px;523  flex-wrap: wrap;524}525.examples-label {526  font-size: 10px;527  color: var(--gray-dim);528  letter-spacing: 1px;529  text-transform: uppercase;530  flex-shrink: 0;531}532.example-chip {533  background: rgba(30,42,58,0.4);534  border: 1px solid var(--border);535  border-radius: 12px;536  padding: 3px 10px;537  font-family: var(--font-mono);538  font-size: 11px;539  color: var(--gray-mid);540  cursor: pointer;541  transition: all var(--transition);542  white-space: nowrap;543}544.example-chip:hover {545  border-color: var(--cyan);546  color: var(--cyan);547  background: rgba(0,212,255,0.05);548  text-shadow: var(--glow-cyan);549}550 551/* ═══════════════════════════════════════════════════════552   OUTPUT PANEL (RIGHT)553   ═══════════════════════════════════════════════════════ */554#output-panel {555  display: flex;556  flex-direction: column;557  width: 45%;558  min-width: 340px;559  max-width: 55%;560  background: var(--bg-panel);561}562 563#output-tabs {564  display: flex;565  border-bottom: 1px solid var(--border);566  background: rgba(13,17,23,0.6);567  flex-shrink: 0;568}569 570.output-tab {571  flex: 1;572  background: transparent;573  border: none;574  border-bottom: 2px solid transparent;575  color: var(--gray-dim);576  font-family: var(--font-mono);577  font-size: 11px;578  padding: 8px 12px;579  cursor: pointer;580  transition: all var(--transition);581  letter-spacing: 1px;582  text-transform: uppercase;583}584.output-tab:hover { color: var(--gray-mid); }585.output-tab.active {586  color: var(--cyan);587  border-bottom-color: var(--cyan);588  text-shadow: var(--glow-cyan);589}590 591#output-content {592  flex: 1;593  overflow: auto;594  position: relative;595}596 597/* Tab panes */598.tab-pane { display: none; height: 100%; }599.tab-pane.active { display: flex; flex-direction: column; }600 601/* Preview tab */602#pane-preview {603  align-items: center;604  justify-content: center;605  position: relative;606}607 608.preview-placeholder {609  text-align: center;610  color: var(--gray-dim);611  padding: 40px 20px;612}613.preview-placeholder .ascii-art {614  font-size: 11px;615  line-height: 1.3;616  margin-bottom: 16px;617  color: var(--border-focus);618}619.preview-placeholder .placeholder-text {620  font-size: 12px;621  letter-spacing: 0.5px;622}623 624#preview-image {625  display: none;626  max-width: 100%;627  max-height: 100%;628  object-fit: contain;629  padding: 12px;630}631 632#preview-iframe {633  display: none;634  width: 100%;635  flex: 1;636  min-height: 680px;637  border: none;638  background: #fff;639}640 641#btn-fullscreen {642  display: none;643  position: absolute;644  top: 8px;645  right: 8px;646  background: rgba(13,17,23,0.8);647  border: 1px solid var(--border);648  color: var(--gray-mid);649  font-family: var(--font-mono);650  font-size: 11px;651  padding: 4px 10px;652  border-radius: var(--radius);653  cursor: pointer;654  z-index: 5;655  transition: all var(--transition);656}657#btn-fullscreen:hover {658  border-color: var(--cyan);659  color: var(--cyan);660}661 662/* Console tab */663#pane-console { padding: 12px 16px; gap: 12px; overflow-y: auto; }664 665.console-section { margin-bottom: 8px; }666.console-label {667  font-size: 10px;668  letter-spacing: 2px;669  color: var(--gray-dim);670  margin-bottom: 4px;671  text-transform: uppercase;672}673.console-output {674  background: var(--bg-deep);675  border: 1px solid var(--border);676  border-radius: var(--radius);677  padding: 10px 12px;678  font-size: 12px;679  line-height: 1.5;680  white-space: pre-wrap;681  word-break: break-word;682  min-height: 40px;683  max-height: 280px;684  overflow-y: auto;685}686#console-stdout { color: var(--success); }687#console-stderr { color: var(--red); }688 689/* Code tab */690#pane-code { padding: 0; }691 692.code-tab-header {693  display: flex;694  align-items: center;695  justify-content: space-between;696  padding: 8px 12px;697  border-bottom: 1px solid var(--border);698  background: rgba(30,42,58,0.3);699  flex-shrink: 0;700}701.code-tab-lang {702  font-size: 11px;703  color: var(--amber);704  letter-spacing: 1px;705  text-transform: uppercase;706}707.code-tab-actions {708  display: flex;709  gap: 8px;710}711.code-tab-btn {712  background: transparent;713  border: 1px solid var(--border);714  color: var(--gray-mid);715  font-family: var(--font-mono);716  font-size: 10px;717  padding: 3px 8px;718  border-radius: 3px;719  cursor: pointer;720  text-decoration: none;721  transition: all var(--transition);722  display: inline-flex;723  align-items: center;724  gap: 4px;725}726.code-tab-btn:hover {727  border-color: var(--cyan);728  color: var(--cyan);729  text-decoration: none;730}731 732#code-display {733  flex: 1;734  overflow: auto;735  padding: 12px;736  background: var(--bg-code);737}738#code-display pre {739  margin: 0;740  font-size: 12px;741  line-height: 1.5;742  color: var(--code-text);743}744 745.code-placeholder {746  display: flex;747  align-items: center;748  justify-content: center;749  height: 100%;750  color: var(--gray-dim);751  font-size: 12px;752}753 754/* ═══════════════════════════════════════════════════════755   STATUS BAR756   ═══════════════════════════════════════════════════════ */757#status-bar {758  display: flex;759  align-items: center;760  gap: 8px;761  padding: 5px 16px;762  border-top: 1px solid var(--border);763  background: var(--bg-panel);764  font-size: 11px;765  flex-shrink: 0;766}767 768.status-indicator {769  display: inline-flex;770  align-items: center;771  gap: 6px;772}773 774.status-dot {775  font-size: 10px;776  line-height: 1;777}778 779#status-text {780  letter-spacing: 1px;781  text-transform: uppercase;782}783 784.status-idle { color: var(--gray-dim); }785.status-working { color: var(--amber); text-shadow: var(--glow-amber); }786.status-success { color: var(--success); text-shadow: 0 0 8px rgba(80,250,123,0.3); }787.status-error { color: var(--red); text-shadow: 0 0 8px rgba(255,85,85,0.3); }788.status-info { color: var(--cyan); text-shadow: var(--glow-cyan); }789 790@keyframes spin {791  to { transform: rotate(360deg); }792}793.status-working .status-dot {794  display: inline-block;795  animation: spin 1s linear infinite;796}797 798/* ═══════════════════════════════════════════════════════799   FULLSCREEN OVERLAY800   ═══════════════════════════════════════════════════════ */801#fullscreen-overlay {802  display: none;803  position: fixed;804  inset: 0;805  z-index: 1000;806  background: var(--bg-deep);807  flex-direction: column;808}809#fullscreen-overlay.active { display: flex; }810 811#fullscreen-bar {812  display: flex;813  align-items: center;814  justify-content: space-between;815  padding: 8px 16px;816  border-bottom: 1px solid var(--border);817  background: var(--bg-panel);818}819#fullscreen-bar span {820  color: var(--cyan);821  font-size: 12px;822  letter-spacing: 1px;823}824#btn-exit-fullscreen {825  background: transparent;826  border: 1px solid var(--border);827  color: var(--gray-mid);828  font-family: var(--font-mono);829  font-size: 11px;830  padding: 4px 12px;831  border-radius: var(--radius);832  cursor: pointer;833  transition: all var(--transition);834}835#btn-exit-fullscreen:hover {836  border-color: var(--red);837  color: var(--red);838}839#fullscreen-iframe {840  flex: 1;841  border: none;842  background: #fff;843}844 845/* ═══════════════════════════════════════════════════════846   RESPONSIVE847   ═══════════════════════════════════════════════════════ */848@media (max-width: 900px) {849  #main {850    flex-direction: column;851  }852  #terminal-panel {853    border-right: none;854    border-bottom: 1px solid var(--border);855    max-height: 55vh;856  }857  #output-panel {858    width: 100%;859    max-width: 100%;860    min-width: 0;861    flex: 1;862  }863  .header-ascii { font-size: 10px; }864  #chat-input { font-size: 12px; }865  #preview-iframe { min-height: 400px; }866}867 868@media (max-width: 600px) {869  #header { padding: 8px 12px; gap: 8px; }870  .header-ascii { display: none; }871  .header-subtitle { display: none; }872  .pill { font-size: 10px; padding: 3px 8px; }873  #chat-messages { padding: 10px; }874  #input-area { padding: 8px 10px 6px; }875  #examples-row { display: none; }876}877</style>878</head>879<body>880<div id="app">881  <!-- Config Warning -->882  <div id="config-warning">⚠ WARNING: COHERE_API_KEY not configured. Set it as a Space secret to enable the model.</div>883 884  <!-- Header -->885  <header id="header">886    <div class="header-title">887      <div class="header-ascii" id="header-ascii-art">╔═══ NORTH MINI CODE 1.0 ═══╗</div>888      <div class="header-subtitle" id="header-subtitle">Terminal Coding Assistant</div>889    </div>890    <div class="header-actions">891      <a class="pill" id="model-pill" href="#" target="_blank" rel="noopener">892        <span class="dot"></span>893        <span id="model-pill-text">north-mini-code-1-0</span>894      </a>895      <a class="pill" id="opencode-pill" href="#" target="_blank" rel="noopener">OpenCode</a>896      <button id="btn-new-chat" onclick="newChat()" title="Start a new chat session">[NEW]</button>897    </div>898  </header>899 900  <!-- Main Layout -->901  <div id="main">902    <!-- Terminal Panel -->903    <div id="terminal-panel">904      <div class="panel-label">Terminal</div>905      <div id="chat-messages"></div>906      <div id="input-area">907        <div id="target-toggle">908          <span class="target-label">Mode:</span>909          <button class="target-btn active" data-target="Python" onclick="setTarget('Python')">[ Python ● ]</button>910          <button class="target-btn" data-target="Web" onclick="setTarget('Web')">[ Web ○ ]</button>911        </div>912        <div id="input-row">913          <span class="input-prompt-symbol">❯</span>914          <textarea id="chat-input" rows="1" placeholder="Ask a coding question or describe what to build…" spellcheck="false"></textarea>915          <button id="btn-send" onclick="handleSend()" title="Send message (Shift+Enter)">➤</button>916          <button id="btn-stop" onclick="stopGeneration()" title="Stop generation">■ STOP</button>917        </div>918        <div id="examples-row"></div>919      </div>920    </div>921 922    <!-- Output Panel -->923    <div id="output-panel">924      <div id="output-tabs">925        <button class="output-tab active" data-tab="preview" onclick="switchTab('preview')">Preview</button>926        <button class="output-tab" data-tab="console" onclick="switchTab('console')">Console</button>927        <button class="output-tab" data-tab="code" onclick="switchTab('code')">Code</button>928      </div>929      <div id="output-content">930        <!-- Preview Pane -->931        <div class="tab-pane active" id="pane-preview">932          <div class="preview-placeholder" id="preview-placeholder">933            <div class="ascii-art">934  ┌──────────────────────┐935  │   ╭━━━╮              │936  │   ┃ ▶ ┃  OUTPUT      │937  │   ╰━━━╯              │938  └──────────────────────┘</div>939            <div class="placeholder-text">Run code to see output here</div>940          </div>941          <img id="preview-image" alt="Generated output">942          <iframe id="preview-iframe" sandbox="allow-scripts"></iframe>943          <button id="btn-fullscreen" onclick="openFullscreen()">⤢ FULLSCREEN</button>944        </div>945 946        <!-- Console Pane -->947        <div class="tab-pane" id="pane-console">948          <div class="console-section">949            <div class="console-label">stdout:</div>950            <div class="console-output" id="console-stdout">No output yet.</div>951          </div>952          <div class="console-section">953            <div class="console-label">stderr:</div>954            <div class="console-output" id="console-stderr">No errors.</div>955          </div>956        </div>957 958        <!-- Code Pane -->959        <div class="tab-pane" id="pane-code">960          <div class="code-tab-header">961            <span class="code-tab-lang" id="code-tab-lang">—</span>962            <div class="code-tab-actions">963              <button class="code-tab-btn" id="btn-copy-code" onclick="copyCode()">📋 Copy</button>964              <a class="code-tab-btn" id="btn-download" href="#" style="display:none;">⬇ Download</a>965            </div>966          </div>967          <div id="code-display">968            <div class="code-placeholder">No code generated yet.</div>969          </div>970        </div>971      </div>972    </div>973  </div>974 975  <!-- Status Bar -->976  <div id="status-bar">977    <div class="status-indicator status-idle" id="status-indicator">978      <span class="status-dot">●</span>979      <span id="status-text">IDLE</span>980    </div>981  </div>982</div>983 984<!-- Fullscreen Overlay -->985<div id="fullscreen-overlay">986  <div id="fullscreen-bar">987    <span>WEB PREVIEW</span>988    <button id="btn-exit-fullscreen" onclick="closeFullscreen()">[✕ CLOSE]</button>989  </div>990  <iframe id="fullscreen-iframe" sandbox="allow-scripts"></iframe>991</div>992 993<script>994// ═══════════════════════════════════════════════════════995// CONFIG996// ═══════════════════════════════════════════════════════997const CONFIG = __RUNTIME_CONFIG__;998 999// ═══════════════════════════════════════════════════════1000// STATE1001// ═══════════════════════════════════════════════════════1002const state = {1003  history: [],1004  executionContext: {},1005  targetLanguage: 'Python',1006  isGenerating: false,1007  currentEventSource: null,1008  activeTab: 'preview',1009  lastExecution: null,1010  lastCode: '',1011  lastCodeLang: ''1012};1013 1014// ═══════════════════════════════════════════════════════1015// INITIALIZATION1016// ═══════════════════════════════════════════════════════1017document.addEventListener('DOMContentLoaded', () => {1018  // Apply config1019  document.title = CONFIG.app_title || 'North Mini Code 1.0';1020 1021  if (CONFIG.model_url) {1022    document.getElementById('model-pill').href = CONFIG.model_url;1023  }1024  if (CONFIG.model_id) {1025    document.getElementById('model-pill-text').textContent = CONFIG.model_id;1026  }1027  if (CONFIG.opencode_url) {1028    document.getElementById('opencode-pill').href = CONFIG.opencode_url;1029  }1030 1031  // Config warning1032  if (!CONFIG.api_key_configured) {1033    document.getElementById('config-warning').classList.add('visible');1034  }1035 1036  // Render examples1037  renderExamples();1038 1039  // Welcome message1040  addSystemMessage(`Welcome to ${CONFIG.app_title || 'North Mini Code 1.0'}. Type a coding question or select an example below to get started.`);1041 1042  // Input auto-resize & keybinding1043  const input = document.getElementById('chat-input');1044  input.addEventListener('input', autoResize);1045  input.addEventListener('keydown', (e) => {1046    if (e.key === 'Enter' && e.shiftKey) {1047      e.preventDefault();1048      handleSend();1049    }1050  });1051});1052 1053function autoResize() {1054  const el = document.getElementById('chat-input');1055  el.style.height = 'auto';1056  el.style.height = Math.min(el.scrollHeight, 120) + 'px';1057}1058 1059// ═══════════════════════════════════════════════════════1060// EXAMPLES1061// ═══════════════════════════════════════════════════════1062function renderExamples() {1063  const row = document.getElementById('examples-row');1064  if (!CONFIG.examples || CONFIG.examples.length === 0) {1065    row.style.display = 'none';1066    return;1067  }1068  row.innerHTML = '<span class="examples-label">Try:</span>';1069  CONFIG.examples.forEach((ex) => {1070    const chip = document.createElement('button');1071    chip.className = 'example-chip';1072    chip.textContent = ex.label;1073    chip.title = ex.prompt;1074    chip.addEventListener('click', () => {1075      if (ex.target) setTarget(ex.target);1076      sendMessage(ex.prompt);1077    });1078    row.appendChild(chip);1079  });1080}1081 1082// ═══════════════════════════════════════════════════════1083// TARGET LANGUAGE1084// ═══════════════════════════════════════════════════════1085function setTarget(target) {1086  state.targetLanguage = target;1087  document.querySelectorAll('.target-btn').forEach((btn) => {1088    const isActive = btn.dataset.target === target;1089    btn.classList.toggle('active', isActive);1090    btn.textContent = `[ ${btn.dataset.target} ${isActive ? '●' : '○'} ]`;1091  });1092}1093 1094// ═══════════════════════════════════════════════════════1095// CHAT MESSAGES1096// ═══════════════════════════════════════════════════════1097function addSystemMessage(text) {1098  const container = document.getElementById('chat-messages');1099  const div = document.createElement('div');1100  div.className = 'msg msg-system';1101  div.innerHTML = `<span class="msg-prefix">system&gt;</span><span class="msg-content">${escapeHtml(text)}</span>`;1102  container.appendChild(div);1103  scrollToBottom();1104}1105 1106function addUserMessage(text) {1107  const container = document.getElementById('chat-messages');1108  const div = document.createElement('div');1109  div.className = 'msg msg-user';1110  div.innerHTML = `<span class="msg-prefix">user&gt;</span><span class="msg-content">${escapeHtml(text)}</span>`;1111  container.appendChild(div);1112  scrollToBottom();1113}1114 1115function addAssistantMessage() {1116  const container = document.getElementById('chat-messages');1117  const div = document.createElement('div');1118  div.className = 'msg msg-assistant';1119  div.id = 'current-assistant-msg';1120  div.innerHTML = `<span class="msg-prefix">north&gt;</span><span class="msg-content streaming-cursor"></span>`;1121  container.appendChild(div);1122  scrollToBottom();1123  return div;1124}1125 1126function updateAssistantMessage(content, isStreaming) {1127  const div = document.getElementById('current-assistant-msg');1128  if (!div) return;1129  const contentEl = div.querySelector('.msg-content');1130  contentEl.innerHTML = parseMarkdown(content);1131  if (isStreaming) {1132    contentEl.classList.add('streaming-cursor');1133  } else {1134    contentEl.classList.remove('streaming-cursor');1135  }1136  scrollToBottom();1137}1138 1139function finalizeAssistantMessage() {1140  const div = document.getElementById('current-assistant-msg');1141  if (div) {1142    div.id = '';1143    const contentEl = div.querySelector('.msg-content');1144    if (contentEl) contentEl.classList.remove('streaming-cursor');1145  }1146}1147 1148function scrollToBottom() {1149  const container = document.getElementById('chat-messages');1150  requestAnimationFrame(() => {1151    container.scrollTop = container.scrollHeight;1152  });1153}1154 1155// ═══════════════════════════════════════════════════════1156// MARKDOWN PARSER1157// ═══════════════════════════════════════════════════════1158function parseMarkdown(text) {1159  if (!text) return '';1160 1161  // Handle think blocks1162  text = text.replace(/<think>([\s\S]*?)<\/think>/g, (_, content) => {1163    return `<details class="think-block"><summary>💭 Reasoning (click to expand)</summary><div class="think-content">${escapeHtml(content.trim())}</div></details>`;1164  });1165  // Handle unclosed think blocks (during streaming)1166  text = text.replace(/<think>([\s\S]*)$/g, (_, content) => {1167    return `<details class="think-block"><summary>💭 Reasoning (thinking…)</summary><div class="think-content">${escapeHtml(content.trim())}</div></details>`;1168  });1169 1170  // Extract code blocks first to prevent inner processing1171  const codeBlocks = [];1172  text = text.replace(/```(\w*)\n([\s\S]*?)```/g, (_, lang, code) => {1173    const idx = codeBlocks.length;1174    codeBlocks.push({ lang: lang || 'text', code: code.trimEnd() });1175    return `\x00CODEBLOCK_${idx}\x00`;1176  });1177 1178  // Escape HTML in remaining text1179  text = escapeHtml(text);1180 1181  // Restore code blocks with formatting1182  text = text.replace(/\x00CODEBLOCK_(\d+)\x00/g, (_, idx) => {1183    const block = codeBlocks[parseInt(idx)];1184    const escapedCode = escapeHtml(block.code);1185    const id = `code-${Date.now()}-${idx}`;1186    return `<div class="code-block-wrap"><div class="code-block-header"><span class="code-lang">${escapeHtml(block.lang)}</span><button class="btn-copy" onclick="copyBlock(this, '${id}')">📋 Copy</button></div><pre><code id="${id}">${escapedCode}</code></pre></div>`;1187  });1188 1189  // Inline formatting1190  text = text.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');1191  text = text.replace(/(?<!\*)\*([^*]+?)\*(?!\*)/g, '<em>$1</em>');1192  text = text.replace(/`([^`]+?)`/g, '<code>$1</code>');1193  text = text.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank" rel="noopener">$1</a>');1194 1195  // Headings1196  text = text.replace(/^### (.+)$/gm, '<h3>$1</h3>');1197  text = text.replace(/^## (.+)$/gm, '<h2>$1</h2>');1198  text = text.replace(/^# (.+)$/gm, '<h1>$1</h1>');1199 1200  // Lists - simple approach

Showing the first 1,200 of 1601 lines. Download the file for the rest.