|
@@ -1,92 +1,166 @@
|
|
|
+import { IconHeight, IconWidth } from "@/assets/icons";
|
|
|
import { CompSizeOpts } from "@/modules/editor/objects/DesignTemp/creates/CompSize";
|
|
|
+import { Layout } from "@/modules/editor/typings";
|
|
|
+import { css } from "@linaria/core";
|
|
|
import { InputNumber, Select } from "ant-design-vue";
|
|
|
-import { defineComponent } from "vue";
|
|
|
+import { AnyFun } from "queenjs/typing";
|
|
|
+import { defineComponent, reactive } from "vue";
|
|
|
import { any } from "vue-types";
|
|
|
+import { TipIcons } from "../../TipIcons";
|
|
|
|
|
|
const selectOptions = [
|
|
|
- { value: "px", label: "像素", options: { step: 1 } },
|
|
|
- { value: "%", label: "比例", options: { step: 0.1, max: 100, min: 0 } },
|
|
|
+ { value: "px", label: "PX", options: { step: 1 } },
|
|
|
+ { value: "%", label: "%", options: { step: 0.1 } },
|
|
|
];
|
|
|
|
|
|
export const Size = defineComponent({
|
|
|
props: {
|
|
|
- value: any<[number, number, string?, string?]>().def([0, 0]),
|
|
|
+ value: any<Layout["size"]>().def([0, 0]),
|
|
|
},
|
|
|
emits: ["change"],
|
|
|
setup(props, { emit }) {
|
|
|
const CompSizeOptsList = [CompSizeOpts.w, CompSizeOpts.h];
|
|
|
+ const state = reactive({
|
|
|
+ relateRatio: 0,
|
|
|
+ });
|
|
|
|
|
|
- function changeVal(unit: any, index: number, v: any) {
|
|
|
+ function changeVal(index: number, v: any) {
|
|
|
const { value } = props;
|
|
|
+ const unit = value[2]?.unit;
|
|
|
value[index] = parseFloat(v) || 0;
|
|
|
+
|
|
|
if (unit === "%") {
|
|
|
value[index] = CompSizeOptsList[index].getPxSize(
|
|
|
value[index] as number
|
|
|
);
|
|
|
}
|
|
|
+
|
|
|
+ if (state.relateRatio) {
|
|
|
+ const isChangeW = index === 0;
|
|
|
+ if (isChangeW) {
|
|
|
+ value[1] = value[0] / state.relateRatio;
|
|
|
+ } else {
|
|
|
+ value[0] = value[1] * state.relateRatio;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
emit("change", value);
|
|
|
}
|
|
|
|
|
|
- function changeUnit(index: number, unit: any) {
|
|
|
+ function changeUnit(unit: any) {
|
|
|
const { value } = props;
|
|
|
- value[index + 2] = unit;
|
|
|
+ if (!value[2]?.unit) {
|
|
|
+ value[2] = { unit };
|
|
|
+ } else {
|
|
|
+ value[2].unit = unit;
|
|
|
+ }
|
|
|
emit("change", value);
|
|
|
}
|
|
|
|
|
|
- function fmtVal(val: number, unit: string, index: number) {
|
|
|
+ function changeRelate() {
|
|
|
+ state.relateRatio = !state.relateRatio
|
|
|
+ ? props.value[0] / props.value[1]
|
|
|
+ : 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ function fmtVal(index: number) {
|
|
|
+ const unit = props.value[2]?.unit;
|
|
|
+ const val = props.value[index] as number;
|
|
|
switch (unit) {
|
|
|
- case "px":
|
|
|
- return val.toFixed(0);
|
|
|
case "%":
|
|
|
- return CompSizeOptsList[index].getVSize(val).toFixed(1);
|
|
|
+ return CompSizeOptsList[index].getVSize(val).toFixed(0);
|
|
|
default:
|
|
|
- return "";
|
|
|
+ return val.toFixed(0);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return () => {
|
|
|
- const values = props.value.slice(0, 2) as number[];
|
|
|
- const units = props.value.slice(2) as string[];
|
|
|
-
|
|
|
- return (
|
|
|
- <div class="flex space-x-10px">
|
|
|
- {values.map((value, i) => {
|
|
|
- const unit = units[i] || selectOptions[0].value;
|
|
|
- const inputOpts =
|
|
|
- selectOptions.find((d) => d.value === unit)?.options || {};
|
|
|
- return (
|
|
|
- <InputNumber
|
|
|
- key={i + unit}
|
|
|
- value={fmtVal(value as number, unit, i)}
|
|
|
- onChange={changeVal.bind(null, unit, i)}
|
|
|
- {...inputOpts}
|
|
|
- >
|
|
|
- {{
|
|
|
- addonBefore() {
|
|
|
- return (
|
|
|
- <span class="-mx-8px">
|
|
|
- {CompSizeOptsList[i].label}
|
|
|
- <Select
|
|
|
- value={unit}
|
|
|
- onChange={changeUnit.bind(null, i)}
|
|
|
- >
|
|
|
- {selectOptions.map((d) => {
|
|
|
- return (
|
|
|
- <Select.Option key={d.value}>
|
|
|
- {d.value === "%" ? CompSizeOptsList[i].vUnit : d.value}
|
|
|
- </Select.Option>
|
|
|
- );
|
|
|
- })}
|
|
|
- </Select>
|
|
|
- </span>
|
|
|
- );
|
|
|
- },
|
|
|
- }}
|
|
|
- </InputNumber>
|
|
|
- );
|
|
|
- })}
|
|
|
+ return () => (
|
|
|
+ <div class="space-y-10px flex-1">
|
|
|
+ <div class="flex justify-between">
|
|
|
+ <SizeInput
|
|
|
+ label="X"
|
|
|
+ icon={IconWidth}
|
|
|
+ value={fmtVal(0)}
|
|
|
+ onChange={(v) => changeVal(0, v)}
|
|
|
+ />
|
|
|
+ <TipIcons.Relate
|
|
|
+ class={[relateIconCls, state.relateRatio && "active"]}
|
|
|
+ onClick={changeRelate}
|
|
|
+ />
|
|
|
</div>
|
|
|
- );
|
|
|
- };
|
|
|
+ <div class="flex justify-between">
|
|
|
+ <SizeInput
|
|
|
+ label="Y"
|
|
|
+ icon={IconHeight}
|
|
|
+ value={fmtVal(1)}
|
|
|
+ onChange={(v) => changeVal(1, v)}
|
|
|
+ />
|
|
|
+ <Select
|
|
|
+ class={selUnitCls}
|
|
|
+ bordered={false}
|
|
|
+ value={props.value[2]?.unit || selectOptions[0].value}
|
|
|
+ onChange={(v) => changeUnit(v)}
|
|
|
+ >
|
|
|
+ {selectOptions.map((d) => {
|
|
|
+ return <Select.Option key={d.value}>{d.label}</Select.Option>;
|
|
|
+ })}
|
|
|
+ </Select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
},
|
|
|
});
|
|
|
+
|
|
|
+const SizeInput = (props: {
|
|
|
+ label: string;
|
|
|
+ icon: any;
|
|
|
+ value: string;
|
|
|
+ onChange: AnyFun;
|
|
|
+}) => {
|
|
|
+ const { label, icon, ...inputProps } = props;
|
|
|
+ return (
|
|
|
+ <div class={numberInputCls}>
|
|
|
+ <span class="pl-14px pr-1px text-14px">{label}</span>
|
|
|
+ <InputNumber class="flex-1" bordered={false} {...inputProps} />
|
|
|
+ <icon class="tipIcon" />
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+const numberInputCls = css`
|
|
|
+ @apply inline-flex items-center flex-1 w-0 mr-12px;
|
|
|
+ background-color: #303030;
|
|
|
+ border-radius: 4px;
|
|
|
+ overflow: hidden;
|
|
|
+
|
|
|
+ .tipIcon {
|
|
|
+ font-size: 24px;
|
|
|
+ padding: 3px 5px;
|
|
|
+ background-color: #373737;
|
|
|
+ }
|
|
|
+`;
|
|
|
+
|
|
|
+const relateIconCls = css`
|
|
|
+ padding: 3px 17px;
|
|
|
+ font-size: 24px;
|
|
|
+ border-radius: 4px;
|
|
|
+ background-color: #303030;
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ &.active {
|
|
|
+ background-color: rgba(234, 158, 64, 0.2);
|
|
|
+ color: #ea9e40;
|
|
|
+ }
|
|
|
+`;
|
|
|
+
|
|
|
+const selUnitCls = css`
|
|
|
+ width: 58px;
|
|
|
+ height: 30px;
|
|
|
+ border-radius: 4px;
|
|
|
+ background-color: #303030;
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ .ant-select-selector {
|
|
|
+ padding: 0 8px;
|
|
|
+ }
|
|
|
+`;
|