CompTree.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import { TreeToolbars } from "@/modules/editor/objects/Toolbars";
  2. import { css } from "@linaria/core";
  3. import { Image } from "@queenjs/ui";
  4. import { useReactive } from "@queenjs/use";
  5. import { Tree } from "ant-design-vue";
  6. import { defineComponent, effect } from "vue";
  7. import { string } from "vue-types";
  8. import { useEditor } from "../../../..";
  9. import { DesignComp } from "../../../../objects/DesignTemp/DesignComp";
  10. type TreeItem = {
  11. key: string;
  12. title: string;
  13. value: string;
  14. children: TreeItem[];
  15. };
  16. export const CompTree = defineComponent({
  17. setup() {
  18. const { store, actions, helper, controls } = useEditor();
  19. const { compUICtrl } = controls;
  20. const state = useReactive(() => ({
  21. expandedKeys: [] as string[],
  22. treeData() {
  23. const rootComp = helper.findRootComp();
  24. function getCompChildren(ids: string[]): TreeItem[] {
  25. return ids.map((id) => {
  26. const comp = helper.findComp(id) as DesignComp;
  27. return {
  28. key: comp.id,
  29. title:
  30. comp.title ||
  31. compUICtrl.state.components.get(comp.compKey)?.name ||
  32. "未命名",
  33. value: comp.id,
  34. children: getCompChildren(comp.getChildIds()),
  35. };
  36. });
  37. }
  38. return getCompChildren(rootComp?.id ? [rootComp.id] : []);
  39. },
  40. }));
  41. effect(() => {
  42. state.expandedKeys = helper
  43. .getCompTrees(store.currCompId)
  44. .map((comp) => comp.id);
  45. });
  46. return () => (
  47. <Tree
  48. class={treeStyle}
  49. treeData={state.treeData}
  50. v-model={[state.expandedKeys, "expandedKeys"]}
  51. selectedKeys={[store.currCompId]}
  52. blockNode={true}
  53. onSelect={(ids) =>
  54. actions.pickComp(
  55. (ids[0] as string) || state.expandedKeys.at(-2) || "root"
  56. )
  57. }
  58. >
  59. {{
  60. title: (data: any) => {
  61. return <CompNode title={data.title} id={data.key} />;
  62. },
  63. }}
  64. </Tree>
  65. );
  66. },
  67. });
  68. const CompNode = defineComponent({
  69. props: {
  70. id: string().isRequired,
  71. title: string().isRequired,
  72. },
  73. setup(props) {
  74. const editor = useEditor();
  75. const comp = editor.helper.findComp(props.id);
  76. return () => {
  77. if (!comp) return;
  78. const compOpts = editor.controls.compUICtrl.state.components.get(
  79. comp.compKey
  80. );
  81. const actions = TreeToolbars[comp.compKey] || TreeToolbars.default;
  82. const thumbnail =
  83. comp.compKey === "Image"
  84. ? comp.value.url
  85. : comp.thumbnail || compOpts?.thumbnail;
  86. return (
  87. <div class={nodeStyle}>
  88. <Image src={thumbnail} size={240} />
  89. <span class="w-0 flex-1 truncate">{props.title}</span>
  90. <span class="space-x-4px">
  91. {actions.map((action) =>
  92. action.getVisible.call(editor, comp) ? (
  93. <action.component
  94. class="p-4px"
  95. key={comp.id}
  96. value={action.getValue?.(comp)}
  97. onClick={(e: MouseEvent) => {
  98. e.stopPropagation();
  99. action.onClick.call(editor, comp);
  100. }}
  101. />
  102. ) : null
  103. )}
  104. </span>
  105. </div>
  106. );
  107. };
  108. },
  109. });
  110. const treeStyle = css`
  111. .ant-tree-switcher {
  112. display: flex;
  113. justify-content: center;
  114. align-items: center;
  115. }
  116. `;
  117. const nodeStyle = css`
  118. display: flex;
  119. align-items: center;
  120. padding: 6px;
  121. @apply rounded;
  122. > img {
  123. width: 24px;
  124. height: 24px;
  125. margin-right: 6px;
  126. object-fit: contain;
  127. }
  128. `;