From ba0320fa8d1e24b7afcc55968d14428a19ae33e7 Mon Sep 17 00:00:00 2001 From: Dorian Date: Wed, 4 Mar 2026 12:24:58 +0000 Subject: [PATCH] feat(code): add Esc to exit code mode, project indicator pill, design token context - Escape key exits code mode on desktop (T14) - Show active project name pill near chat input when in code mode (T15) - Inject selected design tokens, files, and open file content into AI system prompt when in code mode (T16) Co-Authored-By: Claude Opus 4.6 --- .../app/src/components/chat/ChatWindow.vue | 18 ++++++++ packages/app/src/composables/useAI.ts | 23 ++++++++++ packages/app/src/pages/ChatPage.vue | 46 ++++++++++++++----- 3 files changed, 76 insertions(+), 11 deletions(-) diff --git a/packages/app/src/components/chat/ChatWindow.vue b/packages/app/src/components/chat/ChatWindow.vue index 4e8cfeb3..da235d43 100644 --- a/packages/app/src/components/chat/ChatWindow.vue +++ b/packages/app/src/components/chat/ChatWindow.vue @@ -103,6 +103,24 @@ class="flex-1 min-h-0" /> + +
+ + {{ codeContext.activeProject.value.name }} + + +
+ ): string { const archy = useArchy() prompt += archy.buildArchyContext() + // Append code context when in code mode + const code = useCodeContext() + if (code.isCodeMode.value) { + const sections: string[] = [] + if (code.activeProject.value) { + sections.push(`**Active project:** ${code.activeProject.value.name} (${code.activeProject.value.language ?? 'Unknown'})`) + } + if (code.selectedDesignTokens.value.length > 0) { + sections.push(`**Selected design tokens:** ${code.selectedDesignTokens.value.join(', ')}`) + } + if (code.selectedFiles.value.length > 0) { + sections.push(`**Selected files:** ${code.selectedFiles.value.join(', ')}`) + } + if (code.activeFileContent.value && code.activeFile.value) { + const content = code.activeFileContent.value.slice(0, 2000) + sections.push(`**Open file (${code.activeFile.value}):**\n\`\`\`${code.activeFileLanguage.value}\n${content}\n\`\`\``) + } + if (sections.length > 0) { + prompt += `\n\n**Code Context:**\n${sections.join('\n')}` + } + } + return prompt } diff --git a/packages/app/src/pages/ChatPage.vue b/packages/app/src/pages/ChatPage.vue index 3c0ff04c..b3fc7e3e 100644 --- a/packages/app/src/pages/ChatPage.vue +++ b/packages/app/src/pages/ChatPage.vue @@ -4,24 +4,27 @@ :class="[ hasTrack && 'pb-[72px]' ]" - :style="isDark - ? { background: '#000 url(/assets/img/bg-intro-3.jpg) center center / cover no-repeat fixed' } - : { backgroundColor: '#f5f4f1' }" + :style="isEmbedded + ? { background: 'transparent' } + : isDark + ? { background: '#000 url(' + bgImageUrl + ') center center / cover no-repeat fixed' } + : { backgroundColor: '#f5f4f1' }" > -
+
@@ -375,10 +380,16 @@ import { usePlayer } from '@/composables/usePlayer' import { useCodeContext } from '@/composables/useCodeContext' const chatStore = useChatStore() -const { activeFile: codeActiveFile, isCodeMode, clearActiveFile: clearCodeFile } = useCodeContext() +const { activeFile: codeActiveFile, isCodeMode, exitCodeMode, clearActiveFile: clearCodeFile } = useCodeContext() const { hasTrack } = usePlayer() const { isDark } = useTheme() +// Detect if running inside Archy's iframe — transparent bg, hide player bar +const isEmbedded = !!(window as unknown as Record).__AIUI_EMBEDDED__ + +// Background image URL — use BASE_URL for correct path in all deployments +const bgImageUrl = `${import.meta.env.BASE_URL}assets/img/bg-intro-3.jpg` + useAI() const { @@ -441,8 +452,21 @@ const isWideDesktop = computed(() => windowWidth.value >= 1440) const mobileTab = ref<'chat' | 'content' | 'context'>('chat') function onResize() { windowWidth.value = window.innerWidth } -onMounted(() => window.addEventListener('resize', onResize)) -onUnmounted(() => window.removeEventListener('resize', onResize)) + +function onKeydown(e: KeyboardEvent) { + if (e.key === 'Escape' && isCodeMode.value && !isMobile.value) { + exitCodeMode() + } +} + +onMounted(() => { + window.addEventListener('resize', onResize) + window.addEventListener('keydown', onKeydown) +}) +onUnmounted(() => { + window.removeEventListener('resize', onResize) + window.removeEventListener('keydown', onKeydown) +}) // Auto-switch to content tab on mobile when panel opens or content changes watch(panelOpen, (open) => {