From f9ffcc640d32280e142730fdbb0cfe196ce9b681 Mon Sep 17 00:00:00 2001 From: Emanuele Fenocchi Date: Wed, 1 Jul 2026 09:45:45 +0000 Subject: [PATCH 01/22] feat: add svg icon set for the web ui --- packages/web/src/icons.tsx | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 packages/web/src/icons.tsx diff --git a/packages/web/src/icons.tsx b/packages/web/src/icons.tsx new file mode 100644 index 0000000..14d37ff --- /dev/null +++ b/packages/web/src/icons.tsx @@ -0,0 +1,46 @@ +/** Minimal lucide-style stroke icons, 16px, inherit currentColor. */ +type P = { size?: number }; +const svg = (size: number, children: React.ReactNode) => ( + +); + +export const IconFiles = ({ size = 16 }: P) => + svg(size, <>); + +export const IconPreview = ({ size = 16 }: P) => + svg(size, <>); + +export const IconTerminal = ({ size = 16 }: P) => + svg(size, <>); + +export const IconModels = ({ size = 16 }: P) => + svg(size, <>); + +export const IconUsage = ({ size = 16 }: P) => + svg(size, <>); + +export const IconSecrets = ({ size = 16 }: P) => + svg(size, <>); + +export const IconPlus = ({ size = 16 }: P) => svg(size, <>); + +export const IconFolder = ({ size = 16 }: P) => + svg(size, <>); + +export const IconSend = ({ size = 16 }: P) => + svg(size, <>); + +export const IconChevronLeft = ({ size = 16 }: P) => svg(size, <>); +export const IconChevronRight = ({ size = 16 }: P) => svg(size, <>); From 1336171a952bd070a5a109b17f258ee25be2caaf Mon Sep 17 00:00:00 2001 From: Emanuele Fenocchi Date: Wed, 1 Jul 2026 09:45:45 +0000 Subject: [PATCH 02/22] feat: restyle web ui with a modern ide theme --- packages/web/index.html | 6 + packages/web/src/styles.css | 626 ++++++++++++++++++++++++++++-------- 2 files changed, 493 insertions(+), 139 deletions(-) diff --git a/packages/web/index.html b/packages/web/index.html index 9f9e5b3..075818f 100644 --- a/packages/web/index.html +++ b/packages/web/index.html @@ -4,6 +4,12 @@ OpenREPL + + +
diff --git a/packages/web/src/styles.css b/packages/web/src/styles.css index 5ff2e5f..a0303c7 100644 --- a/packages/web/src/styles.css +++ b/packages/web/src/styles.css @@ -1,13 +1,38 @@ :root { - --bg: #0d1117; - --panel: #161b22; - --border: #30363d; - --text: #c9d1d9; - --muted: #8b949e; - --accent: #58a6ff; - --ok: #3fb950; - --bad: #f85149; + /* Elevation layers — deep, warm near-black (modern AI-IDE) */ + --bg-0: #0c0c0d; /* app root / deepest */ + --bg-1: #131315; /* panels */ + --bg-2: #1a1a1d; /* cards, inputs, hover */ + --bg-3: #232327; /* active / selected */ + + --border: #26262b; + --border-strong: #34343a; + + --text: #ececed; + --text-dim: #9a9aa3; + --text-faint: #6a6a72; + + /* Coral-orange accent (OpenREPL identity, kin to Replit's) */ + --accent: #ff5c35; + --accent-hover: #ff7a58; + --accent-soft: rgba(255, 92, 53, 0.14); + --accent-fg: #1a0d08; + + --ok: #35c26a; + --bad: #ff5c5c; + --warn: #f0b429; + + --r-sm: 6px; + --r-md: 10px; + --r-lg: 14px; + + --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.4); + --shadow-2: 0 8px 28px rgba(0, 0, 0, 0.45); + + --font: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif; + --mono: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, monospace; } + * { box-sizing: border-box; } @@ -18,99 +43,185 @@ body, margin: 0; } body { - background: var(--bg); + background: var(--bg-0); color: var(--text); - font: 14px/1.5 ui-sans-serif, system-ui, -apple-system, sans-serif; + font: 14px/1.55 var(--font); + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; } code { - font-family: ui-monospace, SFMono-Regular, Menlo, monospace; + font-family: var(--mono); font-size: 0.85em; } .muted { - color: var(--muted); + color: var(--text-dim); +} +.small { + font-size: 11px; +} +::-webkit-scrollbar { + width: 10px; + height: 10px; } +::-webkit-scrollbar-thumb { + background: #2c2c31; + border: 2px solid transparent; + background-clip: padding-box; + border-radius: 8px; +} +::-webkit-scrollbar-thumb:hover { + background: #3a3a41; + background-clip: padding-box; +} + .app { display: flex; flex-direction: column; height: 100%; } + +/* ── topbar ─────────────────────────────────────────── */ .topbar { display: flex; align-items: center; gap: 12px; - padding: 8px 14px; + height: 48px; + padding: 0 14px; border-bottom: 1px solid var(--border); - background: var(--panel); + background: var(--bg-1); } .brand { + display: inline-flex; + align-items: center; + gap: 8px; font-weight: 700; - color: var(--accent); + letter-spacing: -0.01em; + color: var(--text); +} +.brand-mark { + display: grid; + place-items: center; + width: 24px; + height: 24px; + border-radius: 7px; + background: linear-gradient(135deg, var(--accent), #ff8a3d); + color: var(--accent-fg); + font-weight: 800; + font-size: 13px; + box-shadow: 0 2px 8px rgba(255, 92, 53, 0.35); +} +.project-pill { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 4px 10px; + border-radius: 999px; + background: var(--bg-2); + border: 1px solid var(--border); + color: var(--text-dim); + font-size: 12.5px; +} +.project-pill.none { + color: var(--text-faint); } .spacer { flex: 1; } .provider { - background: var(--bg); + background: var(--bg-2); color: var(--text); border: 1px solid var(--border); - border-radius: 6px; - padding: 4px 8px; + border-radius: var(--r-sm); + padding: 5px 10px; + font: inherit; + font-size: 12.5px; + cursor: pointer; +} +.provider:hover { + border-color: var(--border-strong); +} +.conn { + display: inline-flex; + align-items: center; + gap: 6px; + font-size: 12px; + color: var(--text-dim); } .dot { - width: 10px; - height: 10px; + width: 8px; + height: 8px; border-radius: 50%; } .dot.ok { background: var(--ok); + box-shadow: 0 0 0 3px rgba(53, 194, 106, 0.18); } .dot.bad { background: var(--bad); + box-shadow: 0 0 0 3px rgba(255, 92, 92, 0.18); } .notice { - background: #3d2c00; - color: #f0c000; - padding: 6px 14px; + background: rgba(240, 180, 41, 0.12); + color: var(--warn); + border-bottom: 1px solid rgba(240, 180, 41, 0.25); + padding: 7px 14px; font-size: 13px; } + +/* ── layout ─────────────────────────────────────────── */ .split { display: flex; flex: 1; min-height: 0; + gap: 10px; + padding: 10px; + background: var(--bg-0); } .left { width: 38%; - min-width: 320px; - border-right: 1px solid var(--border); + min-width: 340px; display: flex; flex-direction: column; min-height: 0; + background: var(--bg-1); + border: 1px solid var(--border); + border-radius: var(--r-lg); + overflow: hidden; } .right { flex: 1; display: flex; flex-direction: column; min-height: 0; + background: var(--bg-1); + border: 1px solid var(--border); + border-radius: var(--r-lg); + overflow: hidden; } -/* projects sidebar */ +/* ── projects sidebar ───────────────────────────────── */ .projects-rail { - width: 230px; - min-width: 230px; - border-right: 1px solid var(--border); - background: var(--panel); + width: 232px; + min-width: 232px; + background: var(--bg-1); + border: 1px solid var(--border); + border-radius: var(--r-lg); display: flex; flex-direction: column; min-height: 0; + overflow: hidden; } .projects-rail.collapsed { - width: 34px; - min-width: 34px; + width: 40px; + min-width: 40px; align-items: center; - padding-top: 10px; - gap: 8px; + padding-top: 12px; + gap: 10px; cursor: pointer; - color: var(--muted); + color: var(--text-dim); +} +.projects-rail.collapsed:hover { + color: var(--text); } .projects-rail.collapsed .rail-label { writing-mode: vertical-rl; @@ -121,66 +232,119 @@ code { display: flex; align-items: center; justify-content: space-between; - padding: 10px 12px; + padding: 12px 14px; border-bottom: 1px solid var(--border); + font-size: 12px; + text-transform: uppercase; + letter-spacing: 0.06em; + color: var(--text-dim); } .projects-list { list-style: none; margin: 0; - padding: 6px; + padding: 8px; flex: 1; overflow: auto; + display: flex; + flex-direction: column; + gap: 2px; } .project { - padding: 7px 9px; - border-radius: 6px; + position: relative; + display: flex; + align-items: center; + gap: 9px; + padding: 8px 10px; + border-radius: var(--r-md); cursor: pointer; + transition: background 0.12s; } .project:hover { - background: var(--bg); + background: var(--bg-2); } .project.active { - background: #1f6feb33; + background: var(--bg-3); +} +.project.active::before { + content: ''; + position: absolute; + left: 0; + top: 8px; + bottom: 8px; + width: 3px; + border-radius: 0 3px 3px 0; + background: var(--accent); +} +.project-icon { + flex: none; + color: var(--text-faint); + display: grid; + place-items: center; +} +.project.active .project-icon { + color: var(--accent); +} +.project-body { + min-width: 0; } .project-name { font-weight: 600; + font-size: 13px; } .project-path { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -.small { - font-size: 11px; -} .project-create { - padding: 8px; + padding: 10px; border-top: 1px solid var(--border); display: flex; flex-direction: column; - gap: 6px; + gap: 8px; } .project-create input { - background: var(--bg); + background: var(--bg-2); color: var(--text); border: 1px solid var(--border); - border-radius: 6px; - padding: 6px 8px; + border-radius: var(--r-sm); + padding: 7px 9px; + font: inherit; +} +.project-create input:focus { + outline: none; + border-color: var(--accent); } .project-create .row { display: flex; gap: 6px; } .new-project { - margin: 8px; + margin: 10px; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 7px; background: transparent; + color: var(--text-dim); + border: 1px dashed var(--border-strong); +} +.new-project:hover { color: var(--accent); - border: 1px dashed var(--border); + border-color: var(--accent); + background: var(--accent-soft); } button.ghost { background: transparent; - color: var(--muted); + color: var(--text-dim); border: none; + padding: 4px; + display: inline-grid; + place-items: center; +} +button.ghost:hover { + color: var(--text); + background: transparent; } .no-project { flex: 1; @@ -189,8 +353,13 @@ button.ghost { justify-content: center; text-align: center; } +.no-project h2 { + margin: 0 0 6px; + font-size: 20px; + letter-spacing: -0.01em; +} -/* chat */ +/* ── chat ───────────────────────────────────────────── */ .chat { display: flex; flex-direction: column; @@ -200,47 +369,115 @@ button.ghost { .messages { flex: 1; overflow-y: auto; - padding: 12px; + padding: 16px; + display: flex; + flex-direction: column; + gap: 6px; } .empty { - color: var(--muted); - padding: 20px; + color: var(--text-dim); + padding: 24px; text-align: center; } +.chat-empty { + margin: auto; + max-width: 340px; +} +.chat-empty h3 { + color: var(--text); + margin: 0 0 6px; + font-size: 16px; +} +.suggestions { + display: flex; + flex-direction: column; + gap: 8px; + margin-top: 16px; +} +.chip { + background: var(--bg-2); + border: 1px solid var(--border); + color: var(--text); + border-radius: var(--r-md); + padding: 9px 12px; + text-align: left; + font: inherit; + font-weight: 500; + cursor: pointer; + transition: all 0.12s; +} +.chip:hover { + border-color: var(--accent); + background: var(--accent-soft); +} +.chip code { + color: var(--accent); +} .msg { - margin-bottom: 14px; + display: flex; + gap: 10px; + padding: 6px 0; +} +.avatar { + flex: none; + width: 26px; + height: 26px; + border-radius: 7px; + display: grid; + place-items: center; + font-size: 11px; + font-weight: 700; +} +.msg.user .avatar { + background: var(--bg-3); + color: var(--text-dim); +} +.msg.assistant .avatar { + background: linear-gradient(135deg, var(--accent), #ff8a3d); + color: var(--accent-fg); +} +.msg-main { + min-width: 0; + flex: 1; } .msg .role { font-size: 11px; + font-weight: 600; text-transform: uppercase; - color: var(--muted); - margin-bottom: 2px; + letter-spacing: 0.04em; + color: var(--text-faint); + margin-bottom: 4px; } .msg.user .content { - background: #1f2937; - padding: 8px 10px; - border-radius: 8px; + background: var(--bg-2); + border: 1px solid var(--border); + padding: 9px 12px; + border-radius: var(--r-md); + display: inline-block; } .msg.assistant .content { white-space: pre-wrap; + line-height: 1.6; } .tool { display: flex; align-items: center; gap: 8px; font-size: 12px; - background: var(--panel); + background: var(--bg-2); border: 1px solid var(--border); - border-radius: 6px; - padding: 3px 8px; - margin: 3px 0; + border-radius: var(--r-sm); + padding: 4px 9px; + margin: 4px 0; } .toolname { color: var(--accent); + font-weight: 500; + white-space: nowrap; } .tool.delegate { - border-color: #3fb95066; - background: #102a17; + border-color: rgba(53, 194, 106, 0.4); + background: rgba(53, 194, 106, 0.08); } .tool.delegate .toolname { color: var(--ok); @@ -248,8 +485,10 @@ button.ghost { text-transform: capitalize; } .toolargs { - color: var(--muted); + color: var(--text-dim); overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .toolok { color: var(--ok); @@ -258,48 +497,97 @@ button.ghost { .composer { display: flex; gap: 8px; - padding: 10px; + align-items: flex-end; + padding: 12px; border-top: 1px solid var(--border); + background: var(--bg-1); +} +.composer-box { + flex: 1; + display: flex; + align-items: flex-end; + gap: 8px; + background: var(--bg-2); + border: 1px solid var(--border); + border-radius: var(--r-lg); + padding: 6px 6px 6px 12px; + transition: border-color 0.12s; +} +.composer-box:focus-within { + border-color: var(--accent); } .composer textarea { flex: 1; resize: none; - height: 56px; - background: var(--bg); + height: 44px; + max-height: 160px; + background: transparent; color: var(--text); - border: 1px solid var(--border); - border-radius: 8px; - padding: 8px; + border: none; + padding: 10px 0; + font: inherit; +} +.composer textarea:focus { + outline: none; } +.send-btn { + flex: none; + width: 34px; + height: 34px; + border-radius: 50%; + padding: 0; + display: grid; + place-items: center; +} + +/* ── buttons ────────────────────────────────────────── */ button { background: var(--accent); - color: #001; + color: var(--accent-fg); border: none; - border-radius: 6px; - padding: 6px 12px; + border-radius: var(--r-sm); + padding: 7px 13px; cursor: pointer; + font: inherit; font-weight: 600; + transition: background 0.12s, opacity 0.12s; } button:hover { - opacity: 0.9; + background: var(--accent-hover); +} +button:disabled { + opacity: 0.5; + cursor: default; } -/* tabs */ +/* ── tabs ───────────────────────────────────────────── */ .tabs { display: flex; - gap: 2px; + gap: 4px; + padding: 8px 10px; border-bottom: 1px solid var(--border); - background: var(--panel); + background: var(--bg-1); } .tabs button { + display: inline-flex; + align-items: center; + gap: 6px; background: transparent; - color: var(--muted); - border-radius: 0; + color: var(--text-dim); + border-radius: var(--r-sm); + padding: 6px 11px; font-weight: 500; } +.tabs button:hover { + background: var(--bg-2); + color: var(--text); +} .tabs button.active { color: var(--text); - border-bottom: 2px solid var(--accent); + background: var(--bg-3); +} +.tabs button.active svg { + color: var(--accent); } .tabbody { flex: 1; @@ -311,16 +599,17 @@ button:hover { inset: 0; } -/* files + editor */ +/* ── files + editor ─────────────────────────────────── */ .filesEditor { display: flex; height: 100%; } .tree { - width: 220px; + width: 224px; border-right: 1px solid var(--border); overflow: auto; - padding: 6px 0; + padding: 8px 6px; + background: var(--bg-1); } .treelist { list-style: none; @@ -328,15 +617,28 @@ button:hover { padding: 0; } .node { - padding: 2px 6px; + display: flex; + align-items: center; + gap: 6px; + padding: 4px 8px; + border-radius: var(--r-sm); cursor: pointer; white-space: nowrap; + color: var(--text-dim); + font-size: 13px; } .node:hover { - background: var(--panel); + background: var(--bg-2); + color: var(--text); } .node.sel { - background: #1f6feb33; + background: var(--accent-soft); + color: var(--text); +} +.node .tw { + color: var(--text-faint); + width: 12px; + display: inline-block; } .editor { flex: 1; @@ -345,42 +647,53 @@ button:hover { min-width: 0; } .filepath { - padding: 4px 10px; + padding: 8px 12px; border-bottom: 1px solid var(--border); - color: var(--muted); - font-family: ui-monospace, monospace; + color: var(--text-dim); + font-family: var(--mono); font-size: 12px; + background: var(--bg-1); } .editor .cm-editor { height: 100%; } -/* terminal */ +/* ── terminal ───────────────────────────────────────── */ .terminal { display: flex; flex-direction: column; height: 100%; + background: #0d1117; } .xterm-host { flex: 1; min-height: 0; - padding: 6px; + padding: 8px; } .cmdbar { border-top: 1px solid var(--border); - padding: 6px; + padding: 8px; + background: var(--bg-1); } .cmdbar input, .secret-add input { width: 100%; - background: var(--bg); + background: var(--bg-2); color: var(--text); border: 1px solid var(--border); - border-radius: 6px; - padding: 6px 8px; + border-radius: var(--r-sm); + padding: 8px 10px; + font: inherit; + font-family: var(--mono); + font-size: 12.5px; +} +.cmdbar input:focus, +.secret-add input:focus { + outline: none; + border-color: var(--accent); } -/* preview */ +/* ── preview ────────────────────────────────────────── */ .preview { display: flex; flex-direction: column; @@ -390,8 +703,9 @@ button:hover { display: flex; gap: 8px; align-items: center; - padding: 6px 10px; + padding: 8px 12px; border-bottom: 1px solid var(--border); + background: var(--bg-1); } .preview iframe { flex: 1; @@ -402,16 +716,20 @@ button:hover { background: var(--bad); color: #fff; } +.preview-bar button.stop:hover { + background: #ff7373; +} .preview-bar select { - background: var(--bg); + background: var(--bg-2); color: var(--text); border: 1px solid var(--border); - border-radius: 6px; - padding: 4px 8px; + border-radius: var(--r-sm); + padding: 6px 9px; + font: inherit; } .app-status { font-size: 12px; - color: var(--muted); + color: var(--text-dim); } .app-status.running { color: var(--ok); @@ -421,46 +739,54 @@ button:hover { } .app-status.installing, .app-status.starting { - color: #f0c000; + color: var(--warn); } .preview-empty { - padding: 30px; + padding: 40px; + line-height: 1.7; } -/* usage */ +/* ── usage ──────────────────────────────────────────── */ .usage { - padding: 14px; + padding: 16px; overflow: auto; height: 100%; } .usage-cards { display: grid; - grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 10px; } .card { - background: var(--panel); + background: var(--bg-2); border: 1px solid var(--border); - border-radius: 8px; - padding: 12px; + border-radius: var(--r-md); + padding: 14px; } .card-title { font-size: 12px; - color: var(--muted); + color: var(--text-dim); } .card-value { - font-size: 22px; + font-size: 24px; font-weight: 700; + letter-spacing: -0.01em; + margin: 2px 0; } .card-hint { font-size: 11px; - color: var(--muted); -} -.usage-chart { - margin-top: 18px; + color: var(--text-faint); } +.usage-chart, .breakdown { - margin-top: 18px; + margin-top: 20px; +} +.usage-chart h4, +.breakdown h4 { + margin: 0 0 10px; + font-size: 13px; + color: var(--text-dim); + font-weight: 600; } .breakdown table { width: 100%; @@ -470,16 +796,23 @@ button:hover { .breakdown th, .breakdown td { text-align: left; - padding: 5px 8px; + padding: 7px 10px; border-bottom: 1px solid var(--border); } +.breakdown th { + color: var(--text-faint); + font-weight: 600; + font-size: 11px; + text-transform: uppercase; + letter-spacing: 0.04em; +} .export { - margin-top: 16px; + margin-top: 18px; } -/* models */ +/* ── models ─────────────────────────────────────────── */ .models-pane { - padding: 14px; + padding: 16px; overflow: auto; height: 100%; } @@ -487,13 +820,17 @@ button:hover { display: flex; align-items: center; justify-content: space-between; - margin-bottom: 12px; + margin-bottom: 16px; } .multi-toggle { display: flex; align-items: center; gap: 8px; cursor: pointer; + font-weight: 500; +} +.multi-toggle input { + accent-color: var(--accent); } .model-rows { display: flex; @@ -502,9 +839,13 @@ button:hover { } .model-row { display: grid; - grid-template-columns: 200px 1fr auto; + grid-template-columns: 210px 1fr auto; align-items: center; gap: 12px; + padding: 10px 12px; + background: var(--bg-2); + border: 1px solid var(--border); + border-radius: var(--r-md); } .model-label { display: flex; @@ -514,50 +855,57 @@ button:hover { font-size: 11px; } .model-input { - background: var(--bg); + background: var(--bg-1); color: var(--text); border: 1px solid var(--border); - border-radius: 6px; - padding: 6px 8px; - font-family: ui-monospace, monospace; + border-radius: var(--r-sm); + padding: 8px 10px; + font-family: var(--mono); font-size: 12px; } +.model-input:focus { + outline: none; + border-color: var(--accent); +} .model-price { color: var(--ok); font-size: 12px; min-width: 90px; text-align: right; } -.small { - font-size: 12px; -} -/* secrets */ +/* ── secrets ────────────────────────────────────────── */ .secrets { - padding: 14px; + padding: 16px; } .secret-add { display: grid; grid-template-columns: 1fr 1fr auto; gap: 8px; - margin: 10px 0; + margin: 12px 0; } .secret-list { list-style: none; padding: 0; + margin: 0; } .secret-list li { display: flex; align-items: center; gap: 10px; - padding: 6px 0; + padding: 9px 2px; border-bottom: 1px solid var(--border); } .secret-list .masked { - color: var(--muted); + color: var(--text-faint); margin-left: auto; + letter-spacing: 2px; } .secret-list button { background: transparent; color: var(--bad); + padding: 4px 8px; +} +.secret-list button:hover { + background: rgba(255, 92, 92, 0.12); } From cc39c0469ac180c5025c8384aeaba4e2c45ce9b0 Mon Sep 17 00:00:00 2001 From: Emanuele Fenocchi Date: Wed, 1 Jul 2026 09:45:45 +0000 Subject: [PATCH 03/22] feat: refine app shell, chat and projects layout --- packages/web/src/App.tsx | 30 ++++++---- packages/web/src/panes/Chat.tsx | 76 +++++++++++++++++--------- packages/web/src/panes/FilesEditor.tsx | 2 +- packages/web/src/panes/Projects.tsx | 17 ++++-- 4 files changed, 82 insertions(+), 43 deletions(-) diff --git a/packages/web/src/App.tsx b/packages/web/src/App.tsx index 9d00722..068032e 100644 --- a/packages/web/src/App.tsx +++ b/packages/web/src/App.tsx @@ -8,16 +8,17 @@ import { Usage } from './panes/Usage.js'; import { Secrets } from './panes/Secrets.js'; import { Models } from './panes/Models.js'; import { ProjectsSidebar } from './panes/Projects.js'; +import { IconFiles, IconPreview, IconTerminal, IconModels, IconUsage, IconSecrets } from './icons.js'; type Tab = 'editor' | 'preview' | 'terminal' | 'models' | 'usage' | 'secrets'; -const TABS: { id: Tab; label: string }[] = [ - { id: 'editor', label: 'Files' }, - { id: 'preview', label: 'Preview' }, - { id: 'terminal', label: 'Terminal' }, - { id: 'models', label: 'Models' }, - { id: 'usage', label: 'Usage' }, - { id: 'secrets', label: 'Secrets' }, +const TABS: { id: Tab; label: string; icon: () => JSX.Element }[] = [ + { id: 'editor', label: 'Files', icon: IconFiles }, + { id: 'preview', label: 'Preview', icon: IconPreview }, + { id: 'terminal', label: 'Terminal', icon: IconTerminal }, + { id: 'models', label: 'Models', icon: IconModels }, + { id: 'usage', label: 'Usage', icon: IconUsage }, + { id: 'secrets', label: 'Secrets', icon: IconSecrets }, ]; export function App() { @@ -32,11 +33,19 @@ export function App() { return (
- OpenREPL - {activeProject ?? 'no project'} + + R + OpenREPL + + + {activeProject ? activeProject.split('/').pop() : 'no project'} + {activeProject && } - + + + {connected ? 'connected' : 'offline'} +
{notice &&
{notice}
}
@@ -50,6 +59,7 @@ export function App() {