瀏覽代碼

getting closer

Jimmy Chion 3 年之前
父節點
當前提交
ff355ff956

+ 6 - 6
src/components/CodeBlocks/Css.tsx

@@ -1,17 +1,17 @@
 import { Form, Switch } from 'antd';
 import hljs from 'highlight.js/lib/core';
 import React from 'react';
-import shallow from 'zustand/shallow';
 import { rgbToString } from './Output';
 import { SectionTitle } from './subcomponents';
 import { GradientPicker } from '~/components/GradientPicker';
 import { AnyGradientType, useInputStore } from '~/components/store';
 
 export const CssControls: React.FC = () => {
-  const [cssProps, filterProps] = useInputStore(
-    (state) => [state.cssProps, state.filterProps],
-    shallow
-  );
+  const [cssProps, setCssProps, filterProps] = useInputStore((state) => [
+    state.cssProps,
+    state.setCssProps,
+    state.filterProps,
+  ]);
   const { brightness, contrast } = filterProps;
   const { gradients, showTransparency } = cssProps;
 
@@ -48,7 +48,7 @@ export const CssControls: React.FC = () => {
             size="small"
             checked={showTransparency}
             onChange={(e) => {
-              console.log(e);
+              setCssProps({ ...cssProps, showTransparency: e });
             }}
           />
         </Form.Item>

+ 22 - 11
src/components/CodeBlocks/Filter.tsx

@@ -12,13 +12,16 @@ export const FilterControls: React.FC = () => {
     (state) => [state.svgProps, state.cssProps, state.filterProps, state.setFilterProps],
     shallow
   );
-  const { contrast, brightness } = filterProps;
+  const { contrast, brightness, invert } = filterProps;
   const [inlineSvg, setInlineSvg] = useState(false);
   const { size, baseFrequency, numOctaves } = svgProps;
 
   const { gradients } = cssProps;
-  const firstGradient = gradients[0];
-  const gradientFirstParam = getGradientFirstParam(firstGradient);
+  const gradientsString = gradients.map((grad) => {
+    return `${grad.type}-gradient(${getGradientFirstParam(grad)}, ${rgbToString(
+      grad.stops[0].color
+    )}, ${rgbToString(grad.stops[1].color)})`;
+  });
 
   const cleanSvgString = `<svg viewBox='0 0 ${size} ${size}' xmlns='http://www.w3.org/2000/svg'><filter id='noiseFilter'><feTurbulence type='fractalNoise' baseFrequency='${baseFrequency}' numOctaves='${numOctaves}' stitchTiles='stitch'/></filter><rect width='100%' height='100%' filter='url(#noiseFilter)'/></svg>`;
   const inlineSvgString = `url("data:image/svg+xml,${cleanSvgString.replace(
@@ -29,12 +32,10 @@ export const FilterControls: React.FC = () => {
 {
   width: 250px;
   height: 250px;
-  background: ${firstGradient.type}-gradient(${gradientFirstParam}, ${rgbToString(
-    firstGradient.stops[0].color
-  )}, ${rgbToString(firstGradient.stops[1].color)}), ${
+  background: ${gradientsString.join(' ')}, ${
     inlineSvg ? inlineSvgString : 'url(/👆/that/noise.svg)'
   };
-  filter: contrast(${contrast}%) brightness(${brightness}%);
+  filter: contrast(${contrast}%) brightness(${brightness}%)${invert ? ' invert(100%)' : ''};
 }
   `;
 
@@ -59,9 +60,8 @@ export const FilterControls: React.FC = () => {
           tipFormatter={(v) => `${v}%`}
           onChange={(val: number) =>
             setFilterProps({
-              brightness,
+              ...filterProps,
               contrast: val,
-              inlineSvg,
             })
           }
           value={typeof contrast === 'number' ? contrast : 10}
@@ -75,13 +75,24 @@ export const FilterControls: React.FC = () => {
           tipFormatter={(v) => `${v}%`}
           onChange={(val: number) =>
             setFilterProps({
+              ...filterProps,
               brightness: val,
-              contrast,
-              inlineSvg,
             })
           }
           value={typeof brightness === 'number' ? brightness : 0}
         />
+        <Form.Item label="Invert">
+          <Switch
+            size="small"
+            checked={invert}
+            onChange={(v) =>
+              setFilterProps({
+                ...filterProps,
+                invert: v,
+              })
+            }
+          />
+        </Form.Item>
         <Form.Item label="Inline the SVG">
           <Switch size="small" checked={inlineSvg} onChange={(e) => setInlineSvg(e)} />
         </Form.Item>

+ 16 - 18
src/components/CodeBlocks/Output.tsx

@@ -1,7 +1,6 @@
 import { getGradientFirstParam } from '.';
 import React from 'react';
 import styled from 'styled-components';
-import shallow from 'zustand/shallow';
 import { breakpoints } from '~/components/layout';
 import { ColorType, useInputStore } from '~/components/store';
 
@@ -10,15 +9,14 @@ export const symbols = /[\r\n%#()<>?[\\\]^`{|}]/g;
 export const rgbToString = ({ r, g, b, a }: ColorType) => `rgba(${r},${g},${b},${a})`;
 
 const Output: React.FC = () => {
-  const [svgProps, cssProps, filterProps] = useInputStore(
-    (state) => [state.svgProps, state.cssProps, state.filterProps],
-    shallow
-  );
+  const [svgProps, cssProps, filterProps] = useInputStore((state) => [
+    state.svgProps,
+    state.cssProps,
+    state.filterProps,
+  ]);
   const { size, baseFrequency, numOctaves } = svgProps;
   const { gradients, showTransparency } = cssProps;
-  const { brightness, contrast } = filterProps;
-  const firstGradient = gradients[0];
-  const gradientFirstParam = getGradientFirstParam(firstGradient);
+  const { brightness, contrast, invert } = filterProps;
 
   const svgString = `<!-- svg: first layer -->
 <svg viewBox='0 0 ${size} ${size}' xmlns='http://www.w3.org/2000/svg'>
@@ -33,28 +31,28 @@ const Output: React.FC = () => {
   <rect width='100%' height='100%' filter='url(#noiseFilter)'/>
 </svg>`;
 
+  const gradientsString = gradients.map((grad) => {
+    return `${grad.type}-gradient(${getGradientFirstParam(grad)}, ${rgbToString(
+      grad.stops[0].color
+    )}, ${rgbToString(grad.stops[1].color)})`;
+  });
+
   const gradientCss = `/* css gradient: second layer */
 {
   width: 250px;
   height: 250px;
-  background: 
-    ${firstGradient.type}-gradient(${gradientFirstParam}, 
-      ${rgbToString(firstGradient.stops[0].color)}, ${rgbToString(firstGradient.stops[1].color)})${
-    showTransparency ? ', url(/checkers.png)' : ''
-  };
-  /* filter: contrast(${contrast}%) brightness(${brightness}%); */
+  background: ${gradientsString.join(' ')} ${showTransparency ? ', url(/checkers.png)' : ''};
+  /* filter: contrast(${contrast}%) brightness(${brightness}%)${invert ? ' invert(100%)' : ''}; */
 }`;
 
   const liveCss = `
 width: 250px;
 height: 250px;
-background: ${firstGradient.type}-gradient(${gradientFirstParam}, ${rgbToString(
-    firstGradient.stops[0].color
-  )}, ${rgbToString(firstGradient.stops[1].color)}), url("data:image/svg+xml,${svgString.replace(
+background: ${gradientsString.join(' ')}, url("data:image/svg+xml,${svgString.replace(
     symbols,
     encodeURIComponent
   )}");
-filter: contrast(${contrast}%) brightness(${brightness}%);
+filter: contrast(${contrast}%) brightness(${brightness}%)${invert ? ' invert(100%)' : ''};
 `;
 
   return (

+ 27 - 0
src/components/GradientPicker/GradientPicker.tsx

@@ -0,0 +1,27 @@
+import { PlusOutlined } from '@ant-design/icons';
+import { Button } from 'antd';
+import { useInputStore, AnyGradientType } from '../store';
+import { GradientRow } from './GradientRow';
+
+export const GradientPicker: React.FC = () => {
+  const [cssProps, setCssProps] = useInputStore((state) => [state.cssProps, state.setCssProps]);
+
+  const updateStateOfSelf = (index: number, newData: AnyGradientType) => {
+    setCssProps({ ...cssProps, gradients: cssProps.gradients.splice(index, 1, newData) });
+  };
+  const gradientInterface = cssProps.gradients.map((grad, i) => (
+    <GradientRow
+      key={`${i}` + grad.type + `${grad.stops[0].color.r}`}
+      gradient={grad}
+      updateSelf={updateStateOfSelf}
+      selfIndex={i}
+    />
+  ));
+
+  return (
+    <div>
+      {gradientInterface}
+      <Button icon={<PlusOutlined />}>Add gradient</Button>
+    </div>
+  );
+};

+ 11 - 18
src/components/GradientPicker/GradientRow.tsx

@@ -5,7 +5,7 @@ import styled from 'styled-components';
 import { Row } from '../layout';
 import { ColorPicker, ChromePickerColor } from './ColorPicker';
 import { SliderInput } from '~/components/CodeBlocks/subcomponents';
-import { AnyGradientType } from '~/components/store';
+import { AnyGradientType, ColorStopType } from '~/components/store';
 
 interface IGradientRow {
   gradient: AnyGradientType;
@@ -14,30 +14,23 @@ interface IGradientRow {
 }
 export const GradientRow: React.FC<IGradientRow> = ({ gradient, selfIndex, updateSelf }) => {
   const { type: gradientType, isVisible, stops } = gradient;
-  // const [gradientType, setGradientType] = useState<string>('linear');
-  // const [isVisible, setIsVisible] = useState<boolean>(true);
-  // const [colors, setColors] = useState<ColorStopType[]>([
-  //   { color: { r: 0, g: 255, b: 255, a: 1 }, offset: 0 },
-  //   { color: { r: 0, g: 0, b: 0, a: 0 }, offset: 1.0 },
-  // ]);
-  // const [angle, setAngle] = useState<number>(0);
-  // const [posX, setPosX] = useState<number>(50);
-  // const [posY, setPosY] = useState<number>(50);
-  const updateProp = (key: string, value: any) => {
+
+  const updateProp = (key: string, value: string | boolean | ColorStopType[] | number) => {
     const newGradient = gradient;
     newGradient[key] = value;
     updateSelf(selfIndex, newGradient);
   };
+
   return (
     <Form>
       <Row>
-        <VisibilityIcon onClick={() => setIsVisible((v) => !v)}>
+        <VisibilityIcon onClick={() => updateProp('isVisible', !isVisible)}>
           {isVisible ? <EyeOutlined /> : <EyeInvisibleOutlined />}
         </VisibilityIcon>
         <Form.Item>
           <Select
             value={gradientType}
-            onChange={(v: string) => setGradientType(v)}
+            onChange={(v: string) => updateProp('type', v)}
             style={{ width: 130 }}
           >
             <Select.Option value="linear">linear</Select.Option>
@@ -50,14 +43,14 @@ export const GradientRow: React.FC<IGradientRow> = ({ gradient, selfIndex, updat
           color={stops[0].color}
           style={{ padding: 0 }}
           onChange={(c: ChromePickerColor) =>
-            setColors((colors) => [{ color: c.rgb, offset: 1 }, stops[1]])
+            updateProp('stops', [{ color: c.rgb, offset: 1 }, stops[1]])
           }
         />
         <ColorPicker
           label="Color 2"
           color={stops[stops.length - 1].color}
           onChange={(c: ChromePickerColor) =>
-            setColors((colors) => [stops[0], { color: c.rgb, offset: 1 }])
+            updateProp('stops', [stops[0], { color: c.rgb, offset: 1 }])
           }
         />
       </Row>
@@ -69,7 +62,7 @@ export const GradientRow: React.FC<IGradientRow> = ({ gradient, selfIndex, updat
           min={0}
           max={360}
           tipFormatter={(v) => `${v}°`}
-          onChange={(val: number) => setAngle(val)}
+          onChange={(val: number) => updateProp('angle', val)}
           value={typeof gradient.angle === 'number' ? gradient.angle : 0}
         />
       )}
@@ -80,7 +73,7 @@ export const GradientRow: React.FC<IGradientRow> = ({ gradient, selfIndex, updat
             name="position X"
             min={-50}
             max={150}
-            onChange={(val: number) => setPosX(val)}
+            onChange={(val: number) => updateProp('posX', val)}
             value={typeof gradient.posX === 'number' ? gradient.posX : 0}
           />
           <SliderInput
@@ -88,7 +81,7 @@ export const GradientRow: React.FC<IGradientRow> = ({ gradient, selfIndex, updat
             name="position Y"
             min={-50}
             max={150}
-            onChange={(val: number) => setPosY(val)}
+            onChange={(val: number) => updateProp('posY', val)}
             value={typeof gradient.posY === 'number' ? gradient.posY : 0}
           />
         </>

+ 1 - 44
src/components/GradientPicker/index.tsx

@@ -1,44 +1 @@
-import { PlusOutlined } from '@ant-design/icons';
-import { Button } from 'antd';
-import { useState } from 'react';
-import { AnyGradientType } from '../store';
-import { GradientRow } from './GradientRow';
-
-export const GradientPicker: React.FC = () => {
-  const initialGradients = [
-    {
-      type: 'linear',
-      isVisible: true,
-      angle: 0,
-      stops: [
-        {
-          color: { r: 0, g: 0, b: 255, a: 1 },
-          offset: 0,
-        },
-        {
-          color: { r: 0, g: 0, b: 0, a: 0 },
-          offset: 1,
-        },
-      ],
-    },
-  ];
-  const [gradients, setGradients] = useState<AnyGradientType[]>(initialGradients);
-  const updateStateOfSelf = (index: number, newData: AnyGradientType) => {
-    setGradients((grads) => grads.splice(index, 1, newData));
-  };
-  const gradientInterface = gradients.map((grad, i) => (
-    <GradientRow
-      key={`${i}` + grad.type + `${grad.stops[0].color.r}`}
-      gradient={grad}
-      updateSelf={updateStateOfSelf}
-      selfIndex={i}
-    />
-  ));
-
-  return (
-    <div>
-      {gradientInterface}
-      <Button icon={<PlusOutlined />}>Add gradient</Button>
-    </div>
-  );
-};
+export * from './GradientPicker';

+ 37 - 62
src/components/store.tsx

@@ -44,7 +44,7 @@ export type ConicGradientType = BaseGradientType & {
 export type FilterPropsType = {
   contrast: number;
   brightness: number;
-  inlineSvg: boolean;
+  invert: boolean;
 };
 
 export type InputState = {
@@ -57,72 +57,47 @@ export type InputState = {
   resetAllProps: () => void;
 };
 
+const initialSvgProps = {
+  size: 250,
+  baseFrequency: 0.65,
+  numOctaves: 3,
+};
+const initialCssProps = {
+  showTransparency: false,
+  gradients: [
+    {
+      type: 'linear',
+      isVisible: true,
+      angle: 0,
+      stops: [
+        {
+          color: { r: 0, g: 0, b: 255, a: 1 },
+          offset: 0,
+        },
+        {
+          color: { r: 0, g: 0, b: 0, a: 0 },
+          offset: 1,
+        },
+      ],
+    },
+  ],
+};
+const initialFilterProps = {
+  contrast: 170,
+  brightness: 1000,
+  invert: false,
+};
 export const useInputStore = create<InputState>((set) => ({
-  svgProps: {
-    size: 250,
-    baseFrequency: 0.65,
-    numOctaves: 3,
-  },
+  svgProps: initialSvgProps,
   setSvgProps: (props) => set({ svgProps: props }),
-
-  cssProps: {
-    showTransparency: true,
-    gradients: [
-      {
-        type: 'linear',
-        isVisible: true,
-        angle: 0,
-        stops: [
-          {
-            color: { r: 0, g: 0, b: 255, a: 1 },
-            offset: 0,
-          },
-          {
-            color: { r: 0, g: 0, b: 0, a: 0 },
-            offset: 1,
-          },
-        ],
-      },
-    ],
-  },
+  cssProps: initialCssProps,
   setCssProps: (props) => set({ cssProps: props }),
-  filterProps: {
-    contrast: 170,
-    brightness: 1000,
-    inlineSvg: false,
-  },
+  filterProps: initialFilterProps,
   setFilterProps: (props) => set({ filterProps: props }),
   resetAllProps: () =>
     set({
-      svgProps: {
-        size: 250,
-        baseFrequency: 0.65,
-        numOctaves: 3,
-      },
-      cssProps: {
-        showTransparency: true,
-        gradients: [
-          {
-            type: 'linear',
-            isVisible: true,
-            angle: 0,
-            stops: [
-              {
-                color: { r: 0, g: 0, b: 255, a: 1 },
-                offset: 0,
-              },
-              {
-                color: { r: 0, g: 0, b: 0, a: 0 },
-                offset: 1,
-              },
-            ],
-          },
-        ],
-      },
-      filterProps: {
-        contrast: 170,
-        brightness: 1000,
-        inlineSvg: false,
-      },
+      svgProps: initialSvgProps,
+      cssProps: initialCssProps,
+      filterProps: initialFilterProps,
     }),
 }));