qinyan hai 1 ano
pai
achega
1e9dddf4b7

+ 38 - 14
src/modules/editor/components/CompUI/formItems/NewColorPicker/ColorLib.tsx

@@ -1,9 +1,9 @@
 import { Divider } from "ant-design-vue";
-import { defineComponent } from "vue";
+import { defineComponent, onMounted, reactive } from "vue";
+import { any, bool } from "vue-types";
 import ColorList, { gradientColorType } from "./ColorList";
-import { any } from "vue-types";
 
-const defaultColor = [
+const pureColors = [
   "#111111",
   "#545454",
   "#737373",
@@ -16,7 +16,7 @@ const defaultColor = [
   "#8354F5",
 ];
 
-const gradientColor: gradientColorType[] = [
+const gradientColors: gradientColorType[] = [
   {
     deg: 90,
     type: "linear",
@@ -72,10 +72,30 @@ const gradientColor: gradientColorType[] = [
 export default defineComponent({
   props: {
     value: any<string | gradientColorType>().isRequired,
+    showGradient: bool().def(true),
   },
   emits: ["change"],
   setup(props, { emit }) {
+    const state = reactive({
+      latestColors: [],
+    }) as any;
+
+    const selectColor = (data: any) => {
+      emit("change", data);
+    };
+
+    onMounted(() => {
+      const list = localStorage.getItem("latestColors");
+      let colors = list ? JSON.parse(list) : ["#fff"];
+      if (!props.showGradient) {
+        colors = colors.filter((d: any) => typeof d == "string");
+      }
+      colors.splice(10);
+      state.latestColors = colors;
+    });
+
     return () => {
+      const { showGradient } = props;
       return (
         <div class="w-280px px-5px py-10px rounded">
           <div class="flex items-center justify-between">
@@ -85,23 +105,27 @@ export default defineComponent({
           <div class="mt-15px mb-10px">近期使用</div>
           <ColorList
             value={props.value}
-            data={[]}
+            data={state.latestColors}
             onChange={(data) => emit("change", data)}
           />
           <Divider />
           <div class="mb-10px">纯色库</div>
           <ColorList
             value={props.value}
-            data={defaultColor}
-            onChange={(data) => emit("change", data)}
-          />
-          <Divider />
-          <div class="mb-10px">渐变</div>
-          <ColorList
-            value={props.value}
-            data={gradientColor}
-            onChange={(data) => emit("change", data)}
+            data={pureColors}
+            onChange={selectColor}
           />
+          {showGradient && (
+            <>
+              <Divider />
+              <div class="mb-10px">渐变</div>
+              <ColorList
+                value={props.value}
+                data={gradientColors}
+                onChange={selectColor}
+              />
+            </>
+          )}
         </div>
       );
     };

+ 71 - 37
src/modules/editor/components/CompUI/formItems/NewColorPicker/ColorList.tsx

@@ -1,7 +1,11 @@
 import { css, cx } from "@linaria/core";
-import { IconAddLine, IconClose } from "@queenjs/icons";
+import { IconClose } from "@queenjs/icons";
 import { defineComponent } from "vue";
-import { any, array, bool, number } from "vue-types";
+import { any, array, bool, number, string } from "vue-types";
+
+// radial-gradient(circle at 50% 50%, rgb(255, 255, 255), rgb(0, 253, 3) 100%);
+// radial-gradient(red 10px, yellow 30%, #1e90ff 50%);
+// linear-gradient(70deg, blue, pink);
 
 export type gradientColorType = {
   deg?: number;
@@ -10,9 +14,6 @@ export type gradientColorType = {
 };
 
 export function formatColor(item: string | gradientColorType) {
-  // radial-gradient(circle at 50% 50%, rgb(255, 255, 255), rgb(0, 253, 3) 100%);
-  // radial-gradient(red 10px, yellow 30%, #1e90ff 50%);
-  // linear-gradient(70deg, blue, pink);
   if (typeof item == "string") {
     return item;
   } else if (item.type == "radial") {
@@ -27,53 +28,68 @@ export default defineComponent({
     value: any<string | gradientColorType>().isRequired,
     data: array<string | gradientColorType>().isRequired,
     columns: number().def(5),
-    showAdd: bool().def(false),
     showDelete: bool().def(false),
     min: number().def(2),
   },
-  emits: ["change", "delete"],
+  emits: ["change", "delete", "add"],
   setup(props, { emit }) {
     return () => {
-      const { columns, value, showAdd, showDelete, min } = props;
+      const { columns, value, showDelete, min } = props;
       const list = props.data;
       const propsColor = formatColor(value);
       return (
         <div class={cx("grid gap-16px", `grid-cols-${columns}`)}>
           {list.map((item: string | gradientColorType, index: number) => {
-            // const thisColor = Color(color).object();
             const thisColor = formatColor(item);
             const active = thisColor === propsColor ? true : false;
-
             return (
-              <div class="relative" key={index}>
-                <div
-                  class={cx(
-                    itemStyles,
-                    "h-38px rounded cursor-pointer",
-                    columns == 4 ? "w-52px" : "w-38px",
-                    active && "active"
-                  )}
-                  style={{ background: thisColor }}
-                  onClick={() => emit("change", item)}
-                ></div>
-                {showDelete && list.length > min && (
-                  <IconClose
-                    class="absolute -right-8px -top-8px p-2px bg-dark-50 bg-opacity-80 rounded-1/2 text-light-50 cursor-pointer"
-                    onClick={() => emit("delete", index)}
-                  />
-                )}
-              </div>
+              <ColorItem
+                key={index}
+                color={thisColor}
+                columns={columns}
+                active={active}
+                onDelete={() => emit("delete", index)}
+                showDelete={showDelete && list.length > min}
+                onChange={() => emit("change", item)}
+              />
             );
           })}
-          {showAdd && (
-            <div
-              class="w-38px h-38px rounded cursor-pointer bg-[#3b3b3b] flex items-center justify-center transition hover:opacity-70"
-              onClick={() => {
-                //
-              }}
-            >
-              <IconAddLine class="text-22px text-dark-300" />
-            </div>
+        </div>
+      );
+    };
+  },
+});
+
+export const ColorItem = defineComponent({
+  props: {
+    color: string(),
+    active: bool(),
+    columns: number().def(5),
+    showDelete: bool().def(false),
+    min: number().def(2),
+  },
+  emits: ["change", "delete"],
+  setup(props, { emit }) {
+    return () => {
+      const { active, color, columns, showDelete } = props;
+      return (
+        <div class="relative group">
+          <div
+            class={cx(
+              "h-38px rounded-2px cursor-pointer overflow-hidden",
+              itemStyles,
+              active && "active",
+              columns == 4 ? "w-52px" : "w-38px"
+            )}
+            onClick={() => emit("change")}
+          >
+            <div class="h-full w-full" style={{ background: color }}></div>
+          </div>
+          {showDelete && (
+            <IconClose
+              class="absolute z-10 -right-8px -top-8px p-2px bg-dark-50 bg-opacity-80 rounded-1/2 text-light-50 cursor-pointer transition opacity-0 group-hover:opacity-100"
+              onClick={() => emit("delete")}
+            />
           )}
         </div>
       );
@@ -83,6 +99,24 @@ export default defineComponent({
 
 const itemStyles = css`
   position: relative;
+  background-color: #fff;
+  background-image: linear-gradient(
+      -45deg,
+      rgba(57, 76, 96, 0.15) 25%,
+      transparent 25%,
+      transparent 75%,
+      rgba(57, 76, 96, 0.15) 75%
+    ),
+    linear-gradient(
+      -45deg,
+      rgba(57, 76, 96, 0.15) 25%,
+      transparent 25%,
+      transparent 75%,
+      rgba(57, 76, 96, 0.15) 75%
+    );
+
+  background-position: 0 0, 6px 6px;
+  background-size: 12px 12px;
   &:before {
     border-radius: 4px;
     bottom: 0;

+ 97 - 18
src/modules/editor/components/CompUI/formItems/NewColorPicker/Panel.tsx

@@ -1,13 +1,15 @@
 import { css } from "@linaria/core";
-import { Divider, Tabs } from "ant-design-vue";
-import { computed, defineComponent, reactive, watch } from "vue";
-import { any } from "vue-types";
-import ColorList, { gradientColorType } from "./ColorList";
+import { IconAddLine } from "@queenjs/icons";
+import { Divider, Popover, Tabs } from "ant-design-vue";
+import { computed, defineComponent, onMounted, reactive, watch } from "vue";
+import { any, bool } from "vue-types";
+import ColorList, { ColorItem, gradientColorType } from "./ColorList";
 import Picker from "./Picker";
 
 export default defineComponent({
   props: {
     value: any<string | gradientColorType>().isRequired,
+    showGradient: bool().def(true),
   },
   emits: ["change"],
   setup(props, { emit }) {
@@ -16,18 +18,29 @@ export default defineComponent({
     });
 
     return () => {
-      const color =
-        typeof props.value == "string" ? props.value : props.value.colors[0];
+      const { showGradient } = props;
+      if (!showGradient) {
+        return (
+          <PureColor
+            value={props.value}
+            onChange={(data) => emit("change", data)}
+          />
+        );
+      }
       return (
         <div class="w-280px px-5px pb-10px ">
           <Tabs
-            class={tabStyles}
             centered
+            destroyInactiveTabPane
             activeKey={state.key}
+            class={tabStyles}
             onChange={(v: any) => (state.key = v)}
           >
             <Tabs.TabPane tab="纯色" key={"0"}>
-              <Picker value={color} onChange={(data) => emit("change", data)} />
+              <PureColor
+                value={props.value}
+                onChange={(data) => emit("change", data)}
+              />
             </Tabs.TabPane>
             <Tabs.TabPane tab="渐变" key={"1"}>
               <MutiColor
@@ -42,6 +55,25 @@ export default defineComponent({
   },
 });
 
+const PureColor = defineComponent({
+  props: {
+    value: any<string | gradientColorType>().isRequired,
+  },
+  emits: ["change"],
+  setup(props, { emit }) {
+    onMounted(() => {
+      if (typeof props.value !== "string") {
+        emit("change", props.value.colors[0]);
+      }
+    });
+    return () => {
+      const color =
+        typeof props.value == "string" ? props.value : props.value.colors[0];
+      return <Picker value={color} onChange={(data) => emit("change", data)} />;
+    };
+  },
+});
+
 const MutiColor = defineComponent({
   props: {
     value: any<string | gradientColorType>().isRequired,
@@ -71,6 +103,30 @@ const MutiColor = defineComponent({
       return colors;
     }
 
+    const deleteColor = (index: number) => {
+      state.colors.splice(index, 1);
+    };
+
+    const addColor = () => {
+      state.colors.push(state.colors[0]);
+      setTimeout(() => {
+        const elements = document.querySelectorAll(".jsColorItem");
+        const element = elements[elements.length - 1];
+        // @ts-ignore
+        element.click();
+      }, 0);
+    };
+
+    const changeColor = (value: any, index: number) => {
+      state.colors[index] = value;
+    };
+
+    onMounted(() => {
+      if (typeof props.value == "string") {
+        emit("change", state.gradientColors[0]);
+      }
+    });
+
     watch(
       () => props.value,
       () => (state.colors = getColors())
@@ -80,16 +136,39 @@ const MutiColor = defineComponent({
       return (
         <div>
           <div class="mb-10px">渐变色</div>
-          <ColorList
-            value={props.value}
-            data={state.colors}
-            showAdd
-            showDelete
-            min={2}
-            onDelete={(index) => {
-              state.colors.splice(index, 1);
-            }}
-          />
+          <div class="grid gap-16px grid-cols-5 mr-5px">
+            {state.colors.map((d, i) => {
+              return (
+                <Popover
+                  key={i}
+                  content={
+                    <Picker
+                      value={d}
+                      onChange={(value) => changeColor(value, i)}
+                    />
+                  }
+                  placement="bottomRight"
+                  // visible={libVisible}
+                  trigger="click"
+                >
+                  <ColorItem
+                    class="jsColorItem"
+                    color={d}
+                    showDelete={state.colors.length > 2}
+                    onDelete={() => deleteColor(i)}
+                  />
+                </Popover>
+              );
+            })}
+            {state.colors.length <= 9 && (
+              <div
+                class="w-38px h-38px rounded cursor-pointer bg-[#3b3b3b] flex items-center justify-center transition hover:opacity-70"
+                onClick={addColor}
+              >
+                <IconAddLine class="text-22px text-dark-300" />
+              </div>
+            )}
+          </div>
           <Divider />
           <div class="mb-10px">风格</div>
           <ColorList

+ 67 - 20
src/modules/editor/components/CompUI/formItems/NewColorPicker/Picker.tsx

@@ -2,20 +2,36 @@ import { IconPicker } from "@/assets/icons";
 import iro from "@jaames/iro";
 import { css } from "@linaria/core";
 import { Input } from "ant-design-vue";
-import { defineComponent, onMounted } from "vue";
+import Color from "color";
+import { nanoid } from "nanoid";
+import { defineComponent, nextTick, onMounted, reactive, ref } from "vue";
 import { string } from "vue-types";
 
+declare global {
+  interface Window {
+    EyeDropper?: any;
+  }
+}
+
 export default defineComponent({
   props: {
-    value: string().isRequired,
+    value: string().def("#fff"),
   },
   emits: ["change"],
   setup(props, { emit }) {
-    let pickr: any = null;
+    const containerId = `id_${nanoid(5)}`;
+    const pickr = ref<any>(null);
+
+    const state = reactive({
+      showPicker: false,
+    });
 
     function initPicker() {
+      if (window.EyeDropper) state.showPicker = true;
+      const element = document.querySelector(`.${containerId}`);
+      if (!element) return;
       // @ts-ignore
-      pickr = new iro.ColorPicker("#boxPicker", {
+      pickr.value = new iro.ColorPicker(element, {
         width: 270,
         boxHeight: 150,
         color: props.value,
@@ -46,19 +62,63 @@ export default defineComponent({
         ],
       });
 
-      pickr.on("color:change", function (color: any) {
-        console.log(color.hex8String);
+      pickr.value.on("color:change", function (color: any) {
+        if (color.alpha == 1) {
+          emit("change", color.hexString);
+          return;
+        }
         emit("change", color.hex8String);
       });
     }
 
     onMounted(() => {
-      initPicker();
+      nextTick(() => {
+        initPicker();
+      });
     });
 
+    function pickColor() {
+      if (!window.EyeDropper) {
+        return;
+      }
+      const eyeDropper = new window.EyeDropper();
+      eyeDropper
+        .open()
+        .then((result: any) => {
+          emit("change", result);
+        })
+        .catch((e: any) => {
+          console.log("e: ", e);
+        });
+    }
+
     return () => {
+      const colorObj = Color(props.value);
+      const opacity = (colorObj.alpha() * 100).toFixed(0) + "%";
+
       return (
         <div class={styles}>
+          <div class={containerId}></div>
+          <div class="mt-15px flex items-center justify-between">
+            <Input
+              readonly
+              value={colorObj.hex()}
+              class="flex-1 bg-dark-300 h-36px hover:bg-dark-300 text-center"
+              bordered={false}
+            />
+            <Input
+              readonly
+              value={opacity}
+              class="w-60px ml-10px bg-dark-300 h-36px hover:bg-dark-300 text-center"
+              bordered={false}
+            />
+            {state.showPicker && (
+              <IconPicker
+                class="ml-10px text-36px bg-dark-300 rounded-2px transition cursor-pointer !hidden hover:opacity-60"
+                onClick={pickColor}
+              />
+            )}
+          </div>
           <svg style="display:none;">
             <circle
               fill="#fff"
@@ -70,16 +130,6 @@ export default defineComponent({
               // stroke="#fff"
             ></circle>
           </svg>
-          <div class="ColorPicker" id="boxPicker"></div>
-          <div class="mt-15px flex items-center justify-between">
-            <Input
-              readonly
-              value="#fff"
-              class="mr-10px bg-dark-300 h-36px"
-              bordered={false}
-            />
-            <IconPicker class="text-36px bg-dark-300 rounded-2px" />
-          </div>
         </div>
       );
     };
@@ -90,7 +140,4 @@ const styles = css`
   .IroBox {
     border-radius: 6px !important;
   }
-  /* .IroHandle {
-    box-shadow: 0 0 3px #f00;
-  } */
 `;

+ 73 - 15
src/modules/editor/components/CompUI/formItems/NewColorPicker/index.tsx

@@ -1,7 +1,8 @@
 import { IconPalette } from "@/assets/icons";
+import { css } from "@linaria/core";
 import { Popover } from "ant-design-vue";
 import { defineComponent, reactive } from "vue";
-import { any } from "vue-types";
+import { any, bool } from "vue-types";
 import ColorLib from "./ColorLib";
 import { formatColor, gradientColorType } from "./ColorList";
 import Panel from "./Panel";
@@ -9,43 +10,77 @@ import Panel from "./Panel";
 export default defineComponent({
   props: {
     value: any<string | gradientColorType>(),
+    showGradient: bool().def(true),
   },
   emits: ["change"],
   setup(props, { emit }) {
     // @ts-ignore
     const state = reactive({
-      color: props.value || "#ffffffff",
-      libVisible: false,
-      pickerVisible: true,
+      color: props.value || "#ffffff",
     });
 
     function changeValue(data: any) {
-      console.log("data: ", data);
       state.color = data;
       emit("change", data);
     }
 
+    function storeColors() {
+      const list = localStorage.getItem("latestColors");
+      let colors = list ? JSON.parse(list) : ["#fff"];
+      const index = colors.findIndex(
+        (d: any) => formatColor(props.value || "") == formatColor(d)
+      );
+      if (index !== -1) return;
+      colors.unshift(props.value);
+      colors.splice(10);
+      localStorage.setItem("latestColors", JSON.stringify(colors));
+    }
+
     return () => {
-      const { color, libVisible, pickerVisible } = state;
+      const { color } = state;
 
       return (
         <div class="space-x-10px flex">
           <Popover
-            content={<ColorLib value={color} onChange={changeValue} />}
-            placement="bottomRight"
-            // visible={libVisible}
+            // visible={true}
+            color="#303030"
+            destroyTooltipOnHide
             trigger="click"
+            placement="bottomRight"
+            content={
+              <ColorLib
+                showGradient={props.showGradient}
+                value={color}
+                onChange={changeValue}
+              />
+            }
+            onVisibleChange={(v) => {
+              if (!v) storeColors();
+            }}
           >
-            <div
-              class="w-30px h-30px rounded cursor-pointer"
-              style={{ background: formatColor(color) }}
-            ></div>
+            <div class={colorItem}>
+              <div
+                class="w-30px h-30px cursor-pointer"
+                style={{ background: formatColor(color) }}
+              ></div>
+            </div>
           </Popover>
           <Popover
+            // visible={true}
+            color="#303030"
+            destroyTooltipOnHide
             trigger="click"
-            content={<Panel value={color} onChange={changeValue} />}
             placement="bottomRight"
-            // visible={pickerVisible}
+            content={
+              <Panel
+                showGradient={props.showGradient}
+                onChange={changeValue}
+                value={color}
+              />
+            }
+            onVisibleChange={(v) => {
+              if (!v) storeColors();
+            }}
           >
             <IconPalette class="rounded bg-[#303030] text-30px text-light-50 cursor-pointer" />
           </Popover>
@@ -54,3 +89,26 @@ export default defineComponent({
     };
   },
 });
+
+const colorItem = css`
+  background-color: #fff;
+  background-image: linear-gradient(
+      -45deg,
+      rgba(57, 76, 96, 0.15) 25%,
+      transparent 25%,
+      transparent 75%,
+      rgba(57, 76, 96, 0.15) 75%
+    ),
+    linear-gradient(
+      -45deg,
+      rgba(57, 76, 96, 0.15) 25%,
+      transparent 25%,
+      transparent 75%,
+      rgba(57, 76, 96, 0.15) 75%
+    );
+
+  background-position: 0 0, 6px 6px;
+  background-size: 12px 12px;
+  border-radius: 2px;
+  overflow: hidden;
+`;