From 900c0b90609d79a6d8c07030b9195b84ef3b4307 Mon Sep 17 00:00:00 2001 From: Dorian Date: Thu, 30 Jul 2026 18:17:32 -0400 Subject: [PATCH] feat(app): honor Archipelago D-14 embed defaults via query params MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Archipelago's Chat tab (neode-ui) embeds AIUI in an iframe and now passes two presentation-only query params on the embed URL: - ?chatExpanded — chat starts in the full message list rather than the collapsed prompt-index. chatCollapsed's initial ref now checks for this param before falling back to the existing localStorage default; never written back to localStorage, so the standalone app's own persisted preference is untouched. - ?mobileChat — on mobile, ChatPage opens on the chat tab rather than whatever tab survived from a prior mount of the module-singleton content-panel state. mobileTab already defaulted to 'chat'; this just re-asserts it once on mount when the param is present, so it doesn't interfere with the hasDetailOpen/panelOpen watchers driving normal tab switching in response to user taps afterward. Both params are read directly from window.location.search and are no-ops when absent, so the standalone (non-embedded) app and its existing desktop layout are unaffected. Co-Authored-By: Claude Fable 5 --- packages/app/src/pages/ChatPage.vue | 14 ++++++++++++++ packages/app/src/stores/chat.ts | 11 ++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/app/src/pages/ChatPage.vue b/packages/app/src/pages/ChatPage.vue index 11b5185a..52581cc6 100644 --- a/packages/app/src/pages/ChatPage.vue +++ b/packages/app/src/pages/ChatPage.vue @@ -477,9 +477,23 @@ function onKeydown(e: KeyboardEvent) { } } +// D-14b (Archipelago phase 02-ui-performance): when the host explicitly asks +// for a chat-first mobile start via ?mobileChat, force the initial mobile tab +// to 'chat' on mount. mobileTab already defaults to 'chat', but ChatPage can +// remount while content/detail selection state (module-singleton refs in +// useContentPanel) survives from a previous mount within the same AIUI +// session — this guarantees the documented default regardless of that carry- +// over. It only runs once, at mount, so it never interferes with the +// hasDetailOpen/panelOpen watchers below responding to real user taps after +// the initial paint. +const startOnMobileChat = new URLSearchParams(window.location.search).has('mobileChat') + onMounted(() => { window.addEventListener('resize', onResize) window.addEventListener('keydown', onKeydown) + if (startOnMobileChat && isMobile.value) { + mobileTab.value = 'chat' + } }) onUnmounted(() => { window.removeEventListener('resize', onResize) diff --git a/packages/app/src/stores/chat.ts b/packages/app/src/stores/chat.ts index 434e3875..806a8a49 100644 --- a/packages/app/src/stores/chat.ts +++ b/packages/app/src/stores/chat.ts @@ -129,7 +129,16 @@ export const useChatStore = defineStore('chat', () => { const panelSide = ref<'left' | 'right'>(savedSide ?? 'left') const webSearchEnabled = ref(localStorage.getItem('aiui-web-search') !== 'false') - const chatCollapsed = ref(localStorage.getItem('aiui-chat-collapsed') !== 'false') + + // D-14a (Archipelago phase 02-ui-performance): when the host explicitly asks + // for an expanded start via ?chatExpanded, open in the full message list + // rather than the collapsed prompt-index — this is a presentation-only, + // one-time initial-state override and is never written back to + // localStorage, so it can never change the standalone (non-embedded) app's + // own persisted default. A user who manually collapses while embedded still + // gets that choice persisted for next time, same as before this change. + const _startExpanded = new URLSearchParams(window.location.search).has('chatExpanded') + const chatCollapsed = ref(_startExpanded ? false : localStorage.getItem('aiui-chat-collapsed') !== 'false') const showHistory = ref(false) // Load chats: try IndexedDB first, fall back to dev-chats middleware