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 17 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
11 changes: 9 additions & 2 deletions 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 v-if="!isBlock" :is="CanvasRouteBar"></component>
</template>
<template #container>
<component
:is="CanvasContainer.entry"
Expand All @@ -18,7 +21,7 @@
</template>

<script>
import { ref, watch, onUnmounted, onMounted } from 'vue'
import { computed, ref, watch, onUnmounted, onMounted } from 'vue'
import {
useProperties,
useCanvas,
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 All @@ -74,6 +77,8 @@ export default {
pageState.properties = null
}

const isBlock = computed(() => useCanvas().isBlock())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个会一直调用嘛? isBlock是个普通函数?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里 isBlock 是值,不是函数。修改成 const isBlock = useCanvas().isBlock,保存函数引用,避免 computed


watch(
[() => useCanvas().isSaved(), () => useLayout().layoutState.pageStatus, () => useCanvas().getPageSchema()],
([isSaved, pageStatus, pageSchema], [oldIsSaved, _oldPageStatus, oldPageSchema]) => {
Expand Down Expand Up @@ -221,9 +226,11 @@ export default {
addHistoryDataChangedCallback,
ast
},
isBlock,
CanvasLayout,
canvasRef,
CanvasContainer,
CanvasRouteBar,
CanvasBreadcrumb
}
}
Expand Down
38 changes: 33 additions & 5 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,25 @@ export default {
menus.value.push({ name: '新建区块', code: 'createBlock' })
}

menus.value.unshift({
name: '路由跳转',
code: 'route',
show: () => getCurrent()?.schema?.componentName === 'RouterLink',
check: () => {
const targetPageId = getCurrent().schema.props?.to?.name
return typeof targetPageId === 'number' || targetPageId
}
})

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,10 +224,19 @@ export default {
status: 'error'
})
}
},
route() {
// check中验证过了 targetPageId 是有效值
const targetPageId = getCurrent().schema.props.to.name
usePage().switchPageWithConfirm(targetPageId)
}
}

const actionDisabled = (actionItem) => {
if (typeof actionItem.check === 'function' && !actionItem.check()) {
return true
}

const actions = ['del', 'copy', 'addParent']
return actions.includes(actionItem.code) && !getCurrent().schema?.id
}
Expand All @@ -221,7 +249,7 @@ export default {
boxVisibility.value = false
}
const doOperation = (item) => {
if ((item.check && !item.check?.()) || actionDisabled(item)) {
if (actionDisabled(item)) {
return
}

Expand All @@ -234,7 +262,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
18 changes: 13 additions & 5 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 @@ -8,13 +9,20 @@
</template>
<script setup>
import { computed } from 'vue'
import { useLayout } from '@opentiny/tiny-engine-meta-register'
import { useCanvas, useLayout } from '@opentiny/tiny-engine-meta-register'

const ROUTE_BAR_HEIGHT = 32

const { isBlock } = useCanvas()
const dimension = useLayout().getDimension()

const siteCanvasStyle = computed(() => {
const { scale } = useLayout().getDimension()
const { scale } = dimension
const routeBarHeight = isBlock() ? 0 : ROUTE_BAR_HEIGHT
return {
height: `calc((100% - var(--base-bottom-panel-height, 30px) - 36px) / ${scale})`,
transform: `scale(${scale})`
height: `calc((100% - var(--base-bottom-panel-height, 30px) - ${36 + routeBarHeight}px) / ${scale})`,
transform: `scale(${scale})`,
marginTop: `${18 + routeBarHeight}px`
}
})
</script>
Expand All @@ -32,7 +40,7 @@ const siteCanvasStyle = computed(() => {
background: var(--ti-lowcode-breadcrumb-hover-bg);
position: absolute;
overflow: hidden;
margin: 18px 0;
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 @@ -180,7 +180,7 @@
},
"cols": 12,
"widget": {
"component": "InputConfigurator",
"component": "RouterSelectConfigurator",
"props": {}
}
},
Expand Down Expand Up @@ -630,9 +630,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'
120 changes: 120 additions & 0 deletions packages/canvas/route-bar/src/CanvasRouteBar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<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 } = useLayout().getDimension()
return { width }
})

const { pageSettingState, getAncestors, switchPageWithConfirm } = 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) => {
switchPageWithConfirm(route.id)
}
</script>

<style lang="less" scoped>
#canvas-route-bar {
position: absolute;
top: 18px;
height: 32px;
max-width: 100%;
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