This commit is contained in:
2026-04-13 21:42:28 -04:00
parent 5021138da6
commit 45a21ac933
6 changed files with 134 additions and 144 deletions

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, computed, onBeforeUnmount, type Component } from 'vue'
import { ref, computed, type Component } from 'vue'
import Tabs from 'primevue/tabs'
import TabList from 'primevue/tablist'
import Tab from 'primevue/tab'
@@ -53,29 +53,19 @@ function closeTab(tabId: string) {
let resizeStartY = 0
let resizeStartHeight = 0
function startResize(e: MouseEvent) {
function startResize(e: PointerEvent) {
e.preventDefault()
;(e.target as HTMLElement).setPointerCapture(e.pointerId)
resizeStartY = e.clientY
resizeStartHeight = expandedHeight.value
document.addEventListener('mousemove', onResizeMove)
document.addEventListener('mouseup', stopResize)
}
function onResizeMove(e: MouseEvent) {
function onResizeMove(e: PointerEvent) {
if (!e.buttons) return
const delta = resizeStartY - e.clientY // dragging up increases height
expandedHeight.value = Math.max(MIN_EXPANDED, resizeStartHeight + delta)
}
function stopResize() {
document.removeEventListener('mousemove', onResizeMove)
document.removeEventListener('mouseup', stopResize)
}
onBeforeUnmount(() => {
document.removeEventListener('mousemove', onResizeMove)
document.removeEventListener('mouseup', stopResize)
})
defineExpose({
openTab(id: string, label: string, component: Component, props?: Record<string, any>) {
const existing = tempTabs.value.find(t => t.id === id)
@@ -90,7 +80,7 @@ defineExpose({
<template>
<div class="bottom-tray" :style="trayStyle">
<div v-if="isExpanded" class="tray-resize-handle" @mousedown="startResize" />
<div v-if="isExpanded" class="tray-resize-handle" @pointerdown="startResize" @pointermove="onResizeMove" />
<Tabs :value="activeTab" class="tray-tabs">
<TabList class="tray-tab-list">
<Tab value="orders" @click="onTabClick('orders')">Orders</Tab>
@@ -107,7 +97,9 @@ defineExpose({
<button class="tab-close-btn" @click.stop="closeTab(tab.id)">×</button>
</Tab>
<div class="tray-spacer" />
<button v-if="isExpanded" class="tray-close-btn" @click="isExpanded = false"></button>
<button v-if="isExpanded" class="tray-close-btn" @click="isExpanded = false" title="Minimize">
<i class="pi pi-chevron-down" />
</button>
</TabList>
<TabPanels v-if="isExpanded" class="tray-panels">
<TabPanel value="orders" class="tray-panel"><OrdersTab /></TabPanel>

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, computed } from 'vue'
import { ref, onMounted, onUnmounted, computed, onBeforeUnmount, watch, nextTick } from 'vue'
import { register } from 'vue-advanced-chat'
import Badge from 'primevue/badge'
import Button from 'primevue/button'
@@ -11,6 +11,26 @@ register()
const channelStore = useChannelStore()
// Measure container height and feed a concrete pixel value to vue-advanced-chat,
// because height: 100% doesn't reliably resolve through flex chains.
const chatContainerRef = ref<HTMLElement | null>(null)
const chatHeight = ref('400px')
let resizeObserver: ResizeObserver | null = null
onMounted(() => {
if (chatContainerRef.value) {
resizeObserver = new ResizeObserver(entries => {
const h = entries[0].contentRect.height
if (h > 0) chatHeight.value = h + 'px'
})
resizeObserver.observe(chatContainerRef.value)
}
})
onBeforeUnmount(() => {
resizeObserver?.disconnect()
})
const SESSION_ID = 'default'
const CURRENT_USER_ID = 'user-123'
const AGENT_ID = 'agent'
@@ -543,16 +563,8 @@ onMounted(() => {
wsManager.addHandler(handleMessage)
setTimeout(() => {
// Inject styles into shadow DOM to widen message bubbles
const chatEl = document.querySelector('vue-advanced-chat')
if (chatEl?.shadowRoot) {
const style = document.createElement('style')
style.textContent = `
.vac-message-wrapper .vac-message-box { max-width: 80%; }
.vac-message-wrapper .vac-offset-current { margin-left: 20%; }
`
chatEl.shadowRoot.appendChild(style)
}
// Inject styles into shadow DOM to widen message bubbles (fallback if already ready at mount)
injectShadowStyles()
const chatInput = document.querySelector('.vac-textarea') as HTMLTextAreaElement
if (chatInput) {
@@ -561,13 +573,38 @@ onMounted(() => {
}, 300)
})
const injectShadowStyles = () => {
const chatEl = document.querySelector('vue-advanced-chat')
if (chatEl?.shadowRoot) {
// Remove any previously injected style to avoid duplicates
chatEl.shadowRoot.querySelector('#vac-width-override')?.remove()
const style = document.createElement('style')
style.id = 'vac-width-override'
style.textContent = `
.vac-message-wrapper .vac-message-box { max-width: 80%; }
.vac-message-wrapper .vac-offset-current { margin-left: 20%; }
`
chatEl.shadowRoot.appendChild(style)
}
}
watch(() => channelStore.isReady, async (ready) => {
if (!ready) return
await nextTick()
setTimeout(() => {
injectShadowStyles()
const chatInput = document.querySelector('.vac-textarea') as HTMLTextAreaElement
chatInput?.focus()
}, 100)
})
onUnmounted(() => {
wsManager.removeHandler(handleMessage)
})
</script>
<template>
<div class="chat-container">
<div class="chat-container" ref="chatContainerRef">
<!--
<div class="chat-header-custom">
<span class="chat-title">AI Agent Chat</span>
@@ -586,7 +623,7 @@ onUnmounted(() => {
<vue-advanced-chat
v-else
height="100vh"
:height="chatHeight"
:current-user-id="CURRENT_USER_ID"
:rooms="JSON.stringify(rooms)"
:messages="JSON.stringify(messages)"
@@ -640,13 +677,13 @@ onUnmounted(() => {
align-items: center;
justify-content: center;
gap: 1rem;
background: #131722;
color: #787B86;
background: #0f0f0f;
color: #888;
}
.workspace-loading-spinner {
font-size: 2rem;
color: #787B86;
color: #089981;
}
.workspace-loading-message {

View File

@@ -129,7 +129,7 @@ onMounted(() => {
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, var(--p-surface-0) 0%, var(--p-surface-100) 100%);
background: #0f0f0f;
}
.login-container {
@@ -139,7 +139,7 @@ onMounted(() => {
}
.login-card {
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
box-shadow: 0 8px 48px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.06);
}
.login-title {