Jimmy Chion 3 gadi atpakaļ
vecāks
revīzija
76479d1cca

+ 0 - 5
package-lock.json

@@ -4577,11 +4577,6 @@
       "integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==",
       "dev": true
     },
-    "react-simple-code-editor": {
-      "version": "0.11.0",
-      "resolved": "https://registry.npmjs.org/react-simple-code-editor/-/react-simple-code-editor-0.11.0.tgz",
-      "integrity": "sha512-xGfX7wAzspl113ocfKQAR8lWPhavGWHL3xSzNLeseDRHysT+jzRBi/ExdUqevSMos+7ZtdfeuBOXtgk9HTwsrw=="
-    },
     "reactcss": {
       "version": "1.2.3",
       "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",

+ 0 - 1
package.json

@@ -15,7 +15,6 @@
     "react": "17.0.2",
     "react-color": "^2.19.3",
     "react-dom": "17.0.2",
-    "react-simple-code-editor": "^0.11.0",
     "zustand": "^3.5.9"
   },
   "devDependencies": {

+ 95 - 54
src/components/CodeBlocks/Css.tsx

@@ -1,66 +1,96 @@
-import { Form } from 'antd';
+import { Form, Switch, Button, Popover, Select } from 'antd';
 import hljs from 'highlight.js/lib/core';
-import cssLang from 'highlight.js/lib/languages/css';
 import { useEffect, useState } from 'react';
+import { ChromePicker } from 'react-color';
 import styled from 'styled-components';
 import shallow from 'zustand/shallow';
+import { rgbToString } from './Output';
 import SliderInput from './SliderInput';
-import { Row, LeftCol, RightCol } from '~/components/layout';
 import { useInputStore } from '~/components/store';
-hljs.registerLanguage('css', cssLang);
 
-export const CssSection = () => {
-  const [cssProps, setCssProps] = useInputStore(
-    (state) => [state.cssProps, state.setCssProps],
+export const CssControls = () => {
+  const [setCssProps, filterProps] = useInputStore(
+    (state) => [state.setCssProps, state.filterProps],
     shallow
   );
-  const [contrast, setContrast] = useState(170);
-  const [brightness, setBrightness] = useState(1000);
-  const [angle, setAngle] = useState(20);
-  const [gradientType, setGradientType] = useState('linear-gradient');
-  const [color1, setColor1] = useState('blue');
-  const [color2, setColor2] = useState('transparent');
+  const { brightness, contrast } = filterProps;
+  const [angle, setAngle] = useState(112);
+  const [showTransparency, setShowTransparency] = useState(true);
+  const [gradientType, setGradientType] = useState('linear');
+  const [color1, setColor1] = useState({ r: 0, g: 0, b: 255, a: 1 });
+  const [color2, setColor2] = useState({ r: 0, g: 0, b: 255, a: 0 });
 
   useEffect(() => {
     setCssProps({
       gradientType,
-      color1,
-      color2,
-      contrast,
-      brightness,
+      color1: color1,
+      color2: color2,
       angle,
+      showTransparency,
     });
-  }, [setCssProps, contrast, brightness, angle, gradientType, color1, color2]);
+  }, [setCssProps, showTransparency, contrast, brightness, angle, gradientType, color1, color2]);
 
+  const angleOrPos =
+    gradientType === 'linear'
+      ? `${angle}deg`
+      : gradientType === 'radial'
+      ? 'circle at center'
+      : `from ${angle}deg`;
   const gradientCss = `/* css gradient: second layer */
 {
   width: 250px;
   height: 250px;
-  background: ${gradientType}(${angle}deg, ${color1}, ${color2}), url(/checkers.png);
+  background: ${gradientType}-gradient(${angleOrPos}, ${rgbToString(color1)}, ${rgbToString(
+    color2
+  )})${showTransparency ? ', url(/checkers.png)' : ''};
   /* filter: contrast(${contrast}%) brightness(${brightness}%); */
 }`;
   return (
-    <Row>
-      <LeftCol>
-        <Form labelCol={{ span: 3 }}>
-          <SliderInput
-            label="contrast"
-            name="contrast"
-            min={0}
-            max={1000}
-            step={10}
-            onChange={(val: number) => setContrast(val)}
-            value={typeof contrast === 'number' ? contrast : 10}
-          />
-          <SliderInput
-            label="brightness"
-            name="brightness"
-            min={0}
-            max={5000}
-            step={50}
-            onChange={(val: number) => setBrightness(val)}
-            value={typeof brightness === 'number' ? brightness : 0}
-          />
+    <div>
+      <pre className="hljs">
+        <code
+          dangerouslySetInnerHTML={{
+            __html: hljs.highlight(gradientCss, { language: 'css' }).value,
+          }}
+        />
+      </pre>
+      <Form>
+        <GradientControls>
+          <div>
+            <Form.Item label="Gradient type">
+              <Select
+                value={gradientType}
+                onChange={(v) => setGradientType(v)}
+                style={{ width: 120 }}
+              >
+                <Select.Option value="linear">linear</Select.Option>
+                <Select.Option value="radial">radial</Select.Option>
+                <Select.Option value="conic">conic</Select.Option>
+              </Select>
+            </Form.Item>
+          </div>
+          <ColorPick>
+            <Popover
+              placement="bottom"
+              style={{ padding: 0 }}
+              content={<ChromePicker color={color1} onChange={(c) => setColor1(c.rgb)} />}
+              trigger="click"
+            >
+              <Button>Color 1</Button>
+            </Popover>
+          </ColorPick>
+          <ColorPick>
+            <Popover
+              placement="bottom"
+              content={<ChromePicker color={color2} onChange={(c) => setColor2(c.rgb)} />}
+              trigger="click"
+            >
+              <Button>Color 2</Button>
+            </Popover>
+          </ColorPick>
+        </GradientControls>
+
+        {['linear', 'conic'].includes(gradientType) && (
           <SliderInput
             label="angle"
             name="angle"
@@ -69,22 +99,33 @@ export const CssSection = () => {
             onChange={(val: number) => setAngle(val)}
             value={typeof angle === 'number' ? angle : 0}
           />
-        </Form>
-        <pre className="hljs">
-          <code
-            dangerouslySetInnerHTML={{
-              __html: hljs.highlight(gradientCss, { language: 'css' }).value,
-            }}
+        )}
+        {/* {['radial', 'conic'].includes(gradientType) && (
+          <SliderInput
+            label="position"
+            name="position"
+            min={0}
+            max={360}
+            onChange={(val: number) => setPosition(val)}
+            value={typeof position === 'number' ? position : 0}
           />
-        </pre>{' '}
-      </LeftCol>
-      <RightCol>
-        <Gradient css={gradientCss} />
-      </RightCol>
-    </Row>
+        )} */}
+        <Form.Item label="Show checkered">
+          <Switch
+            size="small"
+            checked={showTransparency}
+            onChange={(e) => setShowTransparency(e)}
+          />
+        </Form.Item>
+      </Form>
+    </div>
   );
 };
 
-const Gradient = styled.div`
-  ${(p) => p.css}
+const GradientControls = styled.div`
+  display: flex;
+`;
+
+const ColorPick = styled.div`
+  margin-left: 15px;
 `;

+ 88 - 0
src/components/CodeBlocks/Filter.tsx

@@ -0,0 +1,88 @@
+import { Form, Switch } from 'antd';
+import hljs from 'highlight.js/lib/core';
+import cssLang from 'highlight.js/lib/languages/css';
+import { useEffect, useState } from 'react';
+import shallow from 'zustand/shallow';
+import { symbols, rgbToString } from './Output';
+import SliderInput from './SliderInput';
+import { useInputStore } from '~/components/store';
+hljs.registerLanguage('css', cssLang);
+
+export const FilterControls = () => {
+  const [svgProps, cssProps, setFilterProps] = useInputStore(
+    (state) => [state.svgProps, state.cssProps, state.setFilterProps],
+    shallow
+  );
+  const [contrast, setContrast] = useState(170);
+  const [brightness, setBrightness] = useState(1000);
+  const [inlineSvg, setInlineSvg] = useState(false);
+  const { size, baseFrequency, numOctaves } = svgProps;
+
+  useEffect(() => {
+    setFilterProps({
+      brightness,
+      contrast,
+      inlineSvg,
+    });
+  }, [setFilterProps, contrast, brightness, inlineSvg]);
+
+  const { gradientType, angle, color1, color2 } = cssProps;
+  const gradientFirstParam =
+    gradientType === 'linear'
+      ? `${angle}deg`
+      : gradientType === 'radial'
+      ? 'circle at center'
+      : `from ${angle}deg`;
+  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(
+    symbols,
+    encodeURIComponent
+  )}")`;
+  const resultCssDisplay = `/* resulting css */
+{
+  width: 250px;
+  height: 250px;
+  background: ${gradientType}-gradient(${gradientFirstParam}, ${rgbToString(color1)}, ${rgbToString(
+    color2
+  )}), ${inlineSvg ? inlineSvgString : 'url(/👆/that/noise.svg)'};
+  filter: contrast(${contrast}%) brightness(${brightness}%);
+}
+  `;
+
+  return (
+    <div>
+      <pre className="hljs">
+        <code
+          dangerouslySetInnerHTML={{
+            __html: hljs.highlight(resultCssDisplay, { language: 'css' }).value,
+          }}
+        />
+      </pre>
+      <Form labelCol={{ span: 4 }}>
+        <SliderInput
+          label="contrast"
+          name="contrast"
+          min={100}
+          max={1000}
+          step={10}
+          tipFormatter={(v) => `${v}%`}
+          onChange={(val: number) => setContrast(val)}
+          value={typeof contrast === 'number' ? contrast : 10}
+        />
+        <SliderInput
+          label="brightness"
+          name="brightness"
+          min={100}
+          max={5000}
+          step={50}
+          tipFormatter={(v) => `${v}%`}
+          onChange={(val: number) => setBrightness(val)}
+          value={typeof brightness === 'number' ? brightness : 0}
+        />
+        <Form.Item label="Inline the SVG">
+          <Switch size="small" checked={inlineSvg} onChange={(e) => setInlineSvg(e)} />
+        </Form.Item>
+      </Form>
+    </div>
+  );
+};

+ 89 - 0
src/components/CodeBlocks/Output.tsx

@@ -0,0 +1,89 @@
+import styled from 'styled-components';
+import shallow from 'zustand/shallow';
+import { useInputStore } from '~/components/store';
+
+export const symbols = /[\r\n%#()<>?[\\\]^`{|}]/g;
+
+export const rgbToString = ({ r, g, b, a }) => `rgba(${r},${g},${b},${a})`;
+
+const Output = () => {
+  const [svgProps, cssProps, filterProps] = useInputStore(
+    (state) => [state.svgProps, state.cssProps, state.filterProps],
+    shallow
+  );
+  const { size, baseFrequency, numOctaves } = svgProps;
+  const { gradientType, color1, color2, angle, showTransparency } = cssProps;
+  const { brightness, contrast } = filterProps;
+  const gradientFirstParam =
+    gradientType === 'linear'
+      ? `${angle}deg`
+      : gradientType === 'radial'
+      ? 'circle at center'
+      : `from ${angle}deg`;
+  const svgString = `<!-- svg: first layer -->
+<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 gradientCss = `/* css gradient: second layer */
+{
+  width: 250px;
+  height: 250px;
+  background: ${gradientType}-gradient(${gradientFirstParam}, ${rgbToString(color1)}, ${rgbToString(
+    color2
+  )})${showTransparency ? ', url(/checkers.png)' : ''};
+  /* filter: contrast(${contrast}%) brightness(${brightness}%); */
+}`;
+
+  const liveCss = `
+width: 250px;
+height: 250px;
+background: ${gradientType}-gradient(${gradientFirstParam}, ${rgbToString(color1)}, ${rgbToString(
+    color2
+  )}), url("data:image/svg+xml,${svgString.replace(symbols, encodeURIComponent)}");
+filter: contrast(${contrast}%) brightness(${brightness}%);
+`;
+
+  return (
+    <Container>
+      <Noise size={size} code={svgString} />
+      <Gradient css={gradientCss} />
+      <Filter css={liveCss} />
+    </Container>
+  );
+};
+
+export default Output;
+
+const Container = styled.div`
+  min-height: 100vh;
+  display: flex;
+  overflow: scroll;
+  flex-direction: column;
+  justify-content: space-evenly;
+  align-items: center;
+  flex-shrink: 1;
+`;
+
+// prettier-ignore
+const Noise = styled.div`
+  width: ${p=>p.size}px;
+  height: ${p=>p.size}px;
+  background: url("data:image/svg+xml,${(p) => p.code.replace(symbols, encodeURIComponent)}");
+`;
+
+const Gradient = styled.div`
+  ${(p) => p.css}
+`;
+
+const Filter = styled.div`
+  ${(p: Record<string, string>) => p.css}
+`;

+ 0 - 60
src/components/CodeBlocks/Result.tsx

@@ -1,60 +0,0 @@
-import { Form } from 'antd';
-import hljs from 'highlight.js/lib/core';
-import cssLang from 'highlight.js/lib/languages/css';
-import { useState } from 'react';
-import styled from 'styled-components';
-import shallow from 'zustand/shallow';
-import SliderInput from './SliderInput';
-import { Row, LeftCol, RightCol } from '~/components/layout';
-import { useInputStore } from '~/components/store';
-hljs.registerLanguage('css', cssLang);
-
-const symbols = /[\r\n%#()<>?[\\\]^`{|}]/g;
-
-export const ResultSection = () => {
-  const [svgProps, cssProps] = useInputStore((state) => [state.svgProps, state.cssProps], shallow);
-  // const [contrast, setContrast] = useState(170);
-  // const [brightness, setBrightness] = useState(1000);
-
-  const { gradientType, angle, color1, color2, contrast, brightness } = cssProps;
-  const { size, baseFrequency, numOctaves } = svgProps;
-  const resultCssDisplay = `/* resulting css */
-{
-  width: 250px;
-  height: 250px;
-  background: ${gradientType}(${angle}deg, ${color1}, ${color2}), url(/that/noise.svg);
-  filter: contrast(${contrast}%) brightness(${brightness}%);
-}
-  `;
-  const svgString = `<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 liveCss = `
-  width: 250px;
-  height: 250px;
-  background: ${gradientType}(${angle}deg, ${color1}, ${color2}), url("data:image/svg+xml,${svgString.replace(
-    symbols,
-    encodeURIComponent
-  )}");
-  filter: contrast(${contrast}%) brightness(${brightness}%);
-  `;
-  return (
-    <Row>
-      <LeftCol>
-        <Form labelCol={{ span: 3 }}></Form>
-        <pre className="hljs">
-          <code
-            dangerouslySetInnerHTML={{
-              __html: hljs.highlight(resultCssDisplay, { language: 'css' }).value,
-            }}
-          />
-        </pre>{' '}
-      </LeftCol>
-      <RightCol>
-        <Result css={liveCss} />
-      </RightCol>
-    </Row>
-  );
-};
-
-const Result = styled.div`
-  ${(p) => p.css}
-`;

+ 11 - 4
src/components/CodeBlocks/SliderInput.tsx

@@ -2,12 +2,19 @@ import { Form, Slider, InputNumber } from 'antd';
 import styled from 'styled-components';
 
 const SliderInput = (props) => {
-  const { label, name, onChange, value, min, max, step } = props;
+  const { label, name, onChange, value, min, max, step, tipFormatter } = props;
   return (
-    <Form.Item label={label} name={name}>
+    <Form.Item label={label} name={name} style={{ width: '100%', margin: 0 }}>
       <SliderAndInput>
         <SliderContainer>
-          <Slider step={step} min={min} max={max} onChange={onChange} value={value} />
+          <Slider
+            tipFormatter={tipFormatter}
+            step={step}
+            min={min}
+            max={max}
+            onChange={onChange}
+            value={value}
+          />
         </SliderContainer>
         <InputNumber
           step={step}
@@ -24,7 +31,7 @@ const SliderInput = (props) => {
 export default SliderInput;
 
 const SliderContainer = styled.div`
-  width: 50%;
+  width: 40%;
 `;
 
 const SliderAndInput = styled.div`

+ 39 - 62
src/components/CodeBlocks/Svg.tsx

@@ -1,20 +1,14 @@
 import { Form } from 'antd';
 import hljs from 'highlight.js/lib/core';
-import xmlLang from 'highlight.js/lib/languages/xml';
 import { useEffect, useState } from 'react';
-import styled from 'styled-components';
 import shallow from 'zustand/shallow';
 import SliderInput from './SliderInput';
-import { Row, LeftCol, RightCol } from '~/components/layout';
 import { useInputStore } from '~/components/store';
-hljs.registerLanguage('xml', xmlLang);
 
-const symbols = /[\r\n%#()<>?[\\\]^`{|}]/g;
-
-export const SvgSection = () => {
+export const SvgControls = () => {
   const [setSvgProps] = useInputStore((state) => [state.setSvgProps], shallow);
 
-  const [size, setSize] = useState(200);
+  const [size, setSize] = useState(250);
   const [baseFrequency, setBaseFrequency] = useState(0.65);
   const [numOctaves, setNumOctaves] = useState(3);
 
@@ -36,59 +30,42 @@ export const SvgSection = () => {
 </svg>`;
 
   return (
-    <Row>
-      <LeftCol>
-        <Form labelCol={{ span: 3 }}>
-          <SliderInput
-            label="SVG size"
-            name="size"
-            min={1}
-            max={400}
-            onChange={(val) => setSize(val)}
-            value={typeof size === 'number' ? size : 1}
-          />
-          <SliderInput
-            label="baseFrequency"
-            name="baseFrequency"
-            min={0}
-            max={10}
-            step={0.01}
-            onChange={(val) => setBaseFrequency(val)}
-            value={typeof baseFrequency === 'number' ? baseFrequency : 1}
-          />
-          <SliderInput
-            label="numOctaves"
-            name="numOctaves"
-            min={0}
-            max={6}
-            onChange={(val) => setNumOctaves(val)}
-            value={typeof numOctaves === 'number' ? numOctaves : 1}
-          />
-        </Form>
-
-        <pre className="hljs">
-          <code
-            dangerouslySetInnerHTML={{
-              __html: hljs.highlight(svgString, { language: 'xml' }).value,
-            }}
-          />
-        </pre>
-      </LeftCol>
-      <RightCol>
-        <Noise size={size} code={svgString} />
-      </RightCol>
-    </Row>
+    <div>
+      <pre className="hljs">
+        <code
+          dangerouslySetInnerHTML={{
+            __html: hljs.highlight(svgString, { language: 'xml' }).value,
+          }}
+        />
+      </pre>
+      <Form labelCol={{ span: 4 }}>
+        <SliderInput
+          label="SVG size"
+          name="size"
+          min={1}
+          max={400}
+          onChange={(val) => setSize(val)}
+          tipFormatter={(v) => `${v}px`}
+          value={typeof size === 'number' ? size : 1}
+        />
+        <SliderInput
+          label="baseFrequency"
+          name="baseFrequency"
+          min={0}
+          max={10}
+          step={0.01}
+          onChange={(val) => setBaseFrequency(val)}
+          value={typeof baseFrequency === 'number' ? baseFrequency : 1}
+        />
+        <SliderInput
+          label="numOctaves"
+          name="numOctaves"
+          min={0}
+          max={6}
+          onChange={(val) => setNumOctaves(val)}
+          value={typeof numOctaves === 'number' ? numOctaves : 1}
+        />
+      </Form>
+    </div>
   );
 };
-
-type NoiseProps = {
-  noiseWidth: number;
-  noiseHeight: number;
-};
-
-// prettier-ignore
-const Noise = styled.div<NoiseProps>`
-  width: ${p=>p.size}px;
-  height: ${p=>p.size}px;
-  background: url("data:image/svg+xml,${(p) => p.code.replace(symbols, encodeURIComponent)}");
-`;

+ 8 - 1
src/components/CodeBlocks/index.tsx

@@ -1,3 +1,10 @@
+import hljs from 'highlight.js/lib/core';
+import cssLang from 'highlight.js/lib/languages/css';
+import xmlLang from 'highlight.js/lib/languages/xml';
+
+hljs.registerLanguage('css', cssLang);
+hljs.registerLanguage('xml', xmlLang);
+
 export * from './Svg';
 export * from './Css';
-export * from './Result';
+export * from './Filter';

+ 4 - 4
src/components/layout/index.tsx

@@ -84,8 +84,8 @@ export const Space = styled.div<SpaceProps>`
 
 export const LeftCol = ({ children }) => (
   <Col
-    off={{ xs: 1, sm: 2, md: 1, lg: 1, xl: 1, xxl: 1 }}
-    span={{ xs: 22, sm: 20, md: 13, lg: 13, xl: 13, xxl: 13 }}
+    off={{ xs: 0, sm: 0, md: 0, lg: 0, xl: 0, xxl: 0 }}
+    span={{ xs: 16, sm: 16, md: 16, lg: 16, xl: 16, xxl: 16 }}
   >
     {children}
   </Col>
@@ -93,8 +93,8 @@ export const LeftCol = ({ children }) => (
 
 export const RightCol = ({ children }) => (
   <Col
-    off={{ xs: 1, sm: 2, md: 2, lg: 2, xl: 2, xxl: 2 }}
-    span={{ xs: 22, sm: 20, md: 7, lg: 7, xl: 7, xxl: 7 }}
+    off={{ xs: 0, sm: 0, md: 0, lg: 0, xl: 0, xxl: 0 }}
+    span={{ xs: 8, sm: 8, md: 8, lg: 8, xl: 8, xxl: 8 }}
   >
     {children}
   </Col>

+ 18 - 8
src/components/store.tsx

@@ -3,10 +3,12 @@
 import create from 'zustand';
 
 export type InputState = {
-  svgProps: any;
+  svgProps: Record<string, number>;
   setSvgProps: ({ size, baseFrequency, numOctaves }) => void;
-  cssProps: any;
-  setCssProps: ({ gradientType, angle, color1, color2, contrast, brightness }) => void;
+  cssProps: Record<string, any>;
+  setCssProps: ({ gradientType, angle, color1, color2, showTransparency }) => void;
+  filterProps: Record<string, number | boolean>;
+  setFilterProps: ({ contrast, brightness, inlineSvg }) => void;
 };
 
 export const useInputStore = create<InputState>((set) => ({
@@ -22,14 +24,22 @@ export const useInputStore = create<InputState>((set) => ({
 
   cssProps: {
     gradientType: 'linear-gradient',
-    angle: 20,
-    color1: 'blue',
-    color2: 'transparent',
+    angle: 112,
+    color1: { r: 0, g: 0, b: 255, a: 1 },
+    color2: { r: 0, g: 0, b: 0, a: 0 },
+    showTransparency: true,
+  },
+  setCssProps: ({ gradientType, angle, color1, color2, showTransparency }) =>
+    set({
+      cssProps: { gradientType, angle, color1, color2, showTransparency },
+    }),
+  filterProps: {
     contrast: 170,
     brightness: 1000,
+    inlineSvg: false,
   },
-  setCssProps: ({ gradientType, angle, color1, color2, contrast, brightness }) =>
+  setFilterProps: ({ contrast, brightness, inlineSvg }) =>
     set({
-      cssProps: { gradientType, angle, color1, color2, contrast, brightness },
+      filterProps: { contrast, brightness, inlineSvg },
     }),
 }));

+ 1 - 1
src/pages/_app.tsx

@@ -1,6 +1,6 @@
 import type { AppProps } from 'next/app';
 import React from 'react';
-import 'antd/dist/antd.dark.css';
+import 'antd/dist/antd.css';
 import 'highlight.js/styles/base16/outrun-dark.css';
 import '~/styles/globals.css';
 

+ 28 - 7
src/pages/index.tsx

@@ -1,20 +1,34 @@
+import Head from 'next/head';
 import React from 'react';
 import styled from 'styled-components';
-import { SvgSection, CssSection, ResultSection } from '~/components/CodeBlocks';
-import { Row, LeftCol, Space } from '~/components/layout';
+import { SvgControls, CssControls, FilterControls } from '~/components/CodeBlocks';
+import Output from '~/components/CodeBlocks/Output';
+import { Row, LeftCol, Space, RightCol } from '~/components/layout';
 
 const IndexPage = () => {
   return (
     <Container>
+      <Head>
+        <title>Grainy Gradients playground</title>
+      </Head>
       <Row>
         <LeftCol>
-          <Space h={30} />
-          <h1>Grainy Gradient playground</h1>
+          <Scroll>
+            <Space h={30} />
+            <h1>Grainy Gradient playground</h1>
+            <h2>1. SVG</h2>
+            <SvgControls />
+            <h2>2. CSS Gradient</h2>
+            <CssControls />
+            <h2>3. CSS Filter</h2>
+            <FilterControls />
+            <Space h={60} />
+          </Scroll>
         </LeftCol>
+        <RightCol>
+          <Output />
+        </RightCol>
       </Row>
-      <SvgSection />
-      <CssSection />
-      <ResultSection />
     </Container>
   );
 };
@@ -24,3 +38,10 @@ export default IndexPage;
 const Container = styled.div`
   height: 100vh;
 `;
+
+const Scroll = styled.div`
+  height: 100vh;
+  overflow-y: scroll;
+  padding: 0 ${(2 / 24) * 100}%;
+  background-color: #ddd;
+`;

+ 11 - 2
src/styles/globals.css

@@ -4,8 +4,8 @@ body {
   margin: 0;
   font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
     Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
-  background-color: #1E1E1E;
-  color: white;
+  background-color: #eee;
+  color: #1e1e1e;
 }
 
 * {
@@ -17,4 +17,13 @@ pre {
   padding: 12px;
   word-wrap: break-word;
   margin: 0;
+}
+
+.hljs {
+  width: 100%;
+  margin-bottom: 1em;
+}
+
+h2 {
+  margin-top: 2em;
 }