Skip to content

Commit

Permalink
feat: apps sidepane
Browse files Browse the repository at this point in the history
  • Loading branch information
Akryum committed Feb 14, 2022
1 parent 470924f commit 2ee2f79
Show file tree
Hide file tree
Showing 7 changed files with 276 additions and 9 deletions.
25 changes: 24 additions & 1 deletion packages/app-frontend/src/features/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import AppConnecting from './connection/AppConnecting.vue'
import AppDisconnected from './connection/AppDisconnected.vue'
import ErrorOverlay from './error/ErrorOverlay.vue'
import WelcomeSlideshow from './welcome/WelcomeSlideshow.vue'
import SplitPane from './layout/SplitPane.vue'
import AppSelectPane from './apps/AppSelectPane.vue'
import { onMounted, defineComponent, ref, watch } from '@vue/composition-api'
import {
Expand All @@ -16,6 +18,7 @@ import {
} from '@vue-devtools/shared-utils'
import { darkMode } from '@front/util/theme'
import { useAppConnection } from './connection'
import { showAppsSelector } from './header/header'
const chromeTheme = isChrome ? chrome.devtools.panels.themeName : undefined
Expand All @@ -31,6 +34,8 @@ export default defineComponent({
AppDisconnected,
ErrorOverlay,
WelcomeSlideshow,
SplitPane,
AppSelectPane,
},
setup () {
Expand Down Expand Up @@ -79,6 +84,7 @@ export default defineComponent({
isConnected,
isInitializing,
welcomeHidden,
showAppsSelector,
}
},
})
Expand All @@ -104,7 +110,24 @@ export default defineComponent({
<template v-else>
<AppHeader class="flex-none relative z-10 border-b border-gray-200 dark:border-gray-800" />

<router-view class="flex-1 overflow-auto" />
<SplitPane
save-id="app-select-pane"
:default-split="12"
:min="5"
:max="40"
collapsable-left
class="flex-1 overflow-hidden"
@left-collapsed="showAppsSelector = $event"
>
<template #left>
<AppSelectPane
class="h-full"
/>
</template>
<template #right>
<router-view class="h-full overflow-auto" />
</template>
</SplitPane>
</template>

<portal-target name="root" />
Expand Down
110 changes: 110 additions & 0 deletions packages/app-frontend/src/features/apps/AppSelectPane.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<script lang="ts">
import AppSelectPaneItem from './AppSelectPaneItem.vue'
import { watch, defineComponent, ref, computed } from '@vue/composition-api'
import { BridgeEvents, SharedData } from '@vue-devtools/shared-utils'
import { useApps, pendingSelectAppId, scanLegacyApps } from '@front/features/apps'
import { useRouter } from '@front/util/router'
import { useBridge } from '../bridge'
export default defineComponent({
components: {
AppSelectPaneItem,
},
setup () {
const router = useRouter()
const { bridge } = useBridge()
const {
apps,
currentAppId,
currentApp,
selectApp,
} = useApps()
watch(currentAppId, value => {
if (pendingSelectAppId.value !== value) {
pendingSelectAppId.value = value
bridge.send(BridgeEvents.TO_BACK_APP_SELECT, value)
}
}, {
immediate: true,
})
let initDefaultAppId = false
watch(apps, () => {
if ((!currentApp.value || (SharedData.pageConfig?.defaultSelectedAppId && !initDefaultAppId)) && apps.value.length) {
let targetId: string
if (SharedData.pageConfig?.defaultSelectedAppId) {
targetId = SharedData.pageConfig.defaultSelectedAppId
initDefaultAppId = true
} else if (currentAppId.value !== apps.value[0].id) {
targetId = apps.value[0].id
}
if (targetId) {
router.push({
params: {
appId: targetId,
componentId: null,
},
})
}
}
}, {
immediate: true,
})
// Search
const search = ref('')
const filteredApps = computed(() => {
if (!search.value) return apps.value
const searchValue = search.value.toLowerCase()
return apps.value.filter(app => {
return app.name.toLowerCase().includes(searchValue)
})
})
return {
currentApp,
filteredApps,
selectApp,
search,
scanLegacyApps,
}
},
})
</script>

<template>
<div class="flex flex-col">
<div class="flex-none border-b border-gray-200 dark:border-gray-800 flex items-center space-x-1 h-[40px] pr-1">
<VueInput
v-model="search"
icon-left="search"
placeholder="Find apps..."
select-all
class="search flat flex-1"
/>

<VueButton
v-if="$shared.legacyApps"
v-tooltip="'Scan apps'"
class="flat icon-button"
icon-left="cached"
@click="scanLegacyApps()"
/>
</div>

<div class="overflow-y-auto flex-1">
<AppSelectPaneItem
v-for="item of filteredApps"
:key="item.id"
:app="item"
:selected="item === currentApp"
@select="selectApp(item.id)"
/>
</div>
</div>
</template>
95 changes: 95 additions & 0 deletions packages/app-frontend/src/features/apps/AppSelectPaneItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<script lang="ts">
import { defineComponent, computed } from '@vue/composition-api'
import { useVueVersionCheck } from './vue-version-check'
export default defineComponent({
props: {
app: {
type: Object,
required: true,
},
selected: {
type: Boolean,
default: false,
},
},
setup (props) {
const { getLatestVersion } = useVueVersionCheck()
const latestVersion = computed(() => getLatestVersion(props.app.version))
const hasNewVersion = computed(() => latestVersion.value !== props.app.version)
return {
latestVersion,
hasNewVersion,
}
},
})
</script>

<template>
<VueButton
class="app-button leading-tight w-full"
:class="{
'flat': !selected,
'text-green-500': selected,
}"
@click="$emit('select')"
>
<div class="flex items-center">
<span class="truncate flex-1">{{ app.name }}</span>
<span class="flex-none flex items-center">
<img
src="~@front/assets/vue-logo.svg"
class="w-6 h-6"
alt="Vue"
>
<span>{{ app.version }}</span>
<span
v-if="hasNewVersion"
class="ml-2 text-sm text-green-500 flex items-center space-x-0.5"
>
<VueIcon
icon="new_releases"
class="w-5 h-5"
/>
<span>{{ latestVersion }}</span>
</span>
</span>

<template v-if="$shared.debugInfo">
<span
v-tooltip="'id'"
class="text-white px-1 rounded bg-gray-500 mx-1"
>
{{ app.id }}
</span>
</template>
</div>
<div
v-if="app.iframe"
class="flex items-center space-x-1 text-2xs font-mono text-gray-500"
>
<VueIcon
icon="web"
class="w-4 h-4"
/>
<span>{{ app.iframe }}</span>
</div>
</VueButton>
</template>

<style lang="postcss" scoped>
.app-button {
@apply rounded-none text-left h-auto py-1.5;
> >>> .content {
@apply min-w-full justify-start;
> .default-slot {
@apply w-full;
}
}
}
</style>
9 changes: 7 additions & 2 deletions packages/app-frontend/src/features/header/AppHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useRoute } from '@front/util/router'
import { useBridge } from '@front/features/bridge'
import { useInspectors } from '@front/features/inspector/custom/composable'
import { useTabs } from './tabs'
import { showAppsSelector } from './header'
export default defineComponent({
components: {
Expand Down Expand Up @@ -68,6 +69,7 @@ export default defineComponent({
inspectorRoutes,
currentInspectorRoute,
lastInspectorRoute,
showAppsSelector,
}
},
})
Expand All @@ -79,12 +81,15 @@ export default defineComponent({

<AppHistoryNav />

<AppSelect />
<template v-if="showAppsSelector">
<AppSelect />

<img src="~@front/assets/breadcrumb-separator.svg">
<img src="~@front/assets/breadcrumb-separator.svg">
</template>

<AppMainMenu
:last-inspector-route="lastInspectorRoute"
:label-shown="!showAppsSelector"
/>

<template v-if="currentInspectorRoute">
Expand Down
27 changes: 23 additions & 4 deletions packages/app-frontend/src/features/header/AppMainMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ export default defineComponent({
type: Object,
default: null,
},
labelShown: {
type: Boolean,
default: false,
},
},
setup (props) {
Expand Down Expand Up @@ -41,15 +46,29 @@ export default defineComponent({
v-tooltip="'Inspector'"
:to="targetInspectorRoute"
value="inspector"
class="icon-button flat"
class="flat"
:class="{
'icon-button': !labelShown,
}"
icon-left="explore"
/>
>
<template v-if="labelShown">
Inspector
</template>
</VueGroupButton>
<VueGroupButton
v-tooltip="'Timeline'"
:to="{ name: 'timeline' }"
value="timeline"
class="icon-button flat"
class="flat"
:class="{
'icon-button': !labelShown,
}"
icon-left="line_style"
/>
>
<template v-if="labelShown">
Timeline
</template>
</VueGroupButton>
</VueGroup>
</template>
3 changes: 3 additions & 0 deletions packages/app-frontend/src/features/header/header.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { ref } from '@vue/composition-api'

export const showAppsSelector = ref(true)
16 changes: 14 additions & 2 deletions packages/app-frontend/src/features/layout/SplitPane.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import { ref, computed, defineComponent, PropType } from '@vue/composition-api'
import { ref, computed, defineComponent, PropType, watch } from '@vue/composition-api'
import { useOrientation } from './orientation'
import { useSavedRef } from '@front/util/reactivity'
Expand Down Expand Up @@ -42,7 +42,7 @@ export default defineComponent({
},
},
setup (props) {
setup (props, { emit }) {
const { orientation } = useOrientation()
const split = ref(props.defaultSplit)
Expand All @@ -59,6 +59,18 @@ export default defineComponent({
}
}
watch(leftCollapsed, value => {
emit('left-collapsed', value)
}, {
immediate: true,
})
watch(rightCollapsed, value => {
emit('right-collapsed', value)
}, {
immediate: true,
})
const boundSplit = computed(() => {
if (split.value < props.min) {
return props.min
Expand Down

0 comments on commit 2ee2f79

Please sign in to comment.