diff --git a/docs/content/8.references/6.hub-api.md b/docs/content/8.references/6.hub-api.md index abb6972a..5e786068 100644 --- a/docs/content/8.references/6.hub-api.md +++ b/docs/content/8.references/6.hub-api.md @@ -137,7 +137,7 @@ The built-in variants of the open dock union (`DevframeDockEntryRegistry`, `@dev | Type | The hub UI provider renders | |---|---| -| `iframe` | the entry's `url` in a kept-alive iframe (per `frameId` when shared); honor `subTabs` soft nav | +| `iframe` | the entry's `url` in a kept-alive iframe (per `frameId` when shared); honor `subTabs` soft nav; force the existing address bar with `showAddressBar`; override Back, Reload, and Open externally visibility with `controls.back`, `controls.reload`, and `controls.openExternal` | | `action` | a dock-rail button; activating runs its client script | | `custom-render` | a container its client script mounts into | | `launcher` | a launch call-to-action reflecting `launcher.status` | diff --git a/packages/hub-ui/src/client/components/views-builtin/SettingsAppearance.vue b/packages/hub-ui/src/client/components/views-builtin/SettingsAppearance.vue index 76c76b42..b211710e 100644 --- a/packages/hub-ui/src/client/components/views-builtin/SettingsAppearance.vue +++ b/packages/hub-ui/src/client/components/views-builtin/SettingsAppearance.vue @@ -105,8 +105,8 @@ function setDockMode(mode: string) { />
- Show iframe address bar - Display navigation controls and URL bar for iframe views + Always show iframe address bars + Show the address bar for every iframe dock.
diff --git a/packages/hub-ui/src/client/components/views/ViewIframe.vue b/packages/hub-ui/src/client/components/views/ViewIframe.vue index e04efa52..fe1c59f7 100644 --- a/packages/hub-ui/src/client/components/views/ViewIframe.vue +++ b/packages/hub-ui/src/client/components/views/ViewIframe.vue @@ -20,7 +20,7 @@ const props = defineProps<{ const settings = useSettings(props.context) const isEdgeMode = computed(() => props.context.panel.store.mode === 'edge') -const showAddressBar = computed(() => settings.value.showIframeAddressBar) +const showAddressBar = computed(() => settings.value.showIframeAddressBar || props.entry.showAddressBar === true) const ADDRESS_BAR_HEIGHT = 40 @@ -77,13 +77,15 @@ const currentPageOrigin = computed(() => { // Check if iframe URL is cross-origin const isCrossOrigin = computed(() => { try { - const url = new URL(currentUrl.value) - return url.origin !== currentPageOrigin.value + return new URL(currentUrl.value).origin !== currentPageOrigin.value } catch { return true // Assume cross-origin if URL parsing fails } }) +const showBack = computed(() => props.entry.controls?.back ?? !isCrossOrigin.value) +const showReload = computed(() => props.entry.controls?.reload ?? !isCrossOrigin.value) +const showOpenExternal = computed(() => props.entry.controls?.openExternal ?? false) // Display URL - hides host if same as current page. The remote connection // descriptor is stripped so its auth token can't be read (or copied) out of the @@ -189,10 +191,20 @@ function refresh() { assetsError.value = null isIframeLoading.value = true - // Reload by reassigning the src - const src = iframe.src + const src = currentUrl.value iframe.src = '' iframe.src = src + currentUrl.value = src + editingUrl.value = src +} + +function openExternally() { + try { + const url = new URL(stripRemoteConnectionFromUrl(currentUrl.value)) + if (url.protocol === 'http:' || url.protocol === 'https:') + window.open(url.href, '_blank', 'noopener,noreferrer') + } + catch {} } let onIframeLoad: (() => void) | undefined @@ -322,40 +334,37 @@ onUnmounted(() => {
- - +
Cross-Origin
+ +
{ class="i-ph-circle-notch text-sm op40 ml-2 shrink-0 animate-spin" />
+ +
-// Placeholder shown while an iframe view loads its content. A blank iframe -// paints white during load, so this is only visible once the pane steps aside -// (`pane.hide()` in `ViewIframe`) — the same layering trick `ViewAssetsError` -// relies on. It covers the initial load and any hard navigation/refresh. +// Placeholder shown while an iframe view loads its content. The pane steps +// aside while loading so this inherits the viewer's configured background.