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: add canvas route bar #967

Merged
merged 20 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
6 changes: 5 additions & 1 deletion packages/canvas/DesignCanvas/src/DesignCanvas.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<template>
<component :is="CanvasLayout">
<template #header>
<component :is="CanvasRouteBar"></component>
</template>
<template #container>
<component
:is="CanvasContainer.entry"
Expand Down Expand Up @@ -52,7 +55,7 @@ export default {
setup() {
const registry = getMergeRegistry('canvas')
const materialsPanel = getMergeMeta('engine.plugins.materials')?.entry
const { CanvasBreadcrumb } = registry.components
const { CanvasRouteBar, CanvasBreadcrumb } = registry.components
const CanvasLayout = registry.layout.entry
const [CanvasContainer] = registry.metas
const footData = ref([])
Expand Down Expand Up @@ -218,6 +221,7 @@ export default {
CanvasLayout,
canvasRef,
CanvasContainer,
CanvasRouteBar,
CanvasBreadcrumb
}
}
Expand Down
29 changes: 25 additions & 4 deletions packages/canvas/container/src/components/CanvasMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div v-show="menuState.show" ref="menuDom" class="context-menu" :style="menuState.position">
<ul class="menu-item">
<li
v-for="(item, index) in menus"
v-for="(item, index) in filteredMenus"
:key="index"
:class="{
'li-item': item.items,
Expand Down Expand Up @@ -32,9 +32,9 @@
</template>

<script lang="jsx">
import { ref, reactive, nextTick } from 'vue'
import { ref, reactive, nextTick, computed } from 'vue'
import { canvasState, getConfigure, getController, getCurrent, copyNode, removeNodeById } from '../container'
import { useLayout, useModal, useCanvas, getMergeMeta } from '@opentiny/tiny-engine-meta-register'
import { useLayout, useModal, useCanvas, usePage, getMergeMeta } from '@opentiny/tiny-engine-meta-register'
import { iconRight } from '@opentiny/vue-icon'

const menuState = reactive({
Expand Down Expand Up @@ -121,6 +121,21 @@ export default {
menus.value.push({ name: '新建区块', code: 'createBlock' })
}

menus.value.unshift({
name: '路由跳转',
code: 'route',
show: () => getCurrent().schema?.componentName === 'RouterLink'
})

const filteredMenus = computed(() =>
menus.value.filter((item) => {
if (typeof item.show === 'function') {
return item.show()
}
return true
})
)

const boxVisibility = ref(false)

// 计算上下文菜单位置,右键时显示,否则关闭
Expand Down Expand Up @@ -205,6 +220,12 @@ export default {
status: 'error'
})
}
},
route() {
const target = getCurrent().schema.props.to?.name
if (target) {
usePage().switchPage(target)
}
}
}

Expand Down Expand Up @@ -234,7 +255,7 @@ export default {
return {
SaveNewBlock,
menuState,
menus,
filteredMenus,
doOperation,
boxVisibility,
close,
Expand Down
2 changes: 2 additions & 0 deletions packages/canvas/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
*
*/
import { CanvasRouteBar } from './route-bar'
import { CanvasBreadcrumb } from './breadcrumb'

// meta app
Expand All @@ -21,6 +22,7 @@ export { CanvasContainer, CanvasLayout, DesignCanvas }
export default {
...DesignCanvas,
components: {
CanvasRouteBar,
CanvasBreadcrumb
},
layout: CanvasLayout,
Expand Down
7 changes: 5 additions & 2 deletions packages/canvas/layout/src/CanvasLayout.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<template>
<div id="canvas-wrap" ref="canvasRef">
<slot name="header"></slot>
<div ref="siteCanvas" class="site-canvas" :style="siteCanvasStyle">
<slot name="container"></slot>
</div>
Expand All @@ -13,7 +14,7 @@ import { useLayout } from '@opentiny/tiny-engine-meta-register'
const siteCanvasStyle = computed(() => {
const { scale } = useLayout().getDimension()
return {
height: `calc((100% - var(--base-bottom-panel-height, 30px) - 36px) / ${scale})`,
height: `calc((100% - var(--base-bottom-panel-height, 30px) - 68px) / ${scale})`,
transform: `scale(${scale})`
}
})
Expand All @@ -32,7 +33,9 @@ const siteCanvasStyle = computed(() => {
background: var(--ti-lowcode-breadcrumb-hover-bg);
position: absolute;
overflow: hidden;
margin: 18px 0;
// TODO 这里的多的32px是route bar的高度,硬编码设置margin-top不适合动态显隐route bar。是否能改成不用 position: absolute;
margin-top: calc(18px + 32px);
margin-bottom: 18px;
transform-origin: top;
}
}
Expand Down
29 changes: 21 additions & 8 deletions packages/canvas/render/src/builtin/CanvasRouterLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</span>
</template>
<script lang="ts">
import { computed, inject } from 'vue'
import { computed, inject, PropType, Ref } from 'vue'
export default {
props: {
activeClass: {
Expand All @@ -22,17 +22,30 @@ export default {
default: ''
},
to: {
type: String
// TODO: 待改成页面选择器
// type: Object as PropType<{
// pageId: string
// }>
// TODO: 支持绝对路径,类型为String
type: Object as PropType<{
name: string
}>
}
},
setup(props) {
const pageAncestor = (inject('page-ancestors') as Ref<string[] | null>).value
const active = computed(() => pageAncestor?.length && pageAncestor.indexOf(props.to) > -1)
const exactActive = computed(() => pageAncestor?.length && props.to === pageAncestor[pageAncestor.length - 1])
const active = computed(() => {
if (!Array.isArray(pageAncestor) || !props.to?.name) {
return false
}

return pageAncestor.includes(props.to.name)
})

const exactActive = computed(() => {
if (!Array.isArray(pageAncestor) || !props.to?.name) {
return false
}

return props.to.name === pageAncestor[pageAncestor.length - 1]
})

return {
active,
exactActive
Expand Down
6 changes: 2 additions & 4 deletions packages/canvas/render/src/builtin/builtin.json
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@
},
"cols": 12,
"widget": {
"component": "InputConfigurator",
"component": "RouterSelectConfigurator",
"props": {}
}
},
Expand Down Expand Up @@ -628,9 +628,7 @@
"icon": "RouterLink",
"schema": {
"componentName": "RouterLink",
"props": {
"to": ""
},
"props": {},
"children": [
{
"componentName": "Text",
Expand Down
1 change: 1 addition & 0 deletions packages/canvas/route-bar/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as CanvasRouteBar } from './src/CanvasRouteBar.vue'
125 changes: 125 additions & 0 deletions packages/canvas/route-bar/src/CanvasRouteBar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<template>
<div id="canvas-route-bar" :style="sizeStyle">
<div class="address-bar">
<template v-for="route in routes" :key="route.id">
<span class="slash">/</span>
<span :class="[{ route: route.isPage && route.id !== pageId }]" @click="handleClickRoute(route)">{{
route.route
}}</span>
</template>
</div>
</div>
</template>

<script setup>
import { getMetaApi, META_SERVICE, useLayout, useMessage, usePage } from '@opentiny/tiny-engine-meta-register'
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'

const sizeStyle = computed(() => {
const { width, maxWidth, minWidth, scale } = useLayout().getDimension()
// TODO 缩放非常小时,高度会有问题
return {
width,
maxWidth,
minWidth,
height: `calc(32px / ${scale})`,
transform: `scale(${scale})`
}
})

const { pageSettingState, getAncestors, switchPage } = usePage()

const pageId = ref(getMetaApi(META_SERVICE.GlobalService).getBaseInfo().pageId)

const { subscribe, unsubscribe } = useMessage()

let subscriber = null

onMounted(() => {
subscriber = subscribe({
topic: 'locationHistoryChanged',
callback: (data) => {
if (data.pageId) {
pageId.value = data.pageId
}
},
subscriber: 'routeBar'
})
})

onUnmounted(() => {
if (subscriber) {
unsubscribe(subscriber)
}
})

/**
* @typedef {Object} Route
* @property {string | number} id
* @property {string} route
* @property {boolean} isPage
*/

/** @type {import('vue').Ref<Route[]>} */
const routes = ref([])

watch(
pageId,
async (value) => {
if (!value) {
return
}
const ancestors = await getAncestors(value, true)

routes.value = ancestors.concat(value).map((id) => {
const { route, isPage } = pageSettingState.treeDataMapping[id]
return {
id,
route: route
.replace(/\/+/g, '/') // 替换连续的 '/' 为单个 '/'
.replace(/^\/|\/$/g, ''), // 去掉开头和结尾的 '/'
isPage
}
})
},
{ immediate: true }
)

/**
* @param route {Route}
*/
const handleClickRoute = (route) => {
switchPage(route.id)
}
</script>

<style lang="less" scoped>
#canvas-route-bar {
position: absolute;
top: 18px;
background-color: var(--te-common-bg-prompt);
border-top-left-radius: 4px;
border-top-right-radius: 4px;
display: flex;
align-items: center;
padding: 0 8px;
}
.address-bar {
display: flex;
align-items: center;
gap: 2px;
background-color: var(--te-common-bg-container);
height: 20px;
width: 100%;
border-radius: 999px;
padding: 0 10px;
cursor: default;
}
.route {
cursor: pointer;
&:hover {
text-decoration: underline;
color: var(--te-common-text-link);
}
}
</style>
2 changes: 2 additions & 0 deletions packages/configurator/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import RadioConfigurator from './radio-configurator/RadioConfigurator.vue'
import RadioGroupConfigurator from './radio-group-configurator/RadioGroupConfigurator.vue'
import RelatedColumnsConfigurator from './related-columns-configurator/RelatedColumnsConfigurator.vue'
import RelatedEditorConfigurator from './related-editor-configurator/RelatedEditorConfigurator.vue'
import RouterSelectConfigurator from './router-select-configurator/RouterSelectConfigurator.vue'
import SelectConfigurator from './select-configurator/SelectConfigurator.vue'
import SelectIconConfigurator from './select-icon-configurator/SelectIconConfigurator.vue'
import SliderConfigurator from './slider-configurator/SliderConfigurator.vue'
Expand Down Expand Up @@ -54,6 +55,7 @@ export {
RadioGroupConfigurator,
RelatedColumnsConfigurator,
RelatedEditorConfigurator,
RouterSelectConfigurator,
SelectConfigurator,
SelectIconConfigurator,
SliderConfigurator,
Expand Down
Loading
Loading