diff --git a/packages/core/src/client/standalone/App.vue b/packages/core/src/client/standalone/App.vue index 2c7aca05..d455672d 100644 --- a/packages/core/src/client/standalone/App.vue +++ b/packages/core/src/client/standalone/App.vue @@ -53,6 +53,7 @@ function switchEntry(id: string) { { +import type { DevToolsDockEntry } from '@vitejs/devtools-kit' +import type { DockEntryState } from '@vitejs/devtools-kit/client' +import { onClickOutside } from '@vueuse/core' +import { computed, useTemplateRef, watch } from 'vue' + +const props = defineProps<{ + entry: DevToolsDockEntry | null + entryState: DockEntryState | null + position: { x: number, y: number } +}>() + +const emit = defineEmits<{ + (e: 'close'): void + (e: 'hide', entryId: string): void + (e: 'toggleAddressBar', entryId: string): void +}>() + +const menuRef = useTemplateRef('menuRef') +const isVisible = computed(() => props.entry !== null) + +onClickOutside(menuRef, () => { + emit('close') +}) + +// Close on escape key +watch(isVisible, (visible) => { + if (visible) { + const handler = (e: KeyboardEvent) => { + if (e.key === 'Escape') { + emit('close') + window.removeEventListener('keydown', handler) + } + } + window.addEventListener('keydown', handler) + } +}) + +// Menu position - ensure it stays within viewport +const menuStyle = computed(() => { + const { x, y } = props.position + const menuWidth = 180 + const menuHeight = 150 + + // Adjust position to keep menu in viewport + const adjustedX = Math.min(x, window.innerWidth - menuWidth - 10) + const adjustedY = Math.min(y, window.innerHeight - menuHeight - 10) + + return { + left: `${Math.max(10, adjustedX)}px`, + top: `${Math.max(10, adjustedY)}px`, + } +}) + +// Check if entry is an iframe type (supports refresh) +const isIframe = computed(() => props.entry?.type === 'iframe') + +// Check if entry has an iframe element mounted +const hasIframe = computed(() => !!props.entryState?.domElements.iframe) + +// Check if address bar is currently shown +const isAddressBarVisible = computed(() => props.entryState?.settings.showAddressBar ?? false) + +function refreshIframe() { + const iframe = props.entryState?.domElements.iframe + if (iframe) { + // Refresh by reassigning src + const currentSrc = iframe.src + iframe.src = '' + // Use setTimeout to ensure the src is cleared before reassigning + setTimeout(() => { + iframe.src = currentSrc + }, 0) + } + emit('close') +} + +function hideFromDock() { + if (props.entry) { + emit('hide', props.entry.id) + } + emit('close') +} + +function openInNewTab() { + if (props.entry?.type === 'iframe') { + window.open(props.entry.url, '_blank') + } + emit('close') +} + +function copyUrl() { + if (props.entry?.type === 'iframe') { + navigator.clipboard.writeText(props.entry.url) + } + emit('close') +} + +function toggleAddressBar() { + if (props.entry) { + emit('toggleAddressBar', props.entry.id) + } + emit('close') +} + + + diff --git a/packages/core/src/client/webcomponents/components/DockEntries.vue b/packages/core/src/client/webcomponents/components/DockEntries.vue index 94d9b01b..08f4d10e 100644 --- a/packages/core/src/client/webcomponents/components/DockEntries.vue +++ b/packages/core/src/client/webcomponents/components/DockEntries.vue @@ -1,19 +1,80 @@