Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improve split screen #358

Merged
merged 3 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions packages/client/src/components/CustomTabComponent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<script setup lang="ts">
import { CustomTab } from '@vue/devtools-kit'

const p = defineProps<{
tab: CustomTab
iframeInline?: boolean
}>()

const props = toRefs(p)

const tabName = computed(() => props.tab.value.name)

const iframeViewVisible = ref(true)
watch(() => tabName.value, () => {
iframeViewVisible.value = false
setTimeout(() => {
iframeViewVisible.value = true
}, 100)
})
</script>

<template>
<template v-if="!tab">
<div flex="~ col" h-full items-center justify-center>
<div flex="~ col gap2" mxa items-center>
<div i-carbon-queued mb2 text-5xl op50 />
<p text-xl>
Tab <code text-rose>{{ tabName }}</code> not found
</p>
<p mt8 animate-pulse>
Redirecting to overview page...
</p>
</div>
</div>
</template>
<template v-else-if="tab?.view?.type === 'iframe'">
<IframeView v-if="iframeViewVisible" :src="tab.view.src" :inline="iframeInline" />
</template>
<template v-else-if="tab?.view?.type === 'vnode'">
<Component :is="tab.view.vnode" />
</template>
<template v-else>
<div>
<NCard flex="~ col" h-full items-center justify-center>
Unknown tab type {{ tab?.view }}
</NCard>
</div>
</template>
</template>
23 changes: 20 additions & 3 deletions packages/client/src/components/common/IframeView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ const iframeCacheMap = new Map<string, HTMLIFrameElement>()
</script>

<script setup lang="ts">
const props = defineProps<{
const props = withDefaults(defineProps<{
src: string
}>()
inline?: boolean
}>(), {
inline: false,
})

const { colorMode } = useDevToolsColorMode()
const anchor = ref<HTMLDivElement>()
Expand Down Expand Up @@ -38,10 +41,18 @@ onMounted(() => {
catch (e) {
iframeEl.value.style.opacity = '1'
}

document.body.appendChild(iframeEl.value)
nextTick(updateIframeBox)
}

// should force update the iframe visible on conflict(inline mode is unmounted after global mode is mounted)
const timer = setTimeout(resolveConflictVisible, 100)
setTimeout(syncColorMode, 100)

onUnmounted(() => {
clearTimeout(timer)
})
})

watchEffect(updateIframeBox)
Expand All @@ -52,6 +63,12 @@ onUnmounted(() => {
iframeEl.value.style.visibility = 'hidden'
})

function resolveConflictVisible() {
if (!iframeEl.value)
return
iframeEl.value.style.visibility = 'visible'
}

function syncColorMode() {
if (!iframeEl.value || !iframeEl.value.contentWindow)
return
Expand All @@ -72,7 +89,7 @@ function updateIframeBox() {
left: `${box.left}px`,
top: `${box.top}px`,
width: `${box.width}px`,
height: `${box.height}px`,
height: `${props.inline ? box.height - box.top : box.height}px`,
outline: 'none',
})
}
Expand Down
13 changes: 10 additions & 3 deletions packages/client/src/components/common/SideNavItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ const props = withDefaults(
tab: ModuleBuiltinTab
minimized?: boolean
target?: 'main' | 'side'
disabled?: boolean
}>(),
{
minimized: true,
target: 'main',
disabled: false,
},
)
const route = useRoute()
Expand All @@ -22,6 +24,8 @@ const badge = computed(() => 'badge' in props.tab && props.tab.badge?.())
const isActive = computed(() => route.path.startsWith(tabPath.value))

function onClick() {
if (props.disabled)
return
if ('onClick' in props.tab && props.tab.onClick)
props.tab.onClick()
else if (props.target === 'side')
Expand All @@ -35,11 +39,14 @@ function onClick() {
:is="target === 'main' ? RouterLink : 'button'"
:to="tabPath"
:flex="`~ items-center ${minimized ? 'justify-center' : 'justify-between'}`"
hover="bg-active op-100"

text-secondary relative block h-10 select-none op65
:disabled="disabled"
:class="[
disabled ? 'cursor-not-allowed op40!' : 'hover:(bg-active op-100)',
]"
:w="minimized ? '10' : 'full'"
:rounded="minimized ? 'xl' : ''"
:p="minimized ? '1' : 'x3'" text-secondary relative block h-10 select-none op65
:p="minimized ? '1' : 'x3'"
exact-active-class="!text-primary-600 bg-active op-100!"
@click="onClick"
>
Expand Down
66 changes: 41 additions & 25 deletions packages/client/src/components/common/SplitScreen.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<script setup lang="ts">
import { CustomTab } from '@vue/devtools-kit'
import { VueButton, VueCard, VueDropdown, VTooltip as vTooltip } from '@vue/devtools-ui'
import { ModuleBuiltinTab } from '~/types'

function close() {
devtoolsClientState.value.splitScreen.enabled = false
Expand All @@ -10,32 +12,45 @@ const { enabledTabs, flattenedTabs } = useAllTabs()
const router = useRouter()
const route = useRoute()
const PageComponent = shallowRef()
const customTabName = ref<string | null>(null)

function isMatchedWithRoute(tab?: typeof flattenedTabs['value'][number]) {
const routePath = route.path.startsWith('/') ? route.path.slice(1) : route.path
return tab && 'path' in tab && routePath === tab.path
const routeTabName = getRouteTabName()
if (!tab)
return false
return tab.name === routeTabName
}

const currentTab = computed(() => {
const tab = flattenedTabs.value.find(tab => tab.name === splitScreenState.value.view)
return isMatchedWithRoute(tab) ? undefined : tab
})

const mainViewName = computed(() =>
getRouteTabName(),
)

function getRouteTabName() {
return route.path.startsWith(`/${CUSTOM_TAB_VIEW}/`)
? route.path.slice(CUSTOM_TAB_VIEW.length + 2)
: route.path.startsWith('/')
? route.path.slice(1)
: route.path
}

watch(
() => currentTab.value,
(tab) => {
if (!tab)
return
const routes = router.getRoutes()
const matched = tab && 'path' in tab
? routes.find(route => route.path === (tab.path.startsWith('/') ? tab.path : `/${tab.path}`))
: routes.find(route => route.name === 'custom-tab') // TODO: custom tabs
// if it's the same route as the main view, skip
const path = route.path.startsWith('/') ? route.path.slice(1) : route.path
if (matched?.path === path || route.params?.name === tab.name) {
PageComponent.value = undefined
// check if is a custom tab
if ((tab as CustomTab).view) {
customTabName.value = tab.name
return
}
customTabName.value = null
const routes = router.getRoutes()
const matched = routes.find(route => route.path === `/${(tab as ModuleBuiltinTab).path}`)
const component = matched?.components?.default
if (typeof component === 'function')
PageComponent.value = defineAsyncComponent(component as any)
Expand All @@ -50,7 +65,7 @@ const showGridPanel = ref(false)

<template>
<div h-full h-screen of-hidden>
<div v-if="PageComponent && currentTab" border="b base" flex="~ gap1" z-99 px4 py3 navbar-glass>
<div v-if="(PageComponent || customTabName) && currentTab" border="b base" flex="~ gap1" z-99 px4 py3 navbar-glass>
<VueDropdown placement="bottom-start" :distance="12" :skidding="5" :shown="showGridPanel" trigger="click">
<div flex cursor-pointer items-center gap2>
<div i-carbon-chevron-down text-sm op50 />
Expand All @@ -66,7 +81,7 @@ const showGridPanel = ref(false)
</span>
</div>
<template #popper>
<TabsGrid :categories="enabledTabs" target="side" />
<TabsGrid :categories="enabledTabs" target="side" :disabled-items="[mainViewName]" />
</template>
</VueDropdown>
<div flex-auto />
Expand All @@ -78,21 +93,22 @@ const showGridPanel = ref(false)
<div i-carbon:side-panel-open />
</button>
</div>
<div v-if="PageComponent && currentTab" of-auto style="height: calc(100% - 50px)">
<!-- TODO: custom tabs -->
<!-- Tabs -->
<CustomTabComponent v-if="customTabName && currentTab" :tab="currentTab as CustomTab" class="h-[calc(100%-50px)]" iframe-inline of-auto />
<div v-else-if="PageComponent && currentTab" of-auto class="h-[calc(100%-50px)]">
<component :is="PageComponent" :key="`tab-${currentTab.name}`" />
</div>
<div v-else>
<span text-lg op50>
Select a tab to start
</span>
<VueCard px4 py2 bg-base>
<TabsGrid :categories="enabledTabs" target="side" />
</VueCard>
<VueButton type="warning" outlined mt2 @click="close">
Close Split Screen
</VueButton>
<div v-else class="h-full w-full $ui-fcc">
<div>
<span text-lg op50>
Select a tab to start
</span>
<VueCard px4 py2 bg-base>
<TabsGrid :categories="enabledTabs" target="side" :disabled-items="[mainViewName]" />
</VueCard>
<VueButton type="warning" outlined mt2 @click="close">
Close Split Screen
</VueButton>
</div>
</div>
</div>
</template>
2 changes: 2 additions & 0 deletions packages/client/src/components/common/TabsGrid.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { CategorizedTabs } from '~/composables/state-tab'
defineProps<{
categories: CategorizedTabs
target: 'main' | 'side'
disabledItems?: string[]
}>()
</script>

Expand All @@ -16,6 +17,7 @@ defineProps<{
<SideNavItem
v-for="tab of tabs"
:key="tab.name"
:disabled="disabledItems?.includes(tab.name)"
:target="target"
:tab="tab"
/>
Expand Down
2 changes: 2 additions & 0 deletions packages/client/src/constants/tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,5 @@ export function getBuiltinTab(viteDetected: boolean, moduleDetectives?: Devtools
? tab
: tab.map(([_, tabs]) => [_, tabs.filter(t => !viteOnlyTabs.includes(t.name))])
}

export const CUSTOM_TAB_VIEW = 'custom-tab-view'
2 changes: 1 addition & 1 deletion packages/client/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const routes = [
{ path: '/assets', component: Assets },
{ path: '/graph', component: Graph },
{ path: '/settings', component: Settings },
{ path: '/custom-tab-view/:name', component: CustomTabView },
{ path: `/${CUSTOM_TAB_VIEW}/:name`, component: CustomTabView },
]

// @TODO: find a better way to handle it
Expand Down
35 changes: 1 addition & 34 deletions packages/client/src/pages/custom-tab-view.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,41 +15,8 @@ onMounted(() => {
}, 2000)
}
})

const iframeViewVisible = ref(true)
watch(() => route.params.name, () => {
iframeViewVisible.value = false
setTimeout(() => {
iframeViewVisible.value = true
}, 100)
})
</script>

<template>
<template v-if="!tab">
<div flex="~ col" h-full items-center justify-center>
<div flex="~ col gap2" mxa items-center>
<div i-carbon-queued mb2 text-5xl op50 />
<p text-xl>
Tab <code text-rose>{{ tabName }}</code> not found
</p>
<p mt8 animate-pulse>
Redirecting to overview page...
</p>
</div>
</div>
</template>
<template v-else-if="tab?.view?.type === 'iframe'">
<IframeView v-if="iframeViewVisible" :src="tab.view.src" />
</template>
<template v-else-if="tab?.view?.type === 'vnode'">
<Component :is="tab.view.vnode" />
</template>
<template v-else>
<div>
<NCard flex="~ col" h-full items-center justify-center>
Unknown tab type {{ tab?.view }}
</NCard>
</div>
</template>
<CustomTabComponent :tab="tab" />
</template>
4 changes: 2 additions & 2 deletions packages/client/src/pages/graph.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ const navbarRef = ref<HTMLElement>()
</script>

<template>
<div flex="~ col" relative h-screen of-hidden panel-grids class="graph-body">
<div flex="~ col" relative h-full of-hidden panel-grids class="graph-body">
<GraphNavbar ref="navbarRef" />
<div ref="container" flex="1" />
<div ref="container" class="absolute h-full w-full" />
<GraphFileType />
<GraphDrawer :top="navbarRef" />
</div>
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/pages/overview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ onDevToolsClientConnected(() => {
</script>

<template>
<div h-screen w-full flex of-auto>
<div h-full w-full flex of-auto>
<div flex="~ col gap2" ma h-full max-w-300 w-full px20>
<div flex-auto />

Expand Down
Loading