View.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import { css } from "@linaria/core";
  2. import { omit, upperFirst } from "lodash";
  3. import { defineComponent } from "vue";
  4. import { string } from "vue-types";
  5. import { useEditor } from "../../..";
  6. import { DesignComp } from "../../../defines/DesignTemp/DesignComp";
  7. export const View = defineComponent({
  8. props: {
  9. compId: string(),
  10. },
  11. emits: ["dblclick"],
  12. setup(props, { slots, emit }) {
  13. const { store, actions, helper } = useEditor();
  14. const comp =
  15. (props.compId && store.designCompMap.get(props.compId)) ||
  16. new DesignComp();
  17. function createStyle(): any {
  18. const style: any = {};
  19. const { textAlign, margin, zIndex } = comp.layout || {};
  20. if (textAlign) {
  21. style.textAlign = textAlign;
  22. }
  23. // if (offsetY) {
  24. // style[`margin` + ((offsetY as number) > 0 ? "Top" : "Bottom")] =
  25. // helper.designToNaturalSize(Math.abs(offsetY as number) * -1);
  26. // }
  27. if (zIndex) {
  28. style["zIndex"] = zIndex;
  29. }
  30. if (margin) {
  31. style.margin = margin;
  32. }
  33. return style;
  34. }
  35. function createContentStyle() {
  36. const style: any = {};
  37. const { background, layout } = comp;
  38. const [w, h] = (layout?.size as number[]) || [];
  39. if (background) {
  40. Object.entries(background).forEach(([key, value]) => {
  41. if (key === "image") {
  42. value = `url(${value})`;
  43. }
  44. style["background" + upperFirst(key)] = value;
  45. });
  46. }
  47. if (layout?.padding) {
  48. style.padding = layout.padding;
  49. }
  50. if (w) style["width"] = helper.designToNaturalSize(w);
  51. if (h) style["height"] = helper.designToNaturalSize(h);
  52. // if (layout?.offsetX) {
  53. // style["marginLeft"] = helper.designToNaturalSize(
  54. // layout.offsetX as number
  55. // );
  56. // }
  57. return style;
  58. }
  59. return () => {
  60. const isComp = !!props.compId;
  61. const isSelected = isComp && store.currCompId === props.compId;
  62. const bgOpts = Object.values(omit(comp.background, ["image", "color"]));
  63. const bgClasses = bgOpts.length ? `bg-${bgOpts.join(" bg-")}` : "";
  64. return isComp ? (
  65. <div
  66. class={[
  67. viewStyle,
  68. store.isEditMode && "view_editing",
  69. store.isEditMode && isSelected && "view_selected",
  70. bgClasses,
  71. ]}
  72. style={createStyle()}
  73. onClick={(e) => {
  74. e.stopPropagation();
  75. if (isComp && !isSelected) {
  76. actions.pickComp(props.compId as string);
  77. }
  78. }}
  79. onDblclick={() => emit("dblclick")}
  80. >
  81. <div class="view_content" style={createContentStyle()}>
  82. {slots.default?.()}
  83. </div>
  84. </div>
  85. ) : (
  86. <div class="view_inside" onDblclick={() => emit("dblclick")}>
  87. {slots.default?.()}
  88. </div>
  89. );
  90. };
  91. },
  92. });
  93. const viewStyle = css`
  94. position: relative;
  95. font-size: 0;
  96. &.view_editing {
  97. .view_content {
  98. &:hover {
  99. outline: 1px dashed @inf-primary-color;
  100. }
  101. }
  102. .view_inside:hover {
  103. outline: 1px dashed @inf-primary-color;
  104. outline-offset: -1px;
  105. }
  106. }
  107. .view_content {
  108. display: inline-block;
  109. width: 100%;
  110. height: 100%;
  111. background: no-repeat center / cover;
  112. }
  113. &.view_selected {
  114. > .view_content {
  115. outline: 1px solid @inf-primary-color;
  116. }
  117. }
  118. .view_inside {
  119. position: relative;
  120. }
  121. .view_content {
  122. overflow: hidden;
  123. }
  124. `;