Skip to content

Commit 5467997

Browse files
ndemiancclaude
andcommitted
redesign(ai): restyle the signed-in account card to the levelcode.ai classic look
The Manage-account popover referenced a specific model ("Plan: Max · Kimi K2.7 Code", and "unlock Kimi K2.7 Code" on the free CTA) — model churn that confused clients — and carried a verbose "Gateway mode: … proxied by the account server … levelcode.ai.providerMode" explainer that wasn't pulling its weight. Rebuilt to match the levelcode.ai "classic" (atom.io) aesthetic used across the site: - Fixed brand palette scoped to `.acctcard.classic` — One Dark by default, One Light under body.vscode-light (the convention the rest of this webview already uses). One violet accent (#7d6bff / #5b3fd6), hairline borders, 6px card / 4px controls, mono + tabular metadata. - Model-agnostic: the plan line becomes a mono `plan · Max` pill (BYOK: `your own key`); the free-tier CTA is just "Upgrade to Pro". No model name anywhere. - The gateway explainer is gone. Its space isn't refilled with credits (those live on /ai/account, one click away via Manage account) — the card now shows the email (mono) under the name and stays uncluttered. BYOK keeps a one-line "keys never leave your machine". - Sign out becomes a quiet accent link; removed the now-dead privacyNote(). Verified: chat.html scripts parse (0 errors); webviewCss + creditFormat suites green; no model refs / credits / privacyNote left in the card. (Design matches the approved mockup; a live webview render needs the VS Code host.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 6a379ef commit 5467997

1 file changed

Lines changed: 70 additions & 20 deletions

File tree

extensions/levelcode-ai/media/chat.html

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,58 @@
839839
.acctbody .link { color: var(--accent); cursor: pointer; text-decoration: none; }
840840
.acctbody .link:hover { text-decoration: underline; }
841841

842+
/* ── Signed-in account card — the levelcode.ai "classic" (atom.io) look. A FIXED brand palette (not the
843+
editor theme): One Dark by default, One Light under body.vscode-light — the same convention the rest of
844+
this webview uses. One violet accent, hairline borders, tiny radii (6px card / 4px controls), and mono +
845+
tabular-nums metadata (email · plan pill · synced) — the detail that sells the code-editor personality. */
846+
.acctcard.classic {
847+
--cc-bg: #282c34; --cc-surface: #21252b; --cc-text: #dcdfe4; --cc-text2: #abb2bf; --cc-text3: #828997;
848+
--cc-line: #3e4451; --cc-accent: #7d6bff;
849+
--cc-mono: var(--vscode-editor-font-family, ui-monospace, "SF Mono", Menlo, Consolas, monospace);
850+
max-width: 300px; padding: 24px 22px 20px; border-radius: 6px;
851+
background: var(--cc-surface); color: var(--cc-text); border: 1px solid var(--cc-line);
852+
box-shadow: 0 1px 2px rgba(0,0,0,.05);
853+
}
854+
body.vscode-light .acctcard.classic, body.vscode-high-contrast-light .acctcard.classic {
855+
--cc-bg: #ffffff; --cc-surface: #fafaf9; --cc-text: #333333; --cc-text2: #555555; --cc-text3: #777777;
856+
--cc-line: #e0e0e0; --cc-accent: #5b3fd6;
857+
}
858+
.acctcard.classic .ovclose { color: var(--cc-text3); }
859+
.acctcard.classic .ovclose:hover { color: var(--cc-text); background: color-mix(in srgb, var(--cc-text3) 18%, transparent); }
860+
.acctcard.classic .bigavatar {
861+
width: 56px; height: 56px; border-radius: 50%; margin: 2px auto 12px; display: grid; place-items: center;
862+
border: 1px solid var(--cc-line); background: var(--cc-bg); color: var(--cc-text);
863+
font-weight: 600; font-size: 18px; letter-spacing: .02em;
864+
}
865+
.acctcard.classic h2 { margin: 0; font-size: 20px; font-weight: 700; letter-spacing: -.01em; color: var(--cc-text); }
866+
.acctcard.classic .em { margin: 5px 0 0; font-family: var(--cc-mono); font-size: 12.5px; color: var(--cc-text3); }
867+
.acctcard.classic .planpill {
868+
display: inline-block; margin: 12px 0 2px; border: 1px solid var(--cc-line); background: var(--cc-bg);
869+
border-radius: 3px; padding: 4px 10px; font-family: var(--cc-mono); font-size: 12px; color: var(--cc-text2);
870+
}
871+
.acctcard.classic .abtn {
872+
display: block; width: 100%; box-sizing: border-box; margin: 16px 0 0; padding: 10px 14px; border-radius: 4px;
873+
border: 1px solid var(--cc-line); background: var(--cc-bg); color: var(--cc-text);
874+
font-size: 14px; font-weight: 500; cursor: pointer; transition: border-color .15s ease;
875+
}
876+
.acctcard.classic .abtn:hover { border-color: var(--cc-accent); }
877+
.acctcard.classic .abtn.primary { background: var(--cc-accent); color: #fff; border-color: transparent; }
878+
.acctcard.classic .abtn.primary:hover { filter: brightness(1.06); }
879+
.acctcard.classic .signout {
880+
display: inline-block; margin-top: 14px; padding: 2px 6px; border: none; background: transparent;
881+
color: var(--cc-accent); font: inherit; font-size: 13px; cursor: pointer; border-radius: 4px;
882+
}
883+
.acctcard.classic .signout:hover { text-decoration: underline; }
884+
.acctcard.classic .signout:focus-visible { outline: 2px solid var(--cc-accent); outline-offset: 2px; }
885+
.acctcard.classic .synced {
886+
margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--cc-line);
887+
font-family: var(--cc-mono); font-size: 11.5px; color: var(--cc-text3); line-height: 1.5;
888+
}
889+
.acctcard.classic .note {
890+
margin-top: 12px; font-family: var(--cc-mono); font-size: 11.5px; color: var(--cc-text3);
891+
line-height: 1.55; text-align: left;
892+
}
893+
842894
/* ── LevelCode sign-in modal — calm, soft, THEME-FOLLOWING (matches the Manage-account card) ────
843895
Scoped to .acctcard.lc-modal. Uses the editor theme tokens (--vscode-*, --border, --muted, --field-bg)
844896
so it adapts light/dark exactly like the signed-in card, with a gentle lavender (--accent) as the
@@ -2689,41 +2741,39 @@
26892741
if (acctLastFocus && acctLastFocus.focus) { try { acctLastFocus.focus(); } catch(e){} } // restore focus to the opener
26902742
acctLastFocus = null;
26912743
}
2692-
// Mode-aware privacy note: BYOK = keys never touch the cloud; gateway = metered plan through LevelCode.
2693-
function privacyNote(gateway){
2694-
return gateway
2695-
? '<div class="note priv">Gateway mode: AI runs through your <b>metered LevelCode plan</b> — no provider key needed. Requests are proxied by the account server. Switch to BYOK any time in settings (<code>levelcode.ai.providerMode</code>).</div>'
2696-
: '<div class="note priv">BYOK mode: the account only syncs settings/skills. AI requests stay <b>direct from your machine to your provider</b> — your keys never touch the cloud.</div>';
2697-
}
26982744
function renderAccount(state){
26992745
account = state || { signedIn: false };
27002746
const gateway = account.mode === 'gateway';
27012747
if (account.signedIn){
2702-
acctCard.classList.remove('lc-modal'); // signed-in keeps the plain themed card
2748+
acctCard.classList.remove('lc-modal');
2749+
acctCard.classList.add('classic'); // signed-in → the levelcode.ai "classic" (atom.io) look
27032750
acctAvatar.textContent = initials(account.name || account.email);
27042751
acctAvatar.classList.add('signed');
2705-
// Gateway: show the active plan (and credits when the server reports them). BYOK: plan is display-only.
27062752
const paidPlan = !!(account.plan && account.plan.trim().toLowerCase() !== 'free');
2707-
const planLine = gateway
2708-
? '<p class="meta">Plan: <b>' + esc(account.plan || 'Free') + '</b> · '
2709-
+ esc(paidPlan ? 'Kimi K2.7 Code' : 'gpt-oss-120b')
2710-
+ (account.credits != null ? ' · ' + esc(String(account.credits)) + ' credit' + (Number(account.credits) === 1 ? '' : 's') + ' left' : '')
2711-
+ '</p>'
2712-
: '<p class="meta">' + esc(account.email || '') + (account.plan ? ' · ' + esc(account.plan) : '') + '</p>';
2713-
// Free-tier Upgrade CTA (gateway only): unlock the flagship Kimi K2.7 Code.
2753+
// Model-agnostic: a mono pill, never a model name (it churns and confused clients), and no credits
2754+
// (that lives on /ai/account). "plan · Max" for gateway; "your own key" for BYOK.
2755+
const planPill = gateway
2756+
? '<span class="planpill">plan · ' + esc(account.plan || 'Free') + '</span>'
2757+
: '<span class="planpill">your own key' + (account.plan ? ' · ' + esc(account.plan) : '') + '</span>';
2758+
const emailLine = account.email ? '<p class="em">' + esc(account.email) + '</p>' : '';
27142759
const upgradeBtn = (gateway && !paidPlan)
2715-
? '<button class="abtn primary" data-act="upgrade">' + codicon('sparkle') + ' Upgrade to Pro — unlock Kimi K2.7 Code</button>'
2760+
? '<button class="abtn primary" data-act="upgrade">' + codicon('sparkle') + ' Upgrade to Pro</button>'
27162761
: '';
2762+
// Gateway needs no explainer (the "how the gateway works" blurb was removed). BYOK keeps a one-line
2763+
// privacy reassurance, which is genuinely useful there.
2764+
const note = gateway ? '' : '<div class="note">Your keys never leave your machine — requests go direct to your provider.</div>';
27172765
acctBody.innerHTML =
27182766
'<div class="bigavatar">' + esc(initials(account.name || account.email)) + '</div>'
27192767
+ '<h2 id="lcTitle">' + esc(account.name || 'Signed in') + '</h2>'
2720-
+ planLine
2768+
+ emailLine
2769+
+ planPill
27212770
+ upgradeBtn
27222771
+ '<button class="abtn" data-act="manage">Manage account</button>'
2723-
+ '<button class="abtn" data-act="signout">Sign out</button>'
2724-
+ '<div class="synced">' + codicon('check-circle') + ' Synced: settings · skills · keymaps</div>'
2725-
+ privacyNote(gateway);
2772+
+ '<button class="signout" data-act="signout">Sign out</button>'
2773+
+ '<div class="synced">Synced · settings · skills · keymaps</div>'
2774+
+ note;
27262775
} else {
2776+
acctCard.classList.remove('classic');
27272777
acctCard.classList.add('lc-modal'); // signed-out → the calm LevelCode sign-in modal
27282778
acctAvatar.innerHTML = PERSON_SVG;
27292779
acctAvatar.classList.remove('signed');

0 commit comments

Comments
 (0)