From 7e7969b5682e9241a8f38f6e01c28a308fa5f17b Mon Sep 17 00:00:00 2001 From: Martin Dvorak Date: Wed, 14 Oct 2026 08:51:14 +0000 Subject: [PATCH] Aero chat welcome panel: frosted and flush; honest model availability The welcome panel is the same frosted glass as the cards now (blurred, not a flat tint) and stretches flush with the chat header and composer (measured: 268..1280 at 1280, exactly the chrome's edges) - a flat pane floating 40px inside the scene read as "cut off next to the sidebar". Availability no longer over-promises: a /api/tags listing proves availability only on a local daemon (the listing is the installed set); on a cloud key the catalogue can include models a free plan cannot run, and provider seeds before their first live /models test, so those stay badge-less until actually used. The configured favourites keep their verified state. Contrast 0 findings, chat 102/102, providers 20/20, mobile 126/126, i18n 13/13, native 33/33. Version 0.5.2, SW -> freezmo-v75. --- app/api/health/route.ts | 9 ++++++++- app/globals.css | 14 ++++++++++++-- components/chat/ChatScreen.tsx | 5 ++++- package.json | 2 +- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/app/api/health/route.ts b/app/api/health/route.ts index ba2db4c..1ebef2f 100644 --- a/app/api/health/route.ts +++ b/app/api/health/route.ts @@ -153,7 +153,14 @@ export async function GET(request: Request) { if (known.has(canonical)) continue; if (/embed|bert|whisper|clip|rerank/i.test(model.name)) continue; known.add(canonical); - extras.push({ name: model.name, badge: badgeFor(model.name), available: true }); + // A local daemon's listing *is* its installed set, so "available" is a + // fact there. The cloud's /api/tags is a catalogue — a free key can list + // models its plan cannot run — so those stay "unknown" until used. + extras.push({ + name: model.name, + badge: badgeFor(model.name), + available: health.mode === "local-daemon" ? true : null, + }); } extras.sort((a, b) => a.name.localeCompare(b.name)); health.chatModels = [...health.chatModels, ...extras.slice(0, 120)]; diff --git a/app/globals.css b/app/globals.css index 8d8ff9c..421124f 100644 --- a/app/globals.css +++ b/app/globals.css @@ -442,6 +442,7 @@ .aero .glass-pill, .aero .btn-secondary, .aero .chat-header, +.aero .chat-empty, .aero .segmented, /* Hand-rolled frost fills in the study, exam, chat and homework flows: white/xx utilities and the surface tokens — without this they render as @@ -621,6 +622,7 @@ .aero .glass-pill, .aero .btn-secondary, .aero .chat-header, + .aero .chat-empty, .aero .segmented { background-image: none; background-color: rgb(255 255 255 / 0.32); @@ -664,14 +666,22 @@ box-shadow: 0 -16px 36px -26px rgb(2 62 110 / 0.5); } -/* The chat welcome (subtitle + suggestions) gets a soft panel, so clouds and - bubbles never sit right behind the text. */ +/* The chat welcome (subtitle + suggestions): the same frosted glass as the + cards (the shared recipe above), stretched flush with the header and the + composer — a panel floating 40px inside the scene looked cut off. */ .aero .chat-empty { + margin-inline: -1rem; border-radius: 1.5rem; border: 1px solid rgb(255 255 255 / 0.5); background-color: rgb(255 255 255 / 0.32); padding: 1.35rem 1rem 1.1rem; } +@media (min-width: 1024px) { + .aero .chat-empty { + margin-inline: -2.5rem; + padding: 1.5rem 2.5rem 1.25rem; + } +} /* Page headings that sit straight on the wallpaper. */ .aero .page-heading { diff --git a/components/chat/ChatScreen.tsx b/components/chat/ChatScreen.tsx index fe75907..8feaec1 100644 --- a/components/chat/ChatScreen.tsx +++ b/components/chat/ChatScreen.tsx @@ -179,8 +179,11 @@ export function ChatScreen() { if (!providerState.keys[info.id]) continue; const models = modelsFor(providerState, info.id).slice(0, 400); if (models.length === 0) continue; + // Only a live /models listing proves the key can use them; the built-in + // seeds stay badge-less until the first successful test. + const listed = (providerState.models[info.id]?.length ?? 0) > 0; for (const name of models) { - cloud.push({ name, badge: "text", available: true, provider: info.id }); + cloud.push({ name, badge: "text", available: listed ? true : null, provider: info.id }); } } return [...ollama, ...cloud]; diff --git a/package.json b/package.json index 67d7f3c..f4c1439 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "freezmo", - "version": "0.5.0", + "version": "0.5.2", "private": true, "license": "GPL-3.0-only", "scripts": {