diff --git a/plugins/_discovery/extensions/python/banners/10_discovery_cards.py b/plugins/_discovery/extensions/python/banners/10_discovery_cards.py index bba6c1c85..460f52ee8 100644 --- a/plugins/_discovery/extensions/python/banners/10_discovery_cards.py +++ b/plugins/_discovery/extensions/python/banners/10_discovery_cards.py @@ -138,7 +138,7 @@ class DiscoveryCardsExtension(Extension): "type": "hero", "placement": "after-features", "title": "Your AI accounts", - "description": "Link account-backed providers such as ChatGPT/Codex, GitHub Copilot, Gemini API, and xAI Grok." + "description": "Use your subscription-backed logins for model access." if not connected_count else "", "cta_text": "Connect accounts" if not connected_count else "Manage accounts", diff --git a/plugins/_discovery/extensions/webui/onboarding-success-end/discovery-cards.html b/plugins/_discovery/extensions/webui/onboarding-success-end/discovery-cards.html index cf54f176b..c7ca47b30 100644 --- a/plugins/_discovery/extensions/webui/onboarding-success-end/discovery-cards.html +++ b/plugins/_discovery/extensions/webui/onboarding-success-end/discovery-cards.html @@ -276,8 +276,8 @@ .discovery-feature-thumb { flex: 0 0 auto; - width: 44px; - height: 44px; + width: 32px; + height: 32px; display: flex; align-items: center; justify-content: center; @@ -570,8 +570,8 @@ } .discovery-feature-thumb { - width: 46px; - height: 46px; + width: 32px; + height: 32px; } .discovery-feature-desc { diff --git a/plugins/_discovery/extensions/webui/welcome-actions-end/discovery-cards.html b/plugins/_discovery/extensions/webui/welcome-actions-end/discovery-cards.html index c0c9b6810..1d6ad7ca9 100644 --- a/plugins/_discovery/extensions/webui/welcome-actions-end/discovery-cards.html +++ b/plugins/_discovery/extensions/webui/welcome-actions-end/discovery-cards.html @@ -11,37 +11,35 @@
-

Connect Channels

-

Extend Agent Zero across your favorite platforms.

+
+

Connect Channels

+

Extend Agent Zero across your favorite platforms.

+
+
@@ -58,11 +56,16 @@
- key

+
@@ -95,12 +98,6 @@
- @@ -135,15 +132,23 @@ .discovery-features-panel { min-height: 100%; - padding: 1.7rem 1.55rem 1.55rem; + padding: 1.25rem 1.45rem; } .discovery-panel-header { display: grid; - gap: 0.42rem; + grid-template-columns: minmax(0, 1fr) auto; + gap: 0.7rem; + align-items: start; margin-bottom: 1.28rem; } + .discovery-panel-copy { + display: grid; + gap: 0.42rem; + min-width: 0; + } + .discovery-panel-header h2 { margin: 0; color: var(--color-text); @@ -162,31 +167,32 @@ .discovery-features { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 0.7rem; + gap: 0.65rem; } .discovery-feature-card { - position: relative; - display: flex; - flex-direction: column; - align-items: flex-start; - text-align: left; - } - - .discovery-feature-head { - display: flex; - flex-direction: row; + display: inline-flex; align-items: center; - gap: 0.75rem; - width: 100%; + gap: 0.5rem; min-width: 0; - margin-bottom: 1rem; + min-height: 3.1rem; + border: 1px solid color-mix(in srgb, var(--color-border) 52%, transparent); + border-radius: 8px; + padding: 0.56rem 0.58rem; + background: color-mix(in srgb, var(--color-background) 50%, transparent); + color: inherit; + cursor: pointer; + font-family: var(--font-family-main, "Rubik", Arial, Helvetica, sans-serif); + text-align: left; + transition: + border-color 0.18s ease, + background-color 0.18s ease; } .discovery-feature-thumb { flex: 0 0 auto; - width: 52px; - height: 52px; + width: 32px; + height: 32px; display: flex; align-items: center; justify-content: center; @@ -212,34 +218,15 @@ flex: 1 1 auto; min-width: 0; color: var(--color-text); - font-size: 0.96rem; + font-size: 0.84rem; font-weight: 520; line-height: 1.25; } - .discovery-feature-desc { - margin: 1.12rem 0 0; - padding-bottom: var(--spacing-md); - color: color-mix(in srgb, var(--color-text) 72%, transparent); - font-size: 0.86rem; - line-height: 1.48; - } - - .discovery-feature-card > .btn { - margin-top: auto; - min-width: 6.1rem; - min-height: 2.35rem; - border: 0; - border-radius: 8px; - color: #fff; - font-family: var(--font-family-main, "Rubik", Arial, Helvetica, sans-serif); - font-size: 0.88rem; - font-weight: 460; - } - - .discovery-feature-card > .btn:hover, - .discovery-feature-card > .btn:focus-visible { - filter: brightness(1.06); + .discovery-feature-card:hover, + .discovery-feature-card:focus-visible { + border-color: color-mix(in srgb, var(--color-border) 88%, var(--color-text) 12%); + background: color-mix(in srgb, var(--color-panel) 86%, var(--color-background) 14%); outline: none; } @@ -272,10 +259,12 @@ height: 26px; } - .discovery-feature-card:hover .discovery-dismiss, - .discovery-feature-card:focus-visible .discovery-dismiss, - .discovery-account-card:hover .discovery-dismiss, - .discovery-account-card:focus-within .discovery-dismiss { + .discovery-panel-dismiss { + position: static; + opacity: 0.68; + } + + .discovery-account-card > .discovery-dismiss { opacity: 0.68; } @@ -294,32 +283,19 @@ .discovery-account-card { position: relative; display: grid; - gap: 1.1rem; - padding: 1.35rem 1.45rem 1.4rem; + gap: 1rem; + padding: 1.25rem 1.45rem 1.25rem; } .discovery-account-header { display: grid; - grid-template-columns: auto minmax(0, 1fr); + grid-template-columns: minmax(0, 1fr) auto; gap: 0.95rem; align-items: center; min-width: 0; padding-right: 2.1rem; } - .discovery-account-icon { - display: inline-flex; - align-items: center; - justify-content: center; - width: 3rem; - height: 3rem; - border-radius: 10px; - color: #2f6bff; - background: color-mix(in srgb, var(--color-primary) 10%, transparent); - box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-primary) 12%, transparent); - font-size: 1.7rem; - } - .discovery-account-copy { display: grid; gap: 0.3rem; @@ -357,7 +333,7 @@ min-height: 2rem; padding: 0.32rem 0.58rem; border: 1px solid color-mix(in srgb, var(--color-border) 52%, transparent); - border-radius: 999px; + border-radius: 8px; background: color-mix(in srgb, var(--color-background) 50%, transparent); color: color-mix(in srgb, var(--color-text) 74%, transparent); font-size: 0.8rem; @@ -464,7 +440,7 @@ } .discovery-account-cta { - justify-self: start; + justify-self: end; display: inline-flex; align-items: center; justify-content: center; @@ -479,6 +455,7 @@ font-family: var(--font-family-main, "Rubik", Arial, Helvetica, sans-serif); font-size: 0.88rem; font-weight: 460; + white-space: nowrap; box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2); } @@ -536,33 +513,14 @@ } .discovery-feature-card { - display: grid; - grid-template-columns: minmax(0, 1fr) auto; - gap: 0.75rem; + display: inline-flex; min-height: 0; - align-items: center; - } - - .discovery-feature-head { - grid-column: 1; - min-width: 0; - margin-bottom: 0; + padding: 0.62rem 0.7rem; } .discovery-feature-thumb { - width: 46px; - height: 46px; - } - - .discovery-feature-desc { - display: none; - } - - .discovery-feature-card > .btn { - grid-column: 2; - grid-row: 1; - align-self: center; - margin-top: 0; + width: 32px; + height: 32px; } .discovery-account-usage-row { @@ -577,12 +535,7 @@ } .discovery-feature-card { - grid-template-columns: minmax(0, 1fr) auto; - padding-right: 3rem; - } - - .discovery-feature-card > .btn { - justify-self: end; + padding-right: 0.7rem; } .discovery-account-card { @@ -594,11 +547,11 @@ padding-right: 2.2rem; } - .discovery-account-icon { - width: 2.55rem; - height: 2.55rem; - font-size: 1.45rem; + .discovery-account-cta { + grid-column: 1 / -1; + justify-self: start; } + } diff --git a/plugins/_discovery/webui/discovery-store.js b/plugins/_discovery/webui/discovery-store.js index 8dbb52919..2feb1756f 100644 --- a/plugins/_discovery/webui/discovery-store.js +++ b/plugins/_discovery/webui/discovery-store.js @@ -64,6 +64,25 @@ const model = { this.hasDismissedCards = true; }, + dismissFeatureCards() { + const featureIds = this.featureCards + .filter((card) => card.dismissible !== false) + .map((card) => card.id) + .filter(Boolean); + + if (!featureIds.length) return; + + const dismissed = this._getDismissedIds(); + const dismissSet = new Set(featureIds); + for (const id of dismissSet) { + dismissed.add(id); + } + this._persistDismissedIds(dismissed); + + this.cards = this.cards.filter((card) => !dismissSet.has(card.id)); + this.hasDismissedCards = true; + }, + undismissCards() { localStorage.removeItem(STORAGE_KEY); this.refreshCards(); diff --git a/plugins/_model_config/extensions/python/banners/_20_missing_api_key.py b/plugins/_model_config/extensions/python/banners/_20_missing_api_key.py index c5722435c..1d58b3d8e 100644 --- a/plugins/_model_config/extensions/python/banners/_20_missing_api_key.py +++ b/plugins/_model_config/extensions/python/banners/_20_missing_api_key.py @@ -7,12 +7,8 @@ class MissingApiKeyCheck(Extension): """Check if API keys are configured for selected model providers.""" LOCAL_PROVIDERS = {"ollama", "lm_studio", "llama_cpp", "omlx", "vllm"} - CONFIGURE_MODEL_SETTINGS_LINK = ( - """
""" - """""" - """
""" - ) + ONBOARDING_MODAL_PATH = "/plugins/_onboarding/webui/onboarding.html" + ONBOARDING_CTA_TEXT = "Start Onboarding" async def execute(self, banners: list = [], frontend_context: dict = {}, **kwargs): cfg = plugins.get_plugin_config("_model_config") or {} @@ -25,11 +21,12 @@ class MissingApiKeyCheck(Extension): "priority": 100, "title": "Welcome to Agent Zero!", "html": f"""You're almost ready to chat. Please configure your models to continue.
- Insert your API key in the onboarding wizard. - {self.CONFIGURE_MODEL_SETTINGS_LINK}""", + Insert your API key in the onboarding wizard.""", + "cta_text": self.ONBOARDING_CTA_TEXT, + "cta_action": f"open-modal:{self.ONBOARDING_MODAL_PATH}", "dismissible": False, "source": "backend", - "auto_modal_path": "/plugins/_onboarding/webui/onboarding.html", + "auto_modal_path": self.ONBOARDING_MODAL_PATH, "auto_modal_reason": "missing-api-key", "auto_modal_priority": 100, "auto_modal_surfaces": ["welcome", "chat-created"], @@ -69,8 +66,9 @@ class MissingApiKeyCheck(Extension): "priority": 90, "title": "Missing API Key for model presets", "html": f"""No API key configured for preset models: {preset_list}.
- These presets will not work until you provide the required API keys.
- {self.CONFIGURE_MODEL_SETTINGS_LINK}""", + These presets will not work until you provide the required API keys.""", + "cta_text": self.ONBOARDING_CTA_TEXT, + "cta_action": f"open-modal:{self.ONBOARDING_MODAL_PATH}", "dismissible": True, "source": "backend" }) diff --git a/tests/test_model_config_api_keys.py b/tests/test_model_config_api_keys.py index 1153630fd..1b592c555 100644 --- a/tests/test_model_config_api_keys.py +++ b/tests/test_model_config_api_keys.py @@ -82,6 +82,9 @@ async def test_missing_api_key_banner_exposes_missing_providers(monkeypatch): ) row = next(b for b in banners if b.get("id") == "missing-api-key") assert row.get("missing_providers") == fake + assert row["cta_text"] == "Start Onboarding" + assert row["cta_action"] == "open-modal:/plugins/_onboarding/webui/onboarding.html" + assert "onboarding-banner-btn-container" not in row["html"] def test_model_config_frontend_tracks_inline_api_key_edits(): @@ -267,6 +270,8 @@ def test_missing_api_key_banner_includes_auto_modal_metadata(monkeypatch): assert row["type"] == "warning" assert row["dismissible"] is False assert row["missing_providers"] == fake + assert row["cta_text"] == "Start Onboarding" + assert row["cta_action"] == "open-modal:/plugins/_onboarding/webui/onboarding.html" def test_provider_key_modes_for_local_and_ollama_cloud(): diff --git a/tests/test_oauth_static.py b/tests/test_oauth_static.py index 4b7b165bd..419a93178 100644 --- a/tests/test_oauth_static.py +++ b/tests/test_oauth_static.py @@ -179,6 +179,8 @@ def test_oauth_discovery_card_renders_in_welcome_account_panel(): assert "discovery-oauth-accounts" in discovery_cards assert "Your AI accounts" in discovery_cards + assert "Use your subscription-backed logins for model access." in discovery_cards + assert "Link account-backed providers such as" not in discovery_cards assert "Connected OAuth accounts" not in discovery_cards assert "discovery-codex-oauth" not in discovery_cards assert "5h and weekly limits are ready." not in discovery_cards @@ -188,6 +190,9 @@ def test_oauth_discovery_card_renders_in_welcome_account_panel(): assert "account_chips" in discovery_cards assert "discovery-account-card" in welcome_cards assert "discovery-account-chip" in welcome_cards + assert "discovery-account-icon" not in welcome_cards + assert ".discovery-account-chip {\n display: inline-grid;" in welcome_cards + assert " border-radius: 8px;" in welcome_cards assert "discovery-account-usage" in welcome_cards assert "formatRemainingPercent(window)" in welcome_cards assert "formatRemainingPercent(window)" in discovery_store diff --git a/tests/test_welcome_composer_static.py b/tests/test_welcome_composer_static.py index 11ab62311..0738fb8a9 100644 --- a/tests/test_welcome_composer_static.py +++ b/tests/test_welcome_composer_static.py @@ -10,17 +10,70 @@ def _read(relative_path: str) -> str: def test_welcome_screen_embeds_shared_new_chat_composer() -> None: welcome = _read("webui/components/welcome/welcome-screen.html") + welcome_store = _read("webui/components/welcome/welcome-store.js") index = _read("webui/index.html") discovery_cards = _read( "plugins/_discovery/extensions/webui/welcome-actions-end/discovery-cards.html" ) + discovery_store = _read("plugins/_discovery/webui/discovery-store.js") assert 'class="welcome-composer"' in welcome assert 'path="chat/attachments/inputPreview.html"' in welcome assert 'path="chat/input/chat-bar-input.html"' in welcome + assert "x-text=\"$store.welcomeStore.heroSubtitle\"" in welcome + assert "Hello! I'm Agent Zero" in welcome + assert "'is-setup-required': $store.welcomeStore.hasBlockingSetupBanner" in welcome + assert 'class="welcome-setup-composer"' in welcome + assert "Configure your models to start chatting" in welcome + assert "Start Onboarding" in welcome + assert "openBlockingSetup()" in welcome + assert '.filter((b) => b.id !== "missing-api-key")' in welcome_store + assert "get blockingSetupBanner()" in welcome_store + assert "get heroSubtitle()" in welcome_store + assert 'return "One setup step before chatting.";' in welcome_store + assert 'return "How can I help you today?";' in welcome_store + assert "openBlockingSetup()" in welcome_store assert '

Quick Actions

' in welcome assert 'class="welcome-lower-grid"' in welcome assert 'x-extension id="welcome-actions-end"' in welcome + assert "grid-template-columns: repeat(4, minmax(0, 1fr));" in welcome + assert '"accounts accounts channels channels"' in welcome + assert '"system system system system"' in welcome + assert "align-items: stretch;" in welcome + assert ".welcome-lower-grid .discovery-slot {\n display: contents;" in welcome + assert ".welcome-lower-grid .discovery-account-card {\n grid-area: accounts;" in welcome + assert "grid-area: system;" in welcome + assert ".welcome-composer .input-row {\n min-height: 4.9rem;" in welcome + assert "border-radius: 8px;" in welcome + assert 'aria-label="Refresh System Resources"' in welcome + assert "refreshBanners(true)" in welcome + assert 'aria-label="Dismiss System Resources"' in welcome + assert "dismissBanner($store.welcomeStore.systemResourceBanner?.id || 'system-resources')" in welcome + assert "welcome-panel-status-icon" not in welcome + assert "monitoring" not in welcome + assert ".welcome-banner {\n --welcome-banner-accent: #2f6bff;" in welcome + assert "grid-template-columns: auto minmax(0, 1fr) auto auto;" in welcome + assert ".welcome-banner.banner-warning {\n --welcome-banner-accent: #f59e0b;" in welcome + assert "border-left: 4px" not in welcome + assert 'class="welcome-banner-cta"' in welcome + assert "executeBannerAction(banner.cta_action)" in welcome + assert "executeBannerAction(action)" in welcome_store + assert 'action.startsWith("open-modal:")' in welcome_store + assert ".welcome-banner-html .onboarding-banner-btn-container" in welcome + assert "justify-content: flex-end;" in welcome + assert "justify-content: flex-start;" in welcome + assert ".welcome-banner-html .btn,\n .welcome-banner-html button" in welcome + assert "background-color: #4248f1;" in welcome + assert 'aria-label="Dismiss Connect Channels"' in discovery_cards + assert "dismissFeatureCards()" in discovery_cards + assert "dismissFeatureCards() {" in discovery_store + assert 'class="discovery-feature-card"\n type="button"' in discovery_cards + assert "`${card.cta_text || 'Connect'} ${card.title}`" in discovery_cards + assert "discovery-feature-card > .btn" not in discovery_cards + assert "discovery-feature-head" not in discovery_cards + assert "discovery-account-header" in discovery_cards + assert "discovery-account-cta" in discovery_cards + assert "discovery-account-icon" not in discovery_cards assert "x-if=\"$store.welcomeStore && $store.welcomeStore.isVisible\"" in index assert "x-if=\"!$store.welcomeStore || !$store.welcomeStore.isVisible\"" in index diff --git a/webui/components/welcome/welcome-screen.html b/webui/components/welcome/welcome-screen.html index d27472373..15a29fc29 100644 --- a/webui/components/welcome/welcome-screen.html +++ b/webui/components/welcome/welcome-screen.html @@ -15,11 +15,31 @@
-

Welcome back

-

Agent Zero is ready to help.

+

Hello! I'm Agent Zero

+

-
+
+
@@ -37,6 +57,14 @@
+ + +
@@ -189,6 +234,7 @@ gap: 1.55rem; width: min(100%, 1220px); margin: 0 auto; + padding-top: 4rem; } .welcome-hero h1 { @@ -217,10 +263,110 @@ display: contents; } + .welcome-composer.is-setup-required > x-component { + display: none; + } + + .welcome-setup-composer { + display: grid; + grid-template-columns: auto minmax(0, 1fr) auto; + align-items: center; + gap: 1rem; + width: 100%; + min-height: 4.9rem; + padding: 0.74rem 0.7rem 0.74rem 0.86rem; + border: 1px solid color-mix(in srgb, var(--color-border) 72%, transparent); + border-radius: 8px; + background: color-mix(in srgb, var(--color-panel) 64%, var(--color-background) 36%); + color: inherit; + cursor: pointer; + font-family: var(--font-family-main, "Rubik", Arial, Helvetica, sans-serif); + text-align: left; + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.035), + 0 18px 46px rgba(0, 0, 0, 0.18); + transition: + border-color 0.18s ease, + background-color 0.18s ease, + box-shadow 0.18s ease; + } + + .welcome-setup-composer:hover, + .welcome-setup-composer:focus-visible { + border-color: color-mix(in srgb, var(--color-border) 88%, var(--color-text) 12%); + background: color-mix(in srgb, var(--color-panel) 74%, var(--color-background) 26%); + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.045), + 0 22px 54px rgba(0, 0, 0, 0.22); + outline: none; + } + + .welcome-setup-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 2.5rem; + height: 2.5rem; + border-radius: 8px; + color: #f59e0b; + background: color-mix(in srgb, #f59e0b 9%, transparent); + box-shadow: inset 0 0 0 1px color-mix(in srgb, #f59e0b 12%, transparent); + } + + .welcome-setup-icon .material-symbols-outlined { + font-size: 1.35rem; + } + + .welcome-setup-copy { + display: grid; + gap: 0.18rem; + min-width: 0; + } + + .welcome-setup-title { + color: var(--color-text); + font-size: 1rem; + font-weight: 520; + line-height: 1.25; + } + + .welcome-setup-detail { + color: color-mix(in srgb, var(--color-text) 58%, transparent); + font-size: 0.92rem; + line-height: 1.35; + } + + .welcome-setup-cta { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.36rem; + min-height: 2.75rem; + border-radius: 12px; + padding: 0.62rem 0.95rem; + background-color: #4248f1; + color: #fff; + font-size: 0.92rem; + font-weight: 500; + line-height: 1; + white-space: nowrap; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2); + transition: background-color 0.18s ease; + } + + .welcome-setup-composer:hover .welcome-setup-cta, + .welcome-setup-composer:focus-visible .welcome-setup-cta { + background-color: #353bc5; + } + + .welcome-setup-cta .material-symbols-outlined { + font-size: 1.24rem; + } + .welcome-composer .input-row { min-height: 4.9rem; padding: 0.58rem 0.7rem 0.58rem 0.86rem; - border-radius: 16px; + border-radius: 8px; background: color-mix(in srgb, var(--color-panel) 64%, var(--color-background) 36%); } @@ -261,64 +407,64 @@ } .welcome-banner { + --welcome-banner-accent: #2f6bff; position: relative; - display: flex; - align-items: flex-start; - gap: 0.78rem; - padding: 0.9rem 1rem; - border-radius: 12px; + display: grid; + grid-template-columns: auto minmax(0, 1fr) auto auto; + align-items: start; + gap: 1rem; + min-height: 5.45rem; + padding: 1rem 1.1rem; + border-radius: 8px; text-align: left; } .welcome-banner.banner-info { - border-left: 4px solid #2f6bff; + --welcome-banner-accent: #2f6bff; } .welcome-banner.banner-warning { - border-left: 4px solid #f59e0b; + --welcome-banner-accent: #f59e0b; } .welcome-banner.banner-error { - border-left: 4px solid #ef4444; + --welcome-banner-accent: #ef4444; } .welcome-banner-icon { - display: flex; - width: 1.6rem; - height: 1.6rem; + display: inline-flex; + width: 2.25rem; + height: 2.25rem; align-items: center; justify-content: center; - color: #2f6bff; - } - - .banner-warning .welcome-banner-icon { - color: #f59e0b; - } - - .banner-error .welcome-banner-icon { - color: #ef4444; + border-radius: 8px; + color: var(--welcome-banner-accent); + background: color-mix(in srgb, var(--welcome-banner-accent) 9%, transparent); + box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--welcome-banner-accent) 12%, transparent); } .welcome-banner-icon .material-symbols-outlined { - font-size: 1.25rem; + font-size: 1.28rem; } .welcome-banner-content { flex: 1; min-width: 0; + padding-top: 0.05rem; } .welcome-banner-title { - margin-bottom: 0.25rem; + margin-bottom: 0.28rem; color: var(--color-text); - font-size: 0.92rem; - font-weight: 650; + font-size: 1rem; + font-weight: 560; line-height: 1.25; } .welcome-banner-html { - color: color-mix(in srgb, var(--color-text) 68%, transparent); - font-size: 0.84rem; + max-width: 72ch; + color: color-mix(in srgb, var(--color-text) 58%, transparent); + font-size: 0.92rem; line-height: 1.45; } @@ -331,6 +477,55 @@ text-decoration: underline; } + .welcome-banner-html .onboarding-banner-btn-container { + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + gap: 0.55rem; + margin-top: 0.9rem !important; + } + + .welcome-banner-cta, + .welcome-banner-html .btn, + .welcome-banner-html button { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 2.35rem; + border: 0; + border-radius: 8px; + padding: 0.55rem 0.9rem; + background-color: #4248f1; + color: #fff; + font-family: var(--font-family-main, "Rubik", Arial, Helvetica, sans-serif); + font-size: 0.88rem; + font-weight: 460; + line-height: 1.2; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2); + transition: background-color 0.18s ease; + } + + .welcome-banner-cta { + align-self: center; + justify-self: end; + gap: 0.36rem; + white-space: nowrap; + } + + .welcome-banner-cta .material-symbols-outlined { + font-size: 1.05rem; + } + + .welcome-banner-cta:hover, + .welcome-banner-cta:focus-visible, + .welcome-banner-html .btn:hover, + .welcome-banner-html .btn:focus-visible, + .welcome-banner-html button:hover, + .welcome-banner-html button:focus-visible { + background-color: #353bc5; + outline: none; + } + .welcome-banner-dismiss, .welcome-undismiss-button { display: inline-flex; @@ -348,6 +543,7 @@ width: 2rem; height: 2rem; border-radius: 8px; + margin: -0.2rem -0.2rem 0 0; } .welcome-banner-dismiss:hover, @@ -451,18 +647,33 @@ .welcome-lower-grid { display: grid; - grid-template-columns: minmax(0, 1.06fr) minmax(320px, 0.94fr); + grid-template-columns: repeat(4, minmax(0, 1fr)); + grid-template-areas: + "accounts accounts channels channels" + "system system system system"; gap: 1rem; align-items: stretch; } .welcome-lower-grid .discovery-slot { - grid-column: auto; - min-width: 0; - width: 100%; + display: contents; + } + + .welcome-lower-grid .discovery-features-panel { + grid-area: channels; + min-height: 0; + } + + .welcome-lower-grid .discovery-account-card { + grid-area: accounts; + } + + .welcome-lower-grid .discovery-undismiss { + grid-column: 1 / -1; } .welcome-system-card { + grid-area: system; min-width: 0; border-radius: 8px; padding: 1.6rem 1.7rem; @@ -477,10 +688,41 @@ margin-bottom: 1.5rem; } - .welcome-panel-header .material-symbols-outlined { + .welcome-panel-actions { + display: flex; + align-items: center; + gap: 0.35rem; + flex: 0 0 auto; + } + + .welcome-panel-icon-button { + display: inline-flex; + align-items: center; + justify-content: center; + width: 2rem; + height: 2rem; + border: 0; + border-radius: 8px; + background: transparent; + color: color-mix(in srgb, var(--color-text) 64%, transparent); + cursor: pointer; + font-family: var(--font-family-main, "Rubik", Arial, Helvetica, sans-serif); + } + + .welcome-panel-icon-button:hover, + .welcome-panel-icon-button:focus-visible { color: var(--color-text); - font-size: 1.35rem; - opacity: 0.86; + background: color-mix(in srgb, var(--color-border) 45%, transparent); + outline: none; + } + + .welcome-panel-icon-button:disabled { + cursor: default; + opacity: 0.45; + } + + .welcome-panel-icon-button .material-symbols-outlined { + font-size: 1.18rem; } .system-resource-body { @@ -560,6 +802,14 @@ .welcome-lower-grid { grid-template-columns: 1fr; + grid-template-areas: + "accounts" + "channels" + "system"; + } + + .welcome-shell { + padding-top: 4rem; } } @@ -571,6 +821,7 @@ .welcome-shell { gap: 1.2rem; + padding-top: 4rem; } .welcome-actions { @@ -593,6 +844,54 @@ min-height: 4.35rem; } + .welcome-setup-composer { + grid-template-columns: auto minmax(0, 1fr); + align-items: start; + gap: 0.8rem; + min-height: 4.35rem; + padding: 0.8rem; + } + + .welcome-setup-cta { + grid-column: 2; + justify-self: start; + min-height: 2.45rem; + border-radius: 8px; + padding: 0.55rem 0.85rem; + } + + .welcome-banner { + grid-template-columns: auto minmax(0, 1fr); + gap: 0.82rem; + padding: 0.95rem; + } + + .welcome-banner-dismiss { + position: absolute; + top: 0.7rem; + right: 0.7rem; + margin: 0; + } + + .welcome-banner-content { + padding-right: 1.9rem; + } + + .welcome-banner-html { + max-width: none; + } + + .welcome-banner-html .onboarding-banner-btn-container { + justify-content: flex-start; + margin-top: 0.75rem !important; + } + + .welcome-banner-cta { + grid-column: 2; + justify-self: start; + margin-top: 0.25rem; + } + .welcome-system-card { padding: 1.15rem; } diff --git a/webui/components/welcome/welcome-store.js b/webui/components/welcome/welcome-store.js index 521b94dbf..eeb41e25b 100644 --- a/webui/components/welcome/welcome-store.js +++ b/webui/components/welcome/welcome-store.js @@ -143,6 +143,7 @@ const model = { get sortedBanners() { return [...this.banners] .filter((b) => b.id !== "system-resources") + .filter((b) => b.id !== "missing-api-key") .filter((b) => b.type !== "hero" && b.type !== "feature") .sort((a, b) => (b.priority || 0) - (a.priority || 0)); }, @@ -151,6 +152,43 @@ const model = { return this.banners.find((b) => b.id === "system-resources") || null; }, + get blockingSetupBanner() { + return this.banners.find((b) => b.id === "missing-api-key") || null; + }, + + get hasBlockingSetupBanner() { + return Boolean(this.blockingSetupBanner); + }, + + get heroSubtitle() { + if (this.hasBlockingSetupBanner) { + return "One setup step before chatting."; + } + return "How can I help you today?"; + }, + + openBlockingSetup() { + const path = + this.blockingSetupBanner?.auto_modal_path || + "/plugins/_onboarding/webui/onboarding.html"; + window.openModal(path); + }, + + executeBannerAction(action) { + if (!action) return; + + if (action.startsWith("open-modal:")) { + const path = action.slice("open-modal:".length); + if (path) window.openModal(path); + return; + } + + if (action.startsWith("open-url:")) { + const url = action.slice("open-url:".length); + if (url) window.open(url, "_blank", "noopener,noreferrer"); + } + }, + /** * Dismiss a banner by ID. *