diff --git a/src/config.ts b/src/config.ts index 231d349..21492a8 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,5 +1,10 @@ -export type EyeFrameShape = "square" | "circle" | "rounded" | "circle-item"; -export type EyeballShape = "square" | "circle" | "circle-item"; +export type EyeFrameShape = + | "body" + | "square" + | "circle" + | "rounded" + | "circle-item"; +export type EyeballShape = "body" | "square" | "circle" | "circle-item"; export type BodyShape = | "square" | "square-small" @@ -53,26 +58,20 @@ export const defaultConfig: Config = { shapes: { eyeFrame: "circle", body: "rounded-horizontal", - eyeball: "circle", + eyeball: "square", }, colors: { background: "white", body: "linear-gradient(90deg, rgba(255,31,234,1) 4%, RGBA(225,147,129,1) 35%, rgba(0,212,255,1) 100%)", eyeFrame: { - topLeft: - "linear-gradient(90deg, RGBA(66, 58, 187, 1) 0%, rgba(9,9,121,1) 35%, rgba(0,212,255,1) 100%)", - topRight: - "linear-gradient(90deg, RGBA(66, 58, 187, 1) 0%, rgba(9,9,121,1) 35%, rgba(0,212,255,1) 100%)", - bottomLeft: - "linear-gradient(90deg, RGBA(66, 58, 187, 1) 0%, rgba(9,9,121,1) 35%, rgba(0,212,255,1) 100%)", + topLeft: "body", + topRight: "body", + bottomLeft: "body", }, eyeball: { - topLeft: - "linear-gradient(90deg, rgba(244,209,74,1) 0%, RGB(5, 5, 5) 35%, rgba(0,212,255,1) 100%)", - topRight: - "linear-gradient(90deg, rgba(244,209,74,1) 0%, RGB(5, 5, 5) 35%, rgba(0,212,255,1) 100%)", - bottomLeft: - "linear-gradient(90deg, rgba(244,209,74,1) 0%, RGB(5, 5, 5) 35%, rgba(0,212,255,1) 100%)", + topLeft: "body", + topRight: "body", + bottomLeft: "body", }, }, }; diff --git a/src/eyeball.ts b/src/eyeball.ts index 17ab884..7968b3a 100644 --- a/src/eyeball.ts +++ b/src/eyeball.ts @@ -92,17 +92,23 @@ const generateEyeballSVG = ({ size, matrixLength, position, + pathOnly, }: GenerateEyeballSVGParams) => { if (shape == "circle-item") { return ""; } + + const path = eyeballFunction[shape]({ + matrixLength: matrixLength, + size: size, + position, + }); + if (pathOnly) { + return path; + } return ``; @@ -110,39 +116,62 @@ const generateEyeballSVG = ({ export const generateEyeballSVGFromConfig = ( config: Config, - matrixLength: number + matrixLength: number, + isFromBody?: boolean ) => { - const eyeballShape = config.shapes.eyeball; - const eyeballColor = config.colors.eyeball; + const shape = config.shapes.eyeball; + const colors = config.colors.eyeball; let svgString = ""; - + if (shape === "body") { + return ""; + } //top-left - svgString += generateEyeballSVG({ - shape: eyeballShape, - color: eyeballColor.topLeft, - size: config.length, - matrixLength, - position: "topLeft", - }); + + if ( + (colors.topLeft === "body" && isFromBody) || + (colors.topLeft !== "body" && !isFromBody) + ) { + svgString += generateEyeballSVG({ + shape: shape, + color: colors.topLeft === "body" ? config.colors.body : colors.topLeft, + size: config.length, + matrixLength, + position: "topLeft", + pathOnly: colors.topLeft === "body", + }); + } //top-right - svgString += generateEyeballSVG({ - shape: eyeballShape, - color: eyeballColor.topLeft, - size: config.length, - matrixLength, - position: "topRight", - }); + if ( + (colors.topRight === "body" && isFromBody) || + (colors.topRight !== "body" && !isFromBody) + ) { + svgString += generateEyeballSVG({ + shape: shape, + color: colors.topRight === "body" ? config.colors.body : colors.topRight, + size: config.length, + matrixLength, + position: "topRight", + pathOnly: colors.bottomLeft === "body", + }); + } //bottom-left - svgString += generateEyeballSVG({ - shape: eyeballShape, - color: eyeballColor.topLeft, - size: config.length, - matrixLength, - position: "bottomLeft", - }); + if ( + (colors.bottomLeft === "body" && isFromBody) || + (colors.bottomLeft !== "body" && !isFromBody) + ) { + svgString += generateEyeballSVG({ + shape: shape, + color: + colors.bottomLeft === "body" ? config.colors.body : colors.bottomLeft, + size: config.length, + matrixLength, + position: "bottomLeft", + pathOnly: colors.bottomLeft === "body", + }); + } return svgString; }; diff --git a/src/eyeframes.ts b/src/eyeframes.ts index 348578d..ff4cf3f 100644 --- a/src/eyeframes.ts +++ b/src/eyeframes.ts @@ -1,7 +1,6 @@ import { isGradientColor } from "./utils/gradient"; import { GenerateEyeFrameSVGParams, - StylePathGeneratorParams, StyledEyePathGeneratorParams, } from "./types"; import { getPositionForEyes } from "./utils"; @@ -165,17 +164,23 @@ const generateEyeFrameSVG = ({ size, matrixLength, position, + pathOnly, }: GenerateEyeFrameSVGParams) => { if (shape == "circle-item") { return ""; } - return ` { const shape = config.shapes.eyeFrame; - const colors = config.colors.eyeball; + const colors = config.colors.eyeFrame; let svgString = ""; + if (shape === "body") { + return ""; + } + //top-left - svgString += generateEyeFrameSVG({ - shape, - color: colors.topLeft, - size: config.length, - matrixLength, - position: "topLeft", - }); + if ( + (colors.topLeft === "body" && isFromBody) || + (colors.topLeft !== "body" && !isFromBody) + ) { + svgString += generateEyeFrameSVG({ + shape, + color: colors.topLeft === "body" ? config.colors.body : colors.topLeft, + size: config.length, + matrixLength, + position: "topLeft", + pathOnly: colors.topLeft === "body", + }); + } //top-right - svgString += generateEyeFrameSVG({ - shape, - color: colors.topLeft, - size: config.length, - matrixLength, - position: "topRight", - }); + if ( + (colors.topRight === "body" && isFromBody) || + (colors.topRight !== "body" && !isFromBody) + ) { + svgString += generateEyeFrameSVG({ + shape, + color: colors.topRight === "body" ? config.colors.body : colors.topRight, + size: config.length, + matrixLength, + position: "topRight", + pathOnly: colors.topLeft === "body", + }); + } //bottom-left - svgString += generateEyeFrameSVG({ - shape, - color: colors.topLeft, - size: config.length, - matrixLength, - position: "bottomLeft", - }); + if ( + (colors.bottomLeft === "body" && isFromBody) || + (colors.bottomLeft !== "body" && !isFromBody) + ) { + svgString += generateEyeFrameSVG({ + shape, + color: + colors.bottomLeft === "body" ? config.colors.body : colors.bottomLeft, + size: config.length, + matrixLength, + position: "bottomLeft", + pathOnly: colors.topLeft === "body", + }); + } return svgString; }; diff --git a/src/path/index.ts b/src/path/index.ts index ae4a81d..6d9eb62 100644 --- a/src/path/index.ts +++ b/src/path/index.ts @@ -12,6 +12,8 @@ import { } from "./square"; import { Config } from "../config"; import { checkNeighbors } from "../utils/path"; +import { generateEyeFrameSVGFromConfig } from "../eyeframes"; +import { generateEyeballSVGFromConfig } from "../eyeball"; interface GeneratePathProps { size: number; matrix: number[][]; @@ -47,7 +49,9 @@ export const generatePath = ({ size, matrix, config }: GeneratePathProps) => { if (config.shapes.eyeFrame === "circle-item") { path += generateCirclePath({ i, j, cellSize }); } - return; + if (config.shapes.eyeFrame !== "body") { + return; + } } } @@ -56,7 +60,9 @@ export const generatePath = ({ size, matrix, config }: GeneratePathProps) => { if (config.shapes.eyeball === "circle-item") { path += generateCirclePath({ i, j, cellSize }); } - return; + if (config.shapes.eyeball !== "body") { + return; + } } } if (config.shapes.body === "square") { @@ -214,5 +220,7 @@ export const generatePath = ({ size, matrix, config }: GeneratePathProps) => { }); }); + path += generateEyeFrameSVGFromConfig(config, matrix.length, true); + path += generateEyeballSVGFromConfig(config, matrix.length, true); return path; }; diff --git a/src/types.ts b/src/types.ts index 2070565..f6edef1 100644 --- a/src/types.ts +++ b/src/types.ts @@ -12,6 +12,7 @@ export interface GenerateEyeballSVGParams { size: number; matrixLength: number; position: EyePosition; + pathOnly: boolean; } export interface GenerateEyeFrameSVGParams { @@ -20,6 +21,7 @@ export interface GenerateEyeFrameSVGParams { size: number; matrixLength: number; position: EyePosition; + pathOnly: boolean; } export interface StyledEyePathGeneratorParams extends StylePathGeneratorParams { diff --git a/web/src/pages/Home/customization/Colors.tsx b/web/src/pages/Home/customization/Colors.tsx index dbb12fc..474193a 100644 --- a/web/src/pages/Home/customization/Colors.tsx +++ b/web/src/pages/Home/customization/Colors.tsx @@ -6,6 +6,7 @@ import GradientPicker from "react-best-gradient-color-picker"; import { useState } from "react"; import { isGradientColor } from "../../../../../src/utils/gradient"; +import { StyledShape } from "./Shape"; const Label = styled.p` width: 80px; @@ -67,6 +68,7 @@ export const Colors = ({ label: ColorConfigLabel; value: string; onChange: (value: string) => void; + RightComponent?: () => JSX.Element; }[] = [ { label: "Background", @@ -110,6 +112,30 @@ export const Colors = ({ }, }); }, + RightComponent: () => ( + + setQrConfig({ + ...qrConfig, + colors: { + ...qrConfig.colors, + eyeFrame: { + topLeft: "body", + topRight: "body", + bottomLeft: "body", + }, + }, + }) + } + style={{ + display: "flex", + alignItems: "center", + }} + > +

Same as body

+
+ ), }, { label: "Eyeball", @@ -127,6 +153,30 @@ export const Colors = ({ }, }); }, + RightComponent: () => ( + + setQrConfig({ + ...qrConfig, + colors: { + ...qrConfig.colors, + eyeball: { + topLeft: "body", + topRight: "body", + bottomLeft: "body", + }, + }, + }) + } + style={{ + display: "flex", + alignItems: "center", + }} + > +

Same as body

+
+ ), }, ]; @@ -137,15 +187,18 @@ export const Colors = ({ return ( - {COLOR_CONFIG.map((config) => ( + {COLOR_CONFIG.map(({ RightComponent, ...config }) => ( - - { - setActiveColorLabel(config.label); - }} - /> + + + { + setActiveColorLabel(config.label); + }} + /> + + {RightComponent && } ))} diff --git a/web/src/pages/Home/customization/Shape.tsx b/web/src/pages/Home/customization/Shape.tsx index 794bc4f..4b24202 100644 --- a/web/src/pages/Home/customization/Shape.tsx +++ b/web/src/pages/Home/customization/Shape.tsx @@ -14,7 +14,7 @@ const ShapeImg = styled.img` object-fit: contain; `; -const StyledShape = styled.div<{ $active: boolean }>` +export const StyledShape = styled.div<{ $active: boolean }>` cursor: pointer; border: 2px solid ${({ $active }) => ($active ? "#03C29C" : "transparent")}; border-radius: 2px; @@ -33,6 +33,7 @@ const ShapeWrapper = styled.div` export const Shape = ({ setQrConfig, qrConfig }: CustomizationSectionProps) => { return ( <> + Body Shape {config.body.map((item) => ( { ))} + + setQrConfig({ + ...qrConfig, + shapes: { + ...qrConfig.shapes, + eyeball: "body", + }, + }) + } + style={{ + display: "flex", + alignItems: "center", + }} + > +

Same as body

+
Eye Frame Shape @@ -91,6 +110,24 @@ export const Shape = ({ setQrConfig, qrConfig }: CustomizationSectionProps) => { ))} + + setQrConfig({ + ...qrConfig, + shapes: { + ...qrConfig.shapes, + eyeFrame: "body", + }, + }) + } + style={{ + display: "flex", + alignItems: "center", + }} + > +

Same as body

+
);