|
@@ -1,16 +1,22 @@
|
|
import {
|
|
import {
|
|
- IconLineHeight,
|
|
|
|
IconTextCenter,
|
|
IconTextCenter,
|
|
IconTextJustify,
|
|
IconTextJustify,
|
|
IconTextLeft,
|
|
IconTextLeft,
|
|
|
|
+ IconTextLetterSpacing,
|
|
|
|
+ IconTextLineHeight,
|
|
IconTextRight,
|
|
IconTextRight,
|
|
|
|
+ IconTextSize,
|
|
|
|
+ IconStrikethrough,
|
|
|
|
+ IconTextBold,
|
|
|
|
+ IconTextItalic,
|
|
|
|
+ IconTextUnderline,
|
|
} from "@/assets/icons";
|
|
} from "@/assets/icons";
|
|
import { css } from "@linaria/core";
|
|
import { css } from "@linaria/core";
|
|
-import { Button, Dropdown, InputNumber, Menu, Tooltip } from "ant-design-vue";
|
|
|
|
|
|
+import { Button, Input, InputNumber, Tooltip } from "ant-design-vue";
|
|
|
|
|
|
import Select from "@queenjs-modules/queditor/components/FormUI/Items/Select";
|
|
import Select from "@queenjs-modules/queditor/components/FormUI/Items/Select";
|
|
-import Pickr from "@simonwep/pickr";
|
|
|
|
import "@simonwep/pickr/dist/themes/nano.min.css";
|
|
import "@simonwep/pickr/dist/themes/nano.min.css";
|
|
|
|
+import _ from "lodash";
|
|
import { queenApi } from "queenjs";
|
|
import { queenApi } from "queenjs";
|
|
import {
|
|
import {
|
|
defineComponent,
|
|
defineComponent,
|
|
@@ -20,9 +26,16 @@ import {
|
|
ref,
|
|
ref,
|
|
watch,
|
|
watch,
|
|
} from "vue";
|
|
} from "vue";
|
|
-import { any, bool, string } from "vue-types";
|
|
|
|
-import _ from "lodash";
|
|
|
|
-
|
|
|
|
|
|
+import { any, bool, func, number, object, string } from "vue-types";
|
|
|
|
+import { useEditor } from "@/modules/editor";
|
|
|
|
+interface ColumnItem {
|
|
|
|
+ label?: string;
|
|
|
|
+ component?: ((...args: any[]) => any) | Record<string, any>;
|
|
|
|
+ dataIndex?: string;
|
|
|
|
+ props?: { [name: string]: any };
|
|
|
|
+ itemProps?: { [name: string]: any };
|
|
|
|
+ changeExtra?: (data: any) => any;
|
|
|
|
+}
|
|
// export const TextColor = defineComponent({
|
|
// export const TextColor = defineComponent({
|
|
// props: {
|
|
// props: {
|
|
// value: string().def("#666666"),
|
|
// value: string().def("#666666"),
|
|
@@ -192,86 +205,136 @@ export const AlignComp = defineComponent({
|
|
icon: <IconTextJustify />,
|
|
icon: <IconTextJustify />,
|
|
},
|
|
},
|
|
];
|
|
];
|
|
-
|
|
|
|
- const overlay = () => {
|
|
|
|
- return (
|
|
|
|
- <Menu>
|
|
|
|
- {aligns.map((e: any) => {
|
|
|
|
- return (
|
|
|
|
- <Menu.Item
|
|
|
|
|
|
+ return () => (
|
|
|
|
+ <div class={AlignCompWapper}>
|
|
|
|
+ {aligns.map((e: any) => {
|
|
|
|
+ return (
|
|
|
|
+ <Tooltip title={e.label} placement="top">
|
|
|
|
+ <Button
|
|
class={props.value == e.key ? currStyle : null}
|
|
class={props.value == e.key ? currStyle : null}
|
|
|
|
+ icon={e.icon}
|
|
|
|
+ type="text"
|
|
onClick={() => {
|
|
onClick={() => {
|
|
emit("change", e.key);
|
|
emit("change", e.key);
|
|
}}
|
|
}}
|
|
- >
|
|
|
|
- <Tooltip placement="right" title={e.label}>
|
|
|
|
- {e.icon}
|
|
|
|
- </Tooltip>
|
|
|
|
- </Menu.Item>
|
|
|
|
- );
|
|
|
|
- })}
|
|
|
|
- </Menu>
|
|
|
|
|
|
+ ></Button>
|
|
|
|
+ </Tooltip>
|
|
|
|
+ );
|
|
|
|
+ })}
|
|
|
|
+ </div>
|
|
|
|
+ );
|
|
|
|
+ },
|
|
|
|
+});
|
|
|
|
+export const LetterSpacingComp = defineComponent({
|
|
|
|
+ props: {
|
|
|
|
+ value: string().def("0"),
|
|
|
|
+ },
|
|
|
|
+ emits: ["change"],
|
|
|
|
+ setup(props, { emit }) {
|
|
|
|
+ return () => {
|
|
|
|
+ const value = parseFloat(props.value) || 0;
|
|
|
|
+ return (
|
|
|
|
+ <InputNumber
|
|
|
|
+ prefix={<IconTextLetterSpacing class="text-22px mr-6px" />}
|
|
|
|
+ defaultValue={0}
|
|
|
|
+ min={0}
|
|
|
|
+ max={100}
|
|
|
|
+ step={1}
|
|
|
|
+ value={value}
|
|
|
|
+ onChange={(value: any) => {
|
|
|
|
+ if (!value) {
|
|
|
|
+ emit("change", "0em");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ emit("change", value / 100 + "em");
|
|
|
|
+ }}
|
|
|
|
+ />
|
|
);
|
|
);
|
|
};
|
|
};
|
|
- const currIcon = (key: string) => {
|
|
|
|
- const item = aligns.find((e) => {
|
|
|
|
- return e.key == key;
|
|
|
|
- });
|
|
|
|
- return item ? item.icon : null;
|
|
|
|
- };
|
|
|
|
- return () => (
|
|
|
|
- <Dropdown
|
|
|
|
- overlay={overlay()}
|
|
|
|
- overlayClassName={"editor_toolbar_drop"}
|
|
|
|
- trigger={"click"}
|
|
|
|
- placement="bottom"
|
|
|
|
- >
|
|
|
|
- <Button type="text" icon={currIcon(props.value)}></Button>
|
|
|
|
- </Dropdown>
|
|
|
|
- );
|
|
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
|
|
export const LineHeightComp = defineComponent({
|
|
export const LineHeightComp = defineComponent({
|
|
props: {
|
|
props: {
|
|
- value: string().def("1.5"),
|
|
|
|
|
|
+ value: number().def(1.5),
|
|
},
|
|
},
|
|
emits: ["change"],
|
|
emits: ["change"],
|
|
setup(props, { emit }) {
|
|
setup(props, { emit }) {
|
|
- const options = [1, 1.5, 2, 2.5, 3];
|
|
|
|
-
|
|
|
|
- const overlay = () => {
|
|
|
|
|
|
+ return () => {
|
|
return (
|
|
return (
|
|
- <Menu>
|
|
|
|
- {options.map((e: any) => {
|
|
|
|
- return (
|
|
|
|
- <Menu.Item
|
|
|
|
- class={props.value == e ? currStyle : null}
|
|
|
|
- onClick={() => {
|
|
|
|
- emit("change", e);
|
|
|
|
- }}
|
|
|
|
- >
|
|
|
|
- {e}
|
|
|
|
- </Menu.Item>
|
|
|
|
- );
|
|
|
|
- })}
|
|
|
|
- </Menu>
|
|
|
|
|
|
+ <InputNumber
|
|
|
|
+ prefix={<IconTextLineHeight class="text-22px mr-6px" />}
|
|
|
|
+ defaultValue={1.5}
|
|
|
|
+ min={0.5}
|
|
|
|
+ max={3}
|
|
|
|
+ step={0.5}
|
|
|
|
+ value={props.value || 1.5}
|
|
|
|
+ onChange={(value: any) => {
|
|
|
|
+ if (!value) {
|
|
|
|
+ emit("change", 1.5);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ emit("change", value);
|
|
|
|
+ }}
|
|
|
|
+ />
|
|
);
|
|
);
|
|
};
|
|
};
|
|
-
|
|
|
|
|
|
+ },
|
|
|
|
+});
|
|
|
|
+export const FontStyleWapper = defineComponent({
|
|
|
|
+ props: {
|
|
|
|
+ editor: any(),
|
|
|
|
+ },
|
|
|
|
+ emits: ["change"],
|
|
|
|
+ setup(props, { emit }) {
|
|
|
|
+ const fontStyleColumns = [
|
|
|
|
+ {
|
|
|
|
+ label: "加粗",
|
|
|
|
+ dataIndex: "bold",
|
|
|
|
+ icon: <IconTextBold />,
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ label: "斜体",
|
|
|
|
+ dataIndex: "italic",
|
|
|
|
+ icon: <IconTextItalic />,
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ label: "下划线",
|
|
|
|
+ dataIndex: "underline",
|
|
|
|
+ icon: <IconTextUnderline />,
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ label: "删除线",
|
|
|
|
+ dataIndex: "strikethrough",
|
|
|
|
+ icon: <IconStrikethrough />,
|
|
|
|
+ },
|
|
|
|
+ ];
|
|
|
|
+ const changeVal = (e: any) => {
|
|
|
|
+ emit("change", e);
|
|
|
|
+ };
|
|
return () => (
|
|
return () => (
|
|
- <Dropdown
|
|
|
|
- overlay={overlay()}
|
|
|
|
- overlayClassName={"editor_toolbar_drop"}
|
|
|
|
- trigger={"click"}
|
|
|
|
- placement="bottom"
|
|
|
|
- >
|
|
|
|
- <Button type="text" icon={<IconLineHeight />}></Button>
|
|
|
|
- </Dropdown>
|
|
|
|
|
|
+ <div class={[FontStyleCompWapper]}>
|
|
|
|
+ {fontStyleColumns.map((e: any) => {
|
|
|
|
+ return (
|
|
|
|
+ <TextToolItem
|
|
|
|
+ key={e.dataIndex}
|
|
|
|
+ class={"!mr-0"}
|
|
|
|
+ column={{
|
|
|
|
+ label: e.label,
|
|
|
|
+ dataIndex: e.dataIndex,
|
|
|
|
+ component: (props) => (
|
|
|
|
+ <FontStyleComp icon={e.icon} {...props} />
|
|
|
|
+ ),
|
|
|
|
+ }}
|
|
|
|
+ editor={props.editor}
|
|
|
|
+ onChange={changeVal}
|
|
|
|
+ />
|
|
|
|
+ );
|
|
|
|
+ })}
|
|
|
|
+ </div>
|
|
);
|
|
);
|
|
},
|
|
},
|
|
});
|
|
});
|
|
-
|
|
|
|
export const FontStyleComp = defineComponent({
|
|
export const FontStyleComp = defineComponent({
|
|
props: {
|
|
props: {
|
|
icon: any(),
|
|
icon: any(),
|
|
@@ -282,14 +345,17 @@ export const FontStyleComp = defineComponent({
|
|
const triggerStyle = () => {
|
|
const triggerStyle = () => {
|
|
emit("change", !props.value);
|
|
emit("change", !props.value);
|
|
};
|
|
};
|
|
- return () => (
|
|
|
|
- <Button
|
|
|
|
- type="text"
|
|
|
|
- class={props.value ? currStyle : null}
|
|
|
|
- icon={props.icon}
|
|
|
|
- onClick={triggerStyle}
|
|
|
|
- ></Button>
|
|
|
|
- );
|
|
|
|
|
|
+ return () => {
|
|
|
|
+ console.log(props.value);
|
|
|
|
+ return (
|
|
|
|
+ <Button
|
|
|
|
+ type="text"
|
|
|
|
+ class={props.value ? currStyle : null}
|
|
|
|
+ icon={props.icon}
|
|
|
|
+ onClick={triggerStyle}
|
|
|
|
+ ></Button>
|
|
|
|
+ );
|
|
|
|
+ };
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
|
|
@@ -328,11 +394,16 @@ export const FontSize = defineComponent({
|
|
return () => {
|
|
return () => {
|
|
return (
|
|
return (
|
|
<InputNumber
|
|
<InputNumber
|
|
|
|
+ prefix={<IconTextSize class="text-22px mr-6px" />}
|
|
defaultValue={12}
|
|
defaultValue={12}
|
|
min={12}
|
|
min={12}
|
|
max={60}
|
|
max={60}
|
|
value={parseInt(props.value) || 12}
|
|
value={parseInt(props.value) || 12}
|
|
onChange={(value: any) => {
|
|
onChange={(value: any) => {
|
|
|
|
+ if (!value) {
|
|
|
|
+ emit("change", "12px");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
emit("change", value + "px");
|
|
emit("change", value + "px");
|
|
}}
|
|
}}
|
|
/>
|
|
/>
|
|
@@ -360,6 +431,90 @@ export const LinkButton = defineComponent({
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
|
|
|
|
+export const TextToolItem = defineComponent({
|
|
|
|
+ props: {
|
|
|
|
+ column: object<ColumnItem>(),
|
|
|
|
+ index: number(),
|
|
|
|
+ editor: any(),
|
|
|
|
+ onChange: func(),
|
|
|
|
+ },
|
|
|
|
+ setup(props) {
|
|
|
|
+ const state = reactive({
|
|
|
|
+ value: undefined,
|
|
|
|
+ });
|
|
|
|
+ function handleValueChange() {
|
|
|
|
+ const { column, editor } = props;
|
|
|
|
+ const command = editor ? editor.commands.get(column?.dataIndex) : "";
|
|
|
|
+ if (command) {
|
|
|
|
+ console.log("change==>", column?.dataIndex, state.value);
|
|
|
|
+ state.value = command.value;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ const initCommands = () => {
|
|
|
|
+ const { column, editor } = props;
|
|
|
|
+ const { controls } = useEditor();
|
|
|
|
+ const command = editor ? editor.commands.get(column?.dataIndex) : "";
|
|
|
|
+ console.log(column?.dataIndex, controls.textEditor);
|
|
|
|
+ if (command) {
|
|
|
|
+ state.value = command.value;
|
|
|
|
+
|
|
|
|
+ command.on("change:value", handleValueChange);
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+ onMounted(() => {
|
|
|
|
+ initCommands();
|
|
|
|
+ });
|
|
|
|
+ onUnmounted(() => {
|
|
|
|
+ const { column, editor } = props;
|
|
|
|
+ const command = editor ? editor.commands.get(column?.dataIndex) : "";
|
|
|
|
+ if (command) {
|
|
|
|
+ command.off("change:value", handleValueChange);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ const changeVal = (value: any, ...args: any[]) => {
|
|
|
|
+ const { column } = props;
|
|
|
|
+ let params = {
|
|
|
|
+ dataIndex: column?.dataIndex,
|
|
|
|
+ value: { value },
|
|
|
|
+ ...args,
|
|
|
|
+ };
|
|
|
|
+ if (column?.changeExtra) params = column.changeExtra?.(params);
|
|
|
|
+ props.onChange?.(params);
|
|
|
|
+ return params;
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ const component = props.column?.component || null;
|
|
|
|
+ return () => {
|
|
|
|
+ const { column, index } = props;
|
|
|
|
+ return (
|
|
|
|
+ <div
|
|
|
|
+ key={column?.dataIndex || "" + index}
|
|
|
|
+ class={formItemStyles}
|
|
|
|
+ {...column?.itemProps}
|
|
|
|
+ onClick={(e) => e.stopPropagation()}
|
|
|
|
+ >
|
|
|
|
+ {column?.label ? (
|
|
|
|
+ <Tooltip title={column.label} placement="top">
|
|
|
|
+ <component
|
|
|
|
+ value={state.value}
|
|
|
|
+ {...column.props}
|
|
|
|
+ onChange={changeVal}
|
|
|
|
+ />
|
|
|
|
+ </Tooltip>
|
|
|
|
+ ) : (
|
|
|
|
+ <component
|
|
|
|
+ value={state.value}
|
|
|
|
+ {...column?.props}
|
|
|
|
+ onChange={changeVal}
|
|
|
|
+ />
|
|
|
|
+ )}
|
|
|
|
+ </div>
|
|
|
|
+ );
|
|
|
|
+ };
|
|
|
|
+ },
|
|
|
|
+});
|
|
|
|
+
|
|
const currStyle = css`
|
|
const currStyle = css`
|
|
color: @inf-primary-color;
|
|
color: @inf-primary-color;
|
|
&:hover,
|
|
&:hover,
|
|
@@ -394,45 +549,48 @@ const ColorPicker = css`
|
|
border: none;
|
|
border: none;
|
|
visibility: hidden;
|
|
visibility: hidden;
|
|
}
|
|
}
|
|
- .pickr {
|
|
|
|
- width: 100%;
|
|
|
|
- height: 100%;
|
|
|
|
|
|
+`;
|
|
|
|
|
|
- .pcr-button {
|
|
|
|
- width: 100%;
|
|
|
|
- height: 100%;
|
|
|
|
- border: 1px solid transparent;
|
|
|
|
- }
|
|
|
|
- border-radius: 2px;
|
|
|
|
- input {
|
|
|
|
- &:focus,
|
|
|
|
- &.pcr-active {
|
|
|
|
- border-color: @inf-primary-color;
|
|
|
|
- box-shadow: 0 0 0 2px rgba(232, 139, 0, 0.2);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- button {
|
|
|
|
- &:focus,
|
|
|
|
- &.pcr-active {
|
|
|
|
- border-color: @inf-primary-color;
|
|
|
|
- box-shadow: 0 0 0 2px rgba(232, 139, 0, 0.2);
|
|
|
|
- }
|
|
|
|
|
|
+const AlignCompWapper = css`
|
|
|
|
+ display: flex;
|
|
|
|
+ .ant-btn {
|
|
|
|
+ flex: 1;
|
|
|
|
+ width: 100%;
|
|
|
|
+ line-height: 1;
|
|
|
|
+ .inficon {
|
|
|
|
+ font-size: 22px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- .pcr-app {
|
|
|
|
- input {
|
|
|
|
- &:focus,
|
|
|
|
- &.pcr-active {
|
|
|
|
- border-color: @inf-primary-color;
|
|
|
|
- box-shadow: 0 0 0 2px rgba(232, 139, 0, 0.2);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- button {
|
|
|
|
- &:focus,
|
|
|
|
- &.pcr-active {
|
|
|
|
- border-color: @inf-primary-color;
|
|
|
|
- box-shadow: 0 0 0 2px rgba(232, 139, 0, 0.2);
|
|
|
|
|
|
+`;
|
|
|
|
+const FontStyleCompWapper = css`
|
|
|
|
+ flex: 1;
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ margin-right: 12px;
|
|
|
|
+ border-radius: 2px;
|
|
|
|
+ & > div {
|
|
|
|
+ flex: 1;
|
|
|
|
+ border-radius: 0;
|
|
|
|
+ .ant-btn {
|
|
|
|
+ width: 100%;
|
|
|
|
+ line-height: 1;
|
|
|
|
+ .inficon {
|
|
|
|
+ font-size: 22px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
`;
|
|
|
|
+
|
|
|
|
+const formItemStyles = css`
|
|
|
|
+ height: 100%;
|
|
|
|
+ flex: 1;
|
|
|
|
+ margin-right: 12px;
|
|
|
|
+ background-color: #303030;
|
|
|
|
+ border-radius: 2px;
|
|
|
|
+ &:last-child {
|
|
|
|
+ margin-right: 0;
|
|
|
|
+ }
|
|
|
|
+ &.disabled {
|
|
|
|
+ cursor: not-allowed;
|
|
|
|
+ }
|
|
|
|
+`;
|