From 2bfa741a715a4d563aaa44e7da054833d3690f26 Mon Sep 17 00:00:00 2001 From: Mohan Ki Date: Mon, 27 Jul 2026 19:26:51 +0530 Subject: [PATCH] feat(qr): Add Gradients, Inner Eye styling, and Logo Presets to Visual Customization Studio --- client/public/logos/facebook.svg | Bin 0 -> 768 bytes client/public/logos/instagram.svg | Bin 0 -> 1946 bytes client/public/logos/linkedin.svg | Bin 0 -> 1188 bytes client/public/logos/x.svg | Bin 0 -> 786 bytes client/public/logos/youtube.svg | Bin 0 -> 888 bytes client/src/app/dashboard/page.tsx | 2 +- .../src/components/qr-editor/DesignPanel.tsx | 209 ++++++++++++++---- 7 files changed, 162 insertions(+), 49 deletions(-) create mode 100644 client/public/logos/facebook.svg create mode 100644 client/public/logos/instagram.svg create mode 100644 client/public/logos/linkedin.svg create mode 100644 client/public/logos/x.svg create mode 100644 client/public/logos/youtube.svg diff --git a/client/public/logos/facebook.svg b/client/public/logos/facebook.svg new file mode 100644 index 0000000000000000000000000000000000000000..67b0879675babda29f8bdd2917bb3a6b6cc6b471 GIT binary patch literal 768 zcmZXSOH0E*6ot=P@IREgPMUWUsa+_D8@KMoSB3h(N-X|(^*b{OQDjJF?(57sckcJs zN;~y>&`f(hX{%@K6V0{JJL^@)TChICO8J*c^`bW_7Alm5wHPqwp!9mw9eJl@?E_MV z*I%J(_|LW03hZlc*x$#&H>S|rUByw%( zOA>ll!L>uR`xo5mC7g4ztjB!ZKXdEYjTmkB!HDKn|M5k}e!mLEMs-G1TXJrBIm|1MVXHNGoj9c^sNSWh(; zs&XHnJK^?Snep$oEk>w;J?)74M=^mre9>srgyFFa9fe z+mgSM)hptWD}44SVrcRcnWFP{Ar(`w$z(v=Boe*-WjHxL$8r?ryo{ZeN9j)S)8#!w>>?$yOXuFiE9+?C#X8bpuGQO_}c?-HKU#wY9C4s>bNpJmO_Hw z{KJpRc@8>ncctT2bGT|WK+jn{6q{Sdcf2jvHF8i48u=A@E;cdO*rUF2>+(I!ujoa* Hj2H12Wh}=z literal 0 HcmV?d00001 diff --git a/client/public/logos/linkedin.svg b/client/public/logos/linkedin.svg new file mode 100644 index 0000000000000000000000000000000000000000..6a3da15c30b5e0115ae68a192bb1f578fcb6642b GIT binary patch literal 1188 zcmZvcOK;Rb5QOWD#D7>V=k>0=e(a(U3HFjpuH4b`aHJ$4Kq1PH2kPtg$W|1MJnm_C zRo8US_}||P{nCTJX{ATq=~nk%ztdWyetZ1TTWvl5#Hc*)Rq4Ba8nIQQU5xF-u{O(t zZuG@*9~|`p|W(j(xA*<75PkpTmD0*(!6i8iHqM zC9OL9M{Pn^=T&P38^0?*y^cDYZ=>4ly(15{D|;GqBxYwnHW7zld)dEtPM8|U)yDK* zgF#RC%umeGF-L1b3A-6|#in}QqPujI6Ill?Pb(E|LLYP1;cDU?{63jyh<)U};qKrWrYfiY z!C1~0caXfTt&?qbjuN=(Rbk58N8MoJRNxssmwQC!g3YhYdilf_|ot@dc z@2@4^aliu>IN}L=Jo9{k0y}&#UU80!@#!e}ZBXI`Z|ta0BRHywqae!xkGLo9lBlDZ z0<-$nXs2(16_(__<%At`TlVZ3ntL{JW@a(oIe(4l*$D%g8s;OBB@$1OxwX}lu8qtr zh`Dk_m;oK9uX(Q7Gcwe*;J>O7JrUv zsiGyKw}N0yRxXA#IT0cdD>kX@c(gdC*L5Fqs5?@>?n^h-ur7y*=i2%*{y%>SH$>-~%5FD&Yn9*O{CZb7#R+}@ Dd?#6_ literal 0 HcmV?d00001 diff --git a/client/public/logos/youtube.svg b/client/public/logos/youtube.svg new file mode 100644 index 0000000000000000000000000000000000000000..2a5264627ee26860e86b16741f6b6727e3599776 GIT binary patch literal 888 zcma)5%TB{U44g9({}6?9nL8Xb;M=Du$Z9>#(kJYdV xHhrCyRH4BQA8lSiovwXkYIS6i8aeM=5Ys$D=AIjz`E9rV$O6YW!VioRVSxYu literal 0 HcmV?d00001 diff --git a/client/src/app/dashboard/page.tsx b/client/src/app/dashboard/page.tsx index 89a3144..a74ccc0 100644 --- a/client/src/app/dashboard/page.tsx +++ b/client/src/app/dashboard/page.tsx @@ -286,7 +286,7 @@ export default function DashboardPage() {
- Edit Link + Edit QR Code {/* Move Folder Dropdown Toggle */} diff --git a/client/src/components/qr-editor/DesignPanel.tsx b/client/src/components/qr-editor/DesignPanel.tsx index dc7e00c..ab4d219 100644 --- a/client/src/components/qr-editor/DesignPanel.tsx +++ b/client/src/components/qr-editor/DesignPanel.tsx @@ -9,13 +9,34 @@ interface DesignPanelProps { export default function DesignPanel({ options, onChange }: DesignPanelProps) { - const handleColorChange = (e: React.ChangeEvent) => { + const [dotColorMode, setDotColorMode] = React.useState<'solid' | 'gradient'>( + options.dotsOptions?.gradient ? 'gradient' : 'solid' + ); + + const handleDotColorChange = (e: React.ChangeEvent) => { const newColor = e.target.value; onChange({ ...options, - dotsOptions: { ...options.dotsOptions, color: newColor }, - cornersSquareOptions: { ...options.cornersSquareOptions, color: newColor }, - cornersDotOptions: { ...options.cornersDotOptions, color: newColor } + dotsOptions: { ...options.dotsOptions, color: newColor, gradient: undefined }, + cornersSquareOptions: { ...options.cornersSquareOptions, color: newColor, gradient: undefined }, + cornersDotOptions: { ...options.cornersDotOptions, color: newColor, gradient: undefined } + }); + }; + + const handleDotGradientChange = (color1: string, color2: string) => { + const gradient: any = { + type: 'linear', + rotation: Math.PI / 4, + colorStops: [ + { offset: 0, color: color1 }, + { offset: 1, color: color2 } + ] + }; + onChange({ + ...options, + dotsOptions: { ...options.dotsOptions, gradient, color: undefined }, + cornersSquareOptions: { ...options.cornersSquareOptions, gradient, color: undefined }, + cornersDotOptions: { ...options.cornersDotOptions, gradient, color: undefined } }); }; @@ -32,6 +53,13 @@ export default function DesignPanel({ options, onChange }: DesignPanelProps) { cornersSquareOptions: { ...options.cornersSquareOptions, type: e.target.value as any } }); }; + + const handleInnerEyeTypeChange = (e: React.ChangeEvent) => { + onChange({ + ...options, + cornersDotOptions: { ...options.cornersDotOptions, type: e.target.value as any } + }); + }; const handleLogoUpload = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; @@ -48,6 +76,13 @@ export default function DesignPanel({ options, onChange }: DesignPanelProps) { reader.readAsDataURL(file); }; + const setPresetLogo = (path: string) => { + onChange({ + ...options, + image: path + }); + }; + const removeLogo = () => { onChange({ ...options, @@ -55,74 +90,152 @@ export default function DesignPanel({ options, onChange }: DesignPanelProps) { }); }; + // Helper to extract colors from gradient + const getGradientColors = () => { + if (options.dotsOptions?.gradient?.colorStops && options.dotsOptions.gradient.colorStops.length >= 2) { + return [ + options.dotsOptions.gradient.colorStops[0].color, + options.dotsOptions.gradient.colorStops[1].color + ]; + } + return ['#4f46e5', '#ec4899']; + }; + const [c1, c2] = getGradientColors(); + return (

Design Customization

{/* Colors */}
- -
- - {options.dotsOptions?.color} + + +
+ + +
+ + {dotColorMode === 'solid' ? ( +
+ + {options.dotsOptions?.color || '#000000'} +
+ ) : ( +
+
+ Color 1 + handleDotGradientChange(e.target.value, c2)} className="w-8 h-8 rounded cursor-pointer" /> +
+ +
+ Color 2 + handleDotGradientChange(c1, e.target.value)} className="w-8 h-8 rounded cursor-pointer" /> +
+
+ )} +
+ + {/* Shapes */} +
+
+ + +
+ +
+ + +
+ +
+ +
{/* Logo */} -
- +
+ + +
+ + + + + +
+
{options.image && ( )}
- - {/* Shapes */} -
- - -
- -
- - -
);