diff --git a/next.config.mjs b/next.config.mjs index 36d10f9..0ff7349 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -2,6 +2,7 @@ const nextConfig = { output: 'standalone', + reactStrictMode: false, pageExtensions: ['tsx', 'ts', 'jsx', 'js', 'mdx', 'md'], experimental: { scrollRestoration: true, @@ -19,6 +20,10 @@ const nextConfig = { protocol: 'https', hostname: 'picsum.photos', }, + { + protocol: 'http', + hostname: 'localhost', + } ], }, }; diff --git a/package.json b/package.json index a327aac..7c4ee09 100644 --- a/package.json +++ b/package.json @@ -9,13 +9,22 @@ "lint": "next lint" }, "dependencies": { + "@heroicons/react": "^2.1.5", "@radix-ui/react-icons": "^1.3.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", + "get-image-colors": "^4.0.1", + "html-to-image": "^1.11.11", "lucide-react": "^0.441.0", "next": "14.2.11", + "next-themes": "^0.3.0", "react": "^18", + "react-click-away-listener": "^2.2.3", "react-dom": "^18", + "react-draggable": "^4.4.6", + "react-use-downloader": "^1.2.8", + "rgb2hex": "^0.2.5", + "sonner": "^1.5.0", "tailwind-merge": "^2.5.2", "tailwindcss-animate": "^1.0.7" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1bba9a2..5a58b06 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,9 @@ settings: excludeLinksFromLockfile: false dependencies: + '@heroicons/react': + specifier: ^2.1.5 + version: 2.1.5(react@18.3.1) '@radix-ui/react-icons': specifier: ^1.3.0 version: 1.3.0(react@18.3.1) @@ -14,18 +17,42 @@ dependencies: clsx: specifier: ^2.1.1 version: 2.1.1 + get-image-colors: + specifier: ^4.0.1 + version: 4.0.1 + html-to-image: + specifier: ^1.11.11 + version: 1.11.11 lucide-react: specifier: ^0.441.0 version: 0.441.0(react@18.3.1) next: specifier: 14.2.11 version: 14.2.11(react-dom@18.3.1)(react@18.3.1) + next-themes: + specifier: ^0.3.0 + version: 0.3.0(react-dom@18.3.1)(react@18.3.1) react: specifier: ^18 version: 18.3.1 + react-click-away-listener: + specifier: ^2.2.3 + version: 2.2.3(react-dom@18.3.1)(react@18.3.1) react-dom: specifier: ^18 version: 18.3.1(react@18.3.1) + react-draggable: + specifier: ^4.4.6 + version: 4.4.6(react-dom@18.3.1)(react@18.3.1) + react-use-downloader: + specifier: ^1.2.8 + version: 1.2.8(react@18.3.1) + rgb2hex: + specifier: ^0.2.5 + version: 0.2.5 + sonner: + specifier: ^1.5.0 + version: 1.5.0(react-dom@18.3.1)(react@18.3.1) tailwind-merge: specifier: ^2.5.2 version: 2.5.2 @@ -102,6 +129,14 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true + /@heroicons/react@2.1.5(react@18.3.1): + resolution: {integrity: sha512-FuzFN+BsHa+7OxbvAERtgBTNeZpUjgM/MIizfVkSCL2/edriN0Hx/DWRCR//aPYwO5QX/YlgLGXk+E3PcfZwjA==} + peerDependencies: + react: '>= 16' + dependencies: + react: 18.3.1 + dev: false + /@humanwhocodes/config-array@0.11.14: resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} @@ -499,7 +534,6 @@ packages: fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 - dev: true /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} @@ -636,10 +670,25 @@ packages: is-shared-array-buffer: 1.0.3 dev: true + /asn1@0.2.6: + resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} + dependencies: + safer-buffer: 2.1.2 + dev: false + + /assert-plus@1.0.0: + resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} + engines: {node: '>=0.8'} + dev: false + /ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} dev: true + /asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: false + /available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -647,6 +696,14 @@ packages: possible-typed-array-names: 1.0.0 dev: true + /aws-sign2@0.7.0: + resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} + dev: false + + /aws4@1.13.2: + resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} + dev: false + /axe-core@4.10.0: resolution: {integrity: sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==} engines: {node: '>=4'} @@ -660,10 +717,20 @@ packages: /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + /bcrypt-pbkdf@1.0.2: + resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} + dependencies: + tweetnacl: 0.14.5 + dev: false + /binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + /boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + dev: false + /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -713,6 +780,10 @@ packages: resolution: {integrity: sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg==} dev: false + /caseless@0.12.0: + resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} + dev: false + /chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -721,6 +792,30 @@ packages: supports-color: 7.2.0 dev: true + /cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + dependencies: + boolbase: 1.0.0 + css-select: 5.1.0 + css-what: 6.1.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.1.0 + dev: false + + /cheerio@1.0.0-rc.12: + resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==} + engines: {node: '>= 6'} + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.1.0 + htmlparser2: 8.0.2 + parse5: 7.1.2 + parse5-htmlparser2-tree-adapter: 7.0.0 + dev: false + /chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -735,6 +830,10 @@ packages: optionalDependencies: fsevents: 2.3.3 + /chroma-js@2.6.0: + resolution: {integrity: sha512-BLHvCB9s8Z1EV4ethr6xnkl/P2YRFOGqfgvuMG/MyCbZPrTA+NeiByY6XvgF0zP4/2deU2CXnWyMa3zu1LqQ3A==} + dev: false + /class-variance-authority@0.7.0: resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==} dependencies: @@ -745,6 +844,11 @@ packages: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} dev: false + /clsx@1.2.1: + resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} + engines: {node: '>=6'} + dev: false + /clsx@2.0.0: resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} engines: {node: '>=6'} @@ -764,6 +868,13 @@ packages: /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + /combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + dev: false + /commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -772,6 +883,10 @@ packages: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} dev: true + /core-util-is@1.0.2: + resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} + dev: false + /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -780,6 +895,21 @@ packages: shebang-command: 2.0.0 which: 2.0.2 + /css-select@5.1.0: + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.1.0 + nth-check: 2.1.1 + dev: false + + /css-what@6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + dev: false + /cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -789,10 +919,27 @@ packages: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} dev: true + /cwise-compiler@1.1.3: + resolution: {integrity: sha512-WXlK/m+Di8DMMcCjcWr4i+XzcQra9eCdXIJrgh4TUgh0pIS/yJduLxS9JgefsHJ/YVLdgPtXm9r62W92MvanEQ==} + dependencies: + uniq: 1.0.1 + dev: false + /damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} dev: true + /dashdash@1.14.1: + resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} + engines: {node: '>=0.10'} + dependencies: + assert-plus: 1.0.0 + dev: false + + /data-uri-to-buffer@0.0.3: + resolution: {integrity: sha512-Cp+jOa8QJef5nXS5hU7M1DWzXPEIoVR3kbV0dQuVGwROZg8bGf1DcCnkmajBTnvghTtSNMUdRrPjgaT6ZQucbw==} + dev: false + /data-view-buffer@1.0.1: resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} engines: {node: '>= 0.4'} @@ -889,6 +1036,11 @@ packages: object-keys: 1.1.1 dev: true + /delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dev: false + /didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} @@ -916,9 +1068,43 @@ packages: esutils: 2.0.3 dev: true + /dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + dev: false + + /domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + dev: false + + /domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: false + + /domutils@3.1.0: + resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dev: false + /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + /ecc-jsbn@0.1.2: + resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} + dependencies: + jsbn: 0.1.1 + safer-buffer: 2.1.2 + dev: false + /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -933,6 +1119,11 @@ packages: tapable: 2.2.1 dev: true + /entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + dev: false + /es-abstract@1.23.3: resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} engines: {node: '>= 0.4'} @@ -1354,9 +1545,17 @@ packages: engines: {node: '>=0.10.0'} dev: true + /extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + dev: false + + /extsprintf@1.3.0: + resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} + engines: {'0': node >=0.6.0} + dev: false + /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true /fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} @@ -1370,12 +1569,18 @@ packages: /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true /fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true + /fast-xml-parser@4.5.0: + resolution: {integrity: sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==} + hasBin: true + dependencies: + strnum: 1.0.5 + dev: false + /fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} dependencies: @@ -1428,6 +1633,19 @@ packages: cross-spawn: 7.0.3 signal-exit: 4.1.0 + /forever-agent@0.6.1: + resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} + dev: false + + /form-data@2.3.3: + resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} + engines: {node: '>= 0.12'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: false + /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true @@ -1456,6 +1674,16 @@ packages: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true + /get-image-colors@4.0.1: + resolution: {integrity: sha512-UVw9LdFemitTVCpwZY33JUkedmY1kNt0UGoneVMzbD12GkBja67/jX2AJFsJOCDefea0oCFFf9z9pa5fjKhAQw==} + dependencies: + chroma-js: 2.6.0 + get-pixels: 3.3.3 + get-rgba-palette: 2.0.1 + get-svg-colors: 2.0.1 + pify: 5.0.0 + dev: false + /get-intrinsic@1.2.4: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} @@ -1467,6 +1695,38 @@ packages: hasown: 2.0.2 dev: true + /get-pixels@3.3.3: + resolution: {integrity: sha512-5kyGBn90i9tSMUVHTqkgCHsoWoR+/lGbl4yC83Gefyr0HLIhgSWEx/2F/3YgsZ7UpYNuM6pDhDK7zebrUJ5nXg==} + dependencies: + data-uri-to-buffer: 0.0.3 + jpeg-js: 0.4.4 + mime-types: 2.1.35 + ndarray: 1.0.19 + ndarray-pack: 1.2.1 + node-bitmap: 0.0.1 + omggif: 1.0.10 + parse-data-uri: 0.2.0 + pngjs: 3.4.0 + request: 2.88.2 + through: 2.3.8 + dev: false + + /get-rgba-palette@2.0.1: + resolution: {integrity: sha512-rYbQg/u2tGnRYWuYHNMcF/nDg0WakAbQRiYLM86AE96d2MA0oYPaphsuywSoYajG0PImMZEEjKbtY4UuL/620A==} + dependencies: + quantize: 1.0.2 + dev: false + + /get-svg-colors@2.0.1: + resolution: {integrity: sha512-h1CWd6EO9hs5WOiwSqA1fb2WKoYVxnTlIYIxiZCFndMKN5iE4FXHmb6+U1o6yUbURl+IPcgZEojSQdayXDatsw==} + dependencies: + cheerio: 1.0.0-rc.12 + chroma-js: 2.6.0 + is-svg: 4.4.0 + lodash.compact: 3.0.1 + lodash.uniq: 4.5.0 + dev: false + /get-symbol-description@1.0.2: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} @@ -1482,6 +1742,12 @@ packages: resolve-pkg-maps: 1.0.0 dev: true + /getpass@0.1.7: + resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} + dependencies: + assert-plus: 1.0.0 + dev: false + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1569,6 +1835,20 @@ packages: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} dev: true + /har-schema@2.0.0: + resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} + engines: {node: '>=4'} + dev: false + + /har-validator@5.1.5: + resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==} + engines: {node: '>=6'} + deprecated: this library is no longer supported + dependencies: + ajv: 6.12.6 + har-schema: 2.0.0 + dev: false + /has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} dev: true @@ -1607,6 +1887,28 @@ packages: dependencies: function-bind: 1.1.2 + /html-to-image@1.11.11: + resolution: {integrity: sha512-9gux8QhvjRO/erSnDPv28noDZcPZmYE7e1vFsBLKLlRlKDSqNJYebj6Qz1TGd5lsRV+X+xYyjCKjuZdABinWjA==} + dev: false + + /htmlparser2@8.0.2: + resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.1.0 + entities: 4.5.0 + dev: false + + /http-signature@1.2.0: + resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} + engines: {node: '>=0.8', npm: '>=1.3.7'} + dependencies: + assert-plus: 1.0.0 + jsprim: 1.4.2 + sshpk: 1.18.0 + dev: false + /ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1646,6 +1948,10 @@ packages: side-channel: 1.0.6 dev: true + /iota-array@1.0.0: + resolution: {integrity: sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA==} + dev: false + /is-arguments@1.1.1: resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} engines: {node: '>= 0.4'} @@ -1689,6 +1995,10 @@ packages: has-tostringtag: 1.0.2 dev: true + /is-buffer@1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + dev: false + /is-bun-module@1.2.1: resolution: {integrity: sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==} dependencies: @@ -1800,6 +2110,13 @@ packages: has-tostringtag: 1.0.2 dev: true + /is-svg@4.4.0: + resolution: {integrity: sha512-v+AgVwiK5DsGtT9ng+m4mClp6zDAmwrW8nZi6Gg15qzvBnRWWdfWA1TGaXyCDnWq5g5asofIgMVl3PjKxvk1ug==} + engines: {node: '>=6'} + dependencies: + fast-xml-parser: 4.5.0 + dev: false + /is-symbol@1.0.4: resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} engines: {node: '>= 0.4'} @@ -1814,6 +2131,10 @@ packages: which-typed-array: 1.1.15 dev: true + /is-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + dev: false + /is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} @@ -1840,6 +2161,10 @@ packages: /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + /isstream@0.1.2: + resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} + dev: false + /iterator.prototype@1.1.2: resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} dependencies: @@ -1870,6 +2195,10 @@ packages: resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} hasBin: true + /jpeg-js@0.4.4: + resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==} + dev: false + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -1880,18 +2209,29 @@ packages: argparse: 2.0.1 dev: true + /jsbn@0.1.1: + resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} + dev: false + /json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} dev: true /json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true + + /json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + dev: false /json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true + /json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + dev: false + /json5@1.0.2: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true @@ -1899,6 +2239,16 @@ packages: minimist: 1.2.8 dev: true + /jsprim@1.4.2: + resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} + engines: {node: '>=0.6.0'} + dependencies: + assert-plus: 1.0.0 + extsprintf: 1.3.0 + json-schema: 0.4.0 + verror: 1.10.0 + dev: false + /jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} @@ -1952,10 +2302,18 @@ packages: p-locate: 5.0.0 dev: true + /lodash.compact@3.0.1: + resolution: {integrity: sha512-2ozeiPi+5eBXW1CLtzjk8XQFhQOEMwwfxblqeq6EGyTxZJ1bPATqilY0e6g2SLQpP4KuMeuioBhEnWz5Pr7ICQ==} + dev: false + /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true + /lodash.uniq@4.5.0: + resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + dev: false + /loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -1984,6 +2342,18 @@ packages: braces: 3.0.3 picomatch: 2.3.1 + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: false + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -2031,6 +2401,30 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true + /ndarray-pack@1.2.1: + resolution: {integrity: sha512-51cECUJMT0rUZNQa09EoKsnFeDL4x2dHRT0VR5U2H5ZgEcm95ZDWcMA5JShroXjHOejmAD/fg8+H+OvUnVXz2g==} + dependencies: + cwise-compiler: 1.1.3 + ndarray: 1.0.19 + dev: false + + /ndarray@1.0.19: + resolution: {integrity: sha512-B4JHA4vdyZU30ELBw3g7/p9bZupyew5a7tX1Y/gGeF2hafrPaQZhgrGQfsvgfYbgdFZjYwuEcnaobeM/WMW+HQ==} + dependencies: + iota-array: 1.0.0 + is-buffer: 1.1.6 + dev: false + + /next-themes@0.3.0(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==} + peerDependencies: + react: ^16.8 || ^17 || ^18 + react-dom: ^16.8 || ^17 || ^18 + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + /next@14.2.11(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-8MDFqHBhdmR2wdfaWc8+lW3A/hppFe1ggQ9vgIu/g2/2QEMYJrPoQP6b+VNk56gIug/bStysAmrpUKtj3XN8Bw==} engines: {node: '>=18.17.0'} @@ -2073,10 +2467,25 @@ packages: - babel-plugin-macros dev: false + /node-bitmap@0.0.1: + resolution: {integrity: sha512-Jx5lPaaLdIaOsj2mVLWMWulXF6GQVdyLvNSxmiYCvZ8Ma2hfKX0POoR2kgKOqz+oFsRreq0yYZjQ2wjE9VNzCA==} + engines: {node: '>=v0.6.5'} + dev: false + /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + /nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + dependencies: + boolbase: 1.0.0 + dev: false + + /oauth-sign@0.9.0: + resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} + dev: false + /object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -2150,6 +2559,10 @@ packages: es-object-atoms: 1.0.0 dev: true + /omggif@1.0.10: + resolution: {integrity: sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==} + dev: false + /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: @@ -2192,6 +2605,25 @@ packages: callsites: 3.1.0 dev: true + /parse-data-uri@0.2.0: + resolution: {integrity: sha512-uOtts8NqDcaCt1rIsO3VFDRsAfgE4c6osG4d9z3l4dCBlxYFzni6Di/oNU270SDrjkfZuUvLZx1rxMyqh46Y9w==} + dependencies: + data-uri-to-buffer: 0.0.3 + dev: false + + /parse5-htmlparser2-tree-adapter@7.0.0: + resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==} + dependencies: + domhandler: 5.0.3 + parse5: 7.1.2 + dev: false + + /parse5@7.1.2: + resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + dependencies: + entities: 4.5.0 + dev: false + /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -2221,6 +2653,10 @@ packages: engines: {node: '>=8'} dev: true + /performance-now@2.1.0: + resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} + dev: false + /picocolors@1.1.0: resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} @@ -2232,10 +2668,20 @@ packages: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} + /pify@5.0.0: + resolution: {integrity: sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==} + engines: {node: '>=10'} + dev: false + /pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} + /pngjs@3.4.0: + resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==} + engines: {node: '>=4.0.0'} + dev: false + /possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} @@ -2324,16 +2770,38 @@ packages: loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 - dev: true + + /psl@1.9.0: + resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + dev: false /punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - dev: true + + /qs@6.5.3: + resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} + engines: {node: '>=0.6'} + dev: false + + /quantize@1.0.2: + resolution: {integrity: sha512-25P7wI2UoDbIQsQp50ARkt+5pwPsOq7G/BqvT5xAbapnRoNWMN8/p55H9TXd5MuENiJnm5XICB2H2aDZGwts7w==} + engines: {node: '>=0.10.21'} + dev: false /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + /react-click-away-listener@2.2.3(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-p63JRQtK9d085+QHUJ2Pje22P/N4tEaXsS2x7tbbptriQqZ9o8xEk7G1JrxwND5YmEVc/VO4fC3+cSBsqqgLUQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + /react-dom@18.3.1(react@18.3.1): resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} peerDependencies: @@ -2344,9 +2812,29 @@ packages: scheduler: 0.23.2 dev: false + /react-draggable@4.4.6(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==} + peerDependencies: + react: '>= 16.3.0' + react-dom: '>= 16.3.0' + dependencies: + clsx: 1.2.1 + prop-types: 15.8.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + /react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - dev: true + + /react-use-downloader@1.2.8(react@18.3.1): + resolution: {integrity: sha512-JYb9esgw2TmODSCmSEFSEd/lJ0xtO50ugOu2T/PaO0JNYvscBqJT0uY452p7N5mf37jqSET7Q5DxcgixH1631Q==} + engines: {node: '>=8', npm: '>=5'} + peerDependencies: + react: ^17.0.2 || ^18 + dependencies: + react: 18.3.1 + dev: false /react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} @@ -2389,6 +2877,33 @@ packages: set-function-name: 2.0.2 dev: true + /request@2.88.2: + resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==} + engines: {node: '>= 6'} + deprecated: request has been deprecated, see https://github.com/request/request/issues/3142 + dependencies: + aws-sign2: 0.7.0 + aws4: 1.13.2 + caseless: 0.12.0 + combined-stream: 1.0.8 + extend: 3.0.2 + forever-agent: 0.6.1 + form-data: 2.3.3 + har-validator: 5.1.5 + http-signature: 1.2.0 + is-typedarray: 1.0.0 + isstream: 0.1.2 + json-stringify-safe: 5.0.1 + mime-types: 2.1.35 + oauth-sign: 0.9.0 + performance-now: 2.1.0 + qs: 6.5.3 + safe-buffer: 5.2.1 + tough-cookie: 2.5.0 + tunnel-agent: 0.6.0 + uuid: 3.4.0 + dev: false + /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -2419,6 +2934,10 @@ packages: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + /rgb2hex@0.2.5: + resolution: {integrity: sha512-22MOP1Rh7sAo1BZpDG6R5RFYzR2lYEgwq7HEmyW2qcsOqR2lQKmn+O//xV3YG/0rrhMC6KVX2hU+ZXuaw9a5bw==} + dev: false + /rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} deprecated: Rimraf versions prior to v4 are no longer supported @@ -2442,6 +2961,10 @@ packages: isarray: 2.0.5 dev: true + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: false + /safe-regex-test@1.0.3: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} @@ -2451,6 +2974,10 @@ packages: is-regex: 1.1.4 dev: true + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: false + /scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} dependencies: @@ -2519,10 +3046,36 @@ packages: engines: {node: '>=8'} dev: true + /sonner@1.5.0(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-FBjhG/gnnbN6FY0jaNnqZOMmB73R+5IiyYAw8yBj7L54ER7HB3fOSE5OFiQiE2iXWxeXKvg6fIP4LtVppHEdJA==} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + /source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + /sshpk@1.18.0: + resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==} + engines: {node: '>=0.10.0'} + hasBin: true + dependencies: + asn1: 0.2.6 + assert-plus: 1.0.0 + bcrypt-pbkdf: 1.0.2 + dashdash: 1.14.1 + ecc-jsbn: 0.1.2 + getpass: 0.1.7 + jsbn: 0.1.1 + safer-buffer: 2.1.2 + tweetnacl: 0.14.5 + dev: false + /stop-iteration-iterator@1.0.0: resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} engines: {node: '>= 0.4'} @@ -2632,6 +3185,10 @@ packages: engines: {node: '>=8'} dev: true + /strnum@1.0.5: + resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + dev: false + /styled-jsx@5.1.1(react@18.3.1): resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} engines: {node: '>= 12.0.0'} @@ -2735,12 +3292,24 @@ packages: dependencies: any-promise: 1.3.0 + /through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + dev: false + /to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} dependencies: is-number: 7.0.0 + /tough-cookie@2.5.0: + resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==} + engines: {node: '>=0.8'} + dependencies: + psl: 1.9.0 + punycode: 2.3.1 + dev: false + /ts-api-utils@1.3.0(typescript@5.6.2): resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} engines: {node: '>=16'} @@ -2766,6 +3335,16 @@ packages: resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} dev: false + /tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /tweetnacl@0.14.5: + resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} + dev: false + /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -2841,15 +3420,33 @@ packages: resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} dev: true + /uniq@1.0.1: + resolution: {integrity: sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA==} + dev: false + /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: punycode: 2.3.1 - dev: true /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + /uuid@3.4.0: + resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} + deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. + hasBin: true + dev: false + + /verror@1.10.0: + resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} + engines: {'0': node >=0.6.0} + dependencies: + assert-plus: 1.0.0 + core-util-is: 1.0.2 + extsprintf: 1.3.0 + dev: false + /which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} dependencies: diff --git a/public/assets/icons/app-store.png b/public/assets/icons/app-store.png new file mode 100644 index 0000000..fea7f61 Binary files /dev/null and b/public/assets/icons/app-store.png differ diff --git a/public/assets/icons/facebook.png b/public/assets/icons/facebook.png new file mode 100644 index 0000000..7d7b029 Binary files /dev/null and b/public/assets/icons/facebook.png differ diff --git a/public/assets/icons/google-play.png b/public/assets/icons/google-play.png new file mode 100644 index 0000000..8573edd Binary files /dev/null and b/public/assets/icons/google-play.png differ diff --git a/public/assets/icons/instagram.png b/public/assets/icons/instagram.png new file mode 100644 index 0000000..c8f1407 Binary files /dev/null and b/public/assets/icons/instagram.png differ diff --git a/public/assets/icons/landscape.png b/public/assets/icons/landscape.png new file mode 100644 index 0000000..f234389 Binary files /dev/null and b/public/assets/icons/landscape.png differ diff --git a/public/assets/icons/linkedin.png b/public/assets/icons/linkedin.png new file mode 100644 index 0000000..e003dec Binary files /dev/null and b/public/assets/icons/linkedin.png differ diff --git a/public/assets/icons/none.png b/public/assets/icons/none.png new file mode 100644 index 0000000..e2f9584 Binary files /dev/null and b/public/assets/icons/none.png differ diff --git a/public/assets/icons/portrait.png b/public/assets/icons/portrait.png new file mode 100644 index 0000000..d5c1ea7 Binary files /dev/null and b/public/assets/icons/portrait.png differ diff --git a/public/assets/icons/snapchat.png b/public/assets/icons/snapchat.png new file mode 100644 index 0000000..0f37544 Binary files /dev/null and b/public/assets/icons/snapchat.png differ diff --git a/public/assets/icons/square.png b/public/assets/icons/square.png new file mode 100644 index 0000000..3abbfe8 Binary files /dev/null and b/public/assets/icons/square.png differ diff --git a/public/assets/icons/twitter.png b/public/assets/icons/twitter.png new file mode 100644 index 0000000..a4eebab Binary files /dev/null and b/public/assets/icons/twitter.png differ diff --git a/public/assets/icons/whatsapp.png b/public/assets/icons/whatsapp.png new file mode 100644 index 0000000..b57bdda Binary files /dev/null and b/public/assets/icons/whatsapp.png differ diff --git a/public/assets/icons/youtube.png b/public/assets/icons/youtube.png new file mode 100644 index 0000000..d1916e0 Binary files /dev/null and b/public/assets/icons/youtube.png differ diff --git a/public/assets/images/placeholder.svg b/public/assets/images/placeholder.svg new file mode 100644 index 0000000..97cee96 --- /dev/null +++ b/public/assets/images/placeholder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/app/layout.tsx b/src/app/layout.tsx index a36cde0..ca2b095 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,6 +1,7 @@ import type { Metadata } from "next"; import localFont from "next/font/local"; import "./globals.css"; +import { Toaster } from "@/components/ui/sonner"; const geistSans = localFont({ src: "./fonts/GeistVF.woff", @@ -26,9 +27,12 @@ export default function RootLayout({ return ( {children} + ); diff --git a/src/app/page.tsx b/src/app/page.tsx index 977ddd1..d8242cf 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,7 +1,11 @@ +import Editor from "@/components/editor/Editor"; import { SnapcutEditor } from "@/components/snapcut-editor"; export default function Home() { return ( - + <> + {/* */} + + ); } diff --git a/src/components/editor/Editor.tsx b/src/components/editor/Editor.tsx new file mode 100644 index 0000000..e15d382 --- /dev/null +++ b/src/components/editor/Editor.tsx @@ -0,0 +1,30 @@ +"use client"; +import React, { useState } from 'react' +import Viewer from './Viewer'; +import Toolbar from './Toolbar'; +import EditorHeader from './EditorHeader'; + +type Props = {} + +const Editor = (props: Props) => { + const [img, setImg] = useState(null); + + const onImageChange = (e) => { + if (e.target.files.length !== 0) { + const [file] = e.target.files; + setImg(URL.createObjectURL(file)); + } + }; + + return ( +
+ + + +
+ ) +} + +export default Editor \ No newline at end of file diff --git a/src/components/editor/EditorHeader.tsx b/src/components/editor/EditorHeader.tsx new file mode 100644 index 0000000..0c8f8d0 --- /dev/null +++ b/src/components/editor/EditorHeader.tsx @@ -0,0 +1,62 @@ +"use client" +import { useState, useEffect, useCallback } from 'react' +import { + Moon, + Sun, + Github, + Upload, + Wand2, + Layers, + Paintbrush, + Maximize2, + CornerUpLeft, + Square, + Cloud, + Share2, + Download +} from 'lucide-react' +import Image from 'next/image' +import { toast } from 'sonner' +type Props = {} + +const EditorHeader = (props: Props) => { + const [darkMode, setDarkMode] = useState(false) + const [mounted, setMounted] = useState(false) + useEffect(() => { + setMounted(true) + }, []) + + const toggleDarkMode = () => setDarkMode(!darkMode) + + return ( +
+

+ SnapCut +

+
+ {/* */} + + + GitHub + +
+
+ ) +} + +export default EditorHeader \ No newline at end of file diff --git a/src/components/editor/Toolbar.tsx b/src/components/editor/Toolbar.tsx new file mode 100644 index 0000000..8278010 --- /dev/null +++ b/src/components/editor/Toolbar.tsx @@ -0,0 +1,64 @@ +"use client" +import React, { useEffect } from "react"; +import Background from "./tools/background/Background"; +import Corners from "./tools/corners/Corners"; +import Padding from "./tools/padding/Padding"; +import Shadow from "./tools/shadow/Shadow"; +import Download from "./tools/download/Download"; +import Resize from "./tools/resize/Resize"; +import useClipboardImage from "./tools/clipboard/Clipboard"; +import CopyClipboard from "./tools/clipboard/CopyClipboard"; +import { UploadIcon } from "@radix-ui/react-icons"; + + +export default function Toolbar({ onImageChange, img }) { + useClipboardImage(onImageChange); + return ( + <> +
+
+ {/* If no image selected we will show big upload button */} + {!img && ( + + )} + {/* All options are visible when an image is selected */} + {img && ( +
+
+ + + + {/* */} + + + + +
+
+ )} +
+ +
+ + ); +} diff --git a/src/components/editor/Viewer.tsx b/src/components/editor/Viewer.tsx new file mode 100644 index 0000000..5fa8d78 --- /dev/null +++ b/src/components/editor/Viewer.tsx @@ -0,0 +1,49 @@ +"use client"; +import Image from 'next/image'; +import React, { useState, useEffect } from 'react' +import Draggable from 'react-draggable'; + + +type Props = { + img: string | null +} + +const Viewer = ({ img }: Props) => { + const [imgH, setImgH] = useState(0); + const [imgW, setImgW] = useState(0); + + useEffect(() => { + // if (document) { + setImgH(document?.getElementById("parent-img")?.offsetHeight || 0); + setImgW(document?.getElementById("parent-img")?.offsetWidth || 0); + // } + }); + + return ( +
+
+
+ + Editable image + +
+
+
+ ) +} + +export default Viewer \ No newline at end of file diff --git a/src/components/editor/tools/background/Background.js b/src/components/editor/tools/background/Background.js new file mode 100644 index 0000000..1e99444 --- /dev/null +++ b/src/components/editor/tools/background/Background.js @@ -0,0 +1,689 @@ +"use client" +import { PaintBrushIcon } from "@heroicons/react/24/outline"; +import { useEffect, useState } from "react"; +import ClickAwayListener from "react-click-away-listener"; +import Color from "./Color"; +const getColors = require("get-image-colors"); +var rgb2hex = require("rgb2hex"); + +export default function Background({ img }) { + const [isVisible, setIsVisible] = useState(false); + const [colors, setColors] = useState([]); + // Click away handle + const handleClickAway = () => { + setIsVisible(false); + }; + useEffect(() => { + if (img !== undefined) { + getColors(img).then((clr) => { + // `colors` is an array of color objects + setColors(clr); + }); + } + }, [img]); + useEffect(() => { + if (colors.length !== 0) { + document.getElementById( + "my-node" + ).style.backgroundColor = `rgb( ${colors[0]._rgb[0]} , ${colors[0]._rgb[1]} , ${colors[0]._rgb[2]})`; + } + }, [colors]); + return ( + <> +
setIsVisible(true)} + > + +
+ {isVisible && ( +
+ +
+ +
+
+
setIsVisible(false)} + >
+
setIsVisible(false)} + >
+
setIsVisible(false)} + >
+
+
+ {/* content */} +

+ Colors Extraced from your Image: +

+
+ {colors.map((color, index) => ( + + (document.getElementById( + "my-node" + ).style.backgroundColor = color.hex()) & + setIsVisible(false) & + (document.getElementById( + "my-node" + ).style.backgroundImage = "") + } + > + + + ))} +
+

Gradients:

+
+ + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(150deg, rgb(0, 176, 158), rgb(19, 77, 93), rgb(16, 23, 31))") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(326deg, #bd4f6c 0%, #d7816a 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(326deg, #861657 0%, #ffa69e 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(326deg, #a4508b 0%, #5f0a87 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #20bf55 0%, #01baef 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #7cffcb 0%, #74f2ce 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #a40606 0%, #d98324 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #0cbaba 0%, #380036 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #eec0c6 0%, #e58c8a 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #7ee8fa 0%, #80ff72 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #eec0c6 0%, #7ee8fa 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #ff4e00 0%, #ec9f05 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #b3cdd1 0%, #9fa4c4 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #9fa4c4 0%, #9e768f 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + " linear-gradient(315deg, #bdd4e7 0%, #8693ab 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #d387ab 0%, #b279a7 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #e899dc 0%, #d387ab 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #7f5a83 0%, #0d324d 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #6b0f1a 0%, #b91372 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #772f1a 0%, #f2a65a 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #9e8fb2 0%, #a7acd9 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #ebbe9b 0%, #e7a977 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #ffac81 0%, #ff928b 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #63d471 0%, #233329 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #e9bcb7 0%, #29524a 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #3f0d12 0%, #a71d31 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #2a2a72 0%, #009ffd 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #00b712 0%, #5aff15 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #f7b42c 0%, #fc575e 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #90d5ec 0%, #fc575e 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #f9c1b1 0%, #fb8085 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #abe9cd 0%, #3eadcf 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #f8ceec 0%, #a88beb 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #fad0c4 0%, #f1a7f1 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #f9d29d 0%, #ffd8cb 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #d5adc8 0%, #ff8489 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #f39f86 0%, #f9d976 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #fce043 0%, #fb7ba2 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #36096d 0%, #37d5d6 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #ffcfdf 0%, #b0f3f1 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #5de6de 0%, #b58ecc 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #f6f0c4 0%, #d99ec9 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #b8c6db 0%, #f5f7fa 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #7f53ac 0%, #647dee 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #f1dfd1 0%, #f6f0ea 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #63a4ff 0%, #83eaf1 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #bbf0f3 0%, #f6d285 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #d8dede 0%, #e5bdf6 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #f8f9d2 0%, #e8dbfc 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #deebdd 0%, #bbdbbe 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #3bb78f 0%, #0bab64 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #045de9 0%, #09c6f9 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #9eabe4 0%, #77eed8 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(315deg, #b1bfd8 0%, #6782b4 74%)") & + setIsVisible(false) + } + /> + + (document.getElementById( + "my-node" + ).style.backgroundImage = + "linear-gradient(90deg, #4b6cb7 0%, #182848 100%)") & + setIsVisible(false) + } + /> +
+
+

+ Custom Color: +

+ + (e.target.value = rgb2hex( + document.getElementById("my-node").style + .backgroundColor + ).hex) + } + onChange={(e) => { + (document.getElementById( + "my-node" + ).style.backgroundColor = e.target.value) & + (document.getElementById( + "my-node" + ).style.backgroundImage = ""); + }} + /> +
+
+
+
+
+
+
+ )} + + ); +} diff --git a/src/components/editor/tools/background/Color.js b/src/components/editor/tools/background/Color.js new file mode 100644 index 0000000..5582e8b --- /dev/null +++ b/src/components/editor/tools/background/Color.js @@ -0,0 +1,13 @@ +"use client" +import React from 'react' +export default function color({ bgcolor, onClick }) { + const divstyle = "inline-flex w-24 h-24 active:scale-95 rounded-full m-1 ring-2 ring-transparent shadow-md hover:ring-gray-300 " + bgcolor; + function clickFun() { + onClick() + localStorage.setItem('lastColor', document.getElementById('my-node').style.backgroundImage) + } + return ( +
+
+ ) +} \ No newline at end of file diff --git a/src/components/editor/tools/clipboard/Clipboard.js b/src/components/editor/tools/clipboard/Clipboard.js new file mode 100644 index 0000000..4e41566 --- /dev/null +++ b/src/components/editor/tools/clipboard/Clipboard.js @@ -0,0 +1,25 @@ +"use client" +import { useEffect } from "react"; + +export default function useClipboardImage(onImageChange) { + const handlePaste = async (event) => { + let clipboardItems = event.clipboardData || window.clipboardData; + for (let i = 0; i < clipboardItems.items.length; i++) { + if (clipboardItems.items[i].type.indexOf("image") === 0) { + let blob = clipboardItems.items[i].getAsFile(); + let reader = new FileReader(); + reader.onload = function (evt) { + onImageChange({ target: { files: [new File([blob], "pasted-image.png")] } }); + }; + reader.readAsArrayBuffer(blob); + } + } + }; + + useEffect(() => { + window.addEventListener('paste', handlePaste); + return () => { + window.removeEventListener('paste', handlePaste); + }; + }, [onImageChange]); +} diff --git a/src/components/editor/tools/clipboard/CopyClipboard.js b/src/components/editor/tools/clipboard/CopyClipboard.js new file mode 100644 index 0000000..9f30127 --- /dev/null +++ b/src/components/editor/tools/clipboard/CopyClipboard.js @@ -0,0 +1,180 @@ +"use client" +import { ArrowDownTrayIcon, ClipboardIcon } from "@heroicons/react/24/outline"; +import React, { useEffect } from "react"; +import * as htmlToImage from "html-to-image"; +import { useState } from "react"; +import ClickAwayListener from "react-click-away-listener"; +// import { toast } from "react-toastify"; +// import imgConverter from "image-converter-pro"; +import { toast } from "sonner"; +import { imgConverter } from "@/lib/image-converter"; + + +export default function CopyClipboard() { + const [isVisible, setIsVisible] = useState(false); + const [isCopyButtonDisabled, setIsCopyButtonDisabled] = + useState(false); + const [copyFormat, setCopyFormat] = useState("png"); // png by default + // Click away handle + const handleClickAway = () => { + setIsVisible(false); + }; + function copyToClipboard(size) { + setIsVisible(false); + setIsCopyButtonDisabled(true); + // toast.info("Starting Copy...", { toastId: "start" }); + toast.info("Starting Copy...", { id: "start" }); + document.getElementById("my-node").style.transform = "scale(1)"; //imp + let width = document.getElementById("my-node").offsetWidth; + let height = document.getElementById("my-node").offsetHeight; + let style = { borderRadius: 0 }; + htmlToImage + .toSvg(document.getElementById("my-node"), { + style: style, + }) + .then(function (dataUrl) { + imgConverter( + dataUrl, + width, + height, + copyFormat, + size / height + ).then((dataUri) => { + let img = new Image(); + img.onload = function () { + let canvas = document.createElement('canvas'); + canvas.width = img.width; + canvas.height = img.height; + let ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0); + canvas.toBlob(function (blob) { + let item = new ClipboardItem({ ['image/' + copyFormat]: blob }); + navigator.clipboard.write([item]).then(() => { + toast.dismiss("start"); + toast.success("Copied to Clipboard Successfully!"); + setIsCopyButtonDisabled(false); + }).catch((error) => { + toast.dismiss("start"); + toast.error("Failed to Copy to Clipboard!"); + setIsCopyButtonDisabled(false); + }); + }); + }; + img.src = dataUri; + }); + }); + } + return ( + <> +
+ +
+ {isVisible && ( +
+ +
+ +
+
+
setIsVisible(false)} + >
+
setIsVisible(false)} + >
+
setIsVisible(false)} + >
+
+
+ {/* content */} +
+ {/* SD */} +
copyToClipboard(480)} + > +
+ SD +
+ 480p +
+ {/* HD */} +
copyToClipboard(720)} + > +
+ HD +
+ 720p +
+ {/* FHD */} +
copyToClipboard(1080)} + > +
+ FHD +
+ 1080p +
+ {/* 2K */} +
copyToClipboard(1440)} + > +
+ 2K +
+ 1440p +
+ {/* 4K */} +
copyToClipboard(2160)} + > +
+ 4K +
+ 2160p +
+ {/* 8K */} +
copyToClipboard(4320)} + > +
+ 8K +
+ 4320p +
+
+
+
+
+
+
+
+ )} + + ); +} diff --git a/src/components/editor/tools/corners/Corners.js b/src/components/editor/tools/corners/Corners.js new file mode 100644 index 0000000..a021efd --- /dev/null +++ b/src/components/editor/tools/corners/Corners.js @@ -0,0 +1,137 @@ +"use client" +import { CursorArrowRippleIcon } from "@heroicons/react/24/outline"; +import { useState } from "react"; +import ClickAwayListener from "react-click-away-listener"; + +export default function Corners() { + const [isVisible, setIsVisible] = useState(false); + // Click away handle + const handleClickAway = () => { + setIsVisible(false); + }; + function setBorderRadius(r) { + document.getElementById("parent-img").style.borderRadius = `${r}rem`; + } + return ( + <> +
setIsVisible(true)} + > + +
+ {isVisible && ( +
+ +
+ +
+
+
setIsVisible(false)} + >
+
setIsVisible(false)} + >
+
setIsVisible(false)} + >
+
+
+ {/* content */} + {/* None */} +
setBorderRadius(0)} + > +
+ None +
+ {/* Basic */} +
setBorderRadius(0.25)} + > +
+ Basic +
+ {/* Small */} +
setBorderRadius(0.125)} + > +
+ Small +
+ {/* Medium */} +
setBorderRadius(0.375)} + > +
+ Medium +
+ {/* Large */} +
setBorderRadius(0.5)} + > +
+ Large +
+ {/* XL */} +
setBorderRadius(0.75)} + > +
+ XL +
+ {/* 2XL */} +
setBorderRadius(1)} + > +
+ 2XL +
+ {/* 3XL */} +
setBorderRadius(1.5)} + > +
+ 3XL +
+ {/* Full */} +
setBorderRadius(9999)} + > +
+ Full +
+
+
+ +
+ +
+ )} + + ); +} diff --git a/src/components/editor/tools/download/Download.js b/src/components/editor/tools/download/Download.js new file mode 100644 index 0000000..9280ffc --- /dev/null +++ b/src/components/editor/tools/download/Download.js @@ -0,0 +1,217 @@ +"use client" +import { ArrowDownTrayIcon } from "@heroicons/react/24/outline"; +import React, { useEffect } from "react"; +import * as htmlToImage from "html-to-image"; +import { useState } from "react"; +import ClickAwayListener from "react-click-away-listener"; +// import { toast } from "react-toastify"; +// import imgConverter from "image-converter-pro"; +import { toast } from "sonner"; +import { imgConverter } from "@/lib/image-converter"; + +export default function Download() { + const [isVisible, setIsVisible] = useState(false); + const [isDownloadButtonDisabled, setIsDownloadButtonDisabled] = + useState(false); + const [downloadFormat, setDownloadFormat] = useState("png"); + // Click away handle + const handleClickAway = () => { + setIsVisible(false); + }; + function downloadCustom(size) { + setIsVisible(false); + setIsDownloadButtonDisabled(true); + toast.info("Starting Download...", { toastId: "start" }); + document.getElementById("my-node").style.transform = "scale(1)"; //imp + let width = document.getElementById("my-node").offsetWidth; + let height = document.getElementById("my-node").offsetHeight; + let style = { borderRadius: 0 }; + // JPG + htmlToImage + .toSvg(document.getElementById("my-node"), { + style: style, + }) + .then(function (dataUrl) { + var link = document.createElement("a"); + imgConverter( + dataUrl, + width, + height, + downloadFormat, + size / height + ).then((dataUri) => { + link.download = `spiffy.${downloadFormat}`; + link.href = dataUri; + link.click(); + toast.dismiss("start"); + toast.success("Downloaded Successfully!"); + setIsDownloadButtonDisabled(false); + }); + }); + } + useEffect(() => { + if (isVisible) { + document.getElementById(downloadFormat).checked = true; + } + }, [isVisible]); + return ( + <> +
+ +
+ {isVisible && ( +
+ +
+ +
+
+
setIsVisible(false)} + >
+
setIsVisible(false)} + >
+
setIsVisible(false)} + >
+
+
+ {/* content */} +
+ {/* SD */} +
downloadCustom(480)} + > +
+ SD +
+ 480p +
+ {/* HD */} +
downloadCustom(720)} + > +
+ HD +
+ 720p +
+ {/* FHD */} +
downloadCustom(1080)} + > +
+ FHD +
+ 1080p +
+ {/* 2K */} +
downloadCustom(1440)} + > +
+ 2K +
+ 1440p +
+ {/* 4K */} +
downloadCustom(2160)} + > +
+ 4K +
+ 2160p +
+ {/* 8K */} +
downloadCustom(4320)} + > +
+ 8K +
+ 4320p +
+
+
+
setDownloadFormat(e.target.value)} + > + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+ )} + + ); +} diff --git a/src/components/editor/tools/padding/Padding.js b/src/components/editor/tools/padding/Padding.js new file mode 100644 index 0000000..2fddea4 --- /dev/null +++ b/src/components/editor/tools/padding/Padding.js @@ -0,0 +1,88 @@ +"use client" +import { ViewfinderCircleIcon } from "@heroicons/react/24/outline"; +import { useEffect, useState } from "react"; +import ClickAwayListener from "react-click-away-listener"; + +export default function Padding() { + const [isVisible, setIsVisible] = useState(false); + const [pVal, setPVal] = useState(1.5); + // Click away handle + const handleClickAway = () => { + setIsVisible(false); + }; + // Padding Persists on Session Switch + useEffect(() => { + const plocal = localStorage.getItem("betterscreensort_p"); + // If padding value exists in local storage, we will set its value to pval + if (plocal) { + setPVal(plocal); + document.getElementById("my-node").style.padding = `${plocal}rem`; + } + }, []); + + function setPadding() { + localStorage.setItem("betterscreensort_p", pVal); + document.getElementById("my-node").style.padding = `${pVal}rem`; + } + return ( + <> +
setIsVisible(true)} + > + +
+ {isVisible && ( +
+ +
+ +
+
+
setIsVisible(false)} + >
+
setIsVisible(false)} + >
+
setIsVisible(false)} + >
+
+
+ {/* content */} + 0rem + setPVal(e.target.value) & setPadding()} + step={0.25} + value={pVal} + className="w-6/12 accent-indigo-500 dark:accent-indigo-300 -mb-1.5" + /> + 5rem +
+
+
+
+
+
+ )} + + ); +} diff --git a/src/components/editor/tools/resize/Resize.js b/src/components/editor/tools/resize/Resize.js new file mode 100644 index 0000000..eed044a --- /dev/null +++ b/src/components/editor/tools/resize/Resize.js @@ -0,0 +1,155 @@ +"use client" +import { ArrowsPointingOutIcon } from "@heroicons/react/24/outline"; +import { useState } from "react"; +import ClickAwayListener from "react-click-away-listener"; +import Resizer from "./Resizer"; + +export default function Resize() { + const [isVisible, setIsVisible] = useState(false); + // Click away handle + const handleClickAway = () => { + setIsVisible(false); + }; + return ( + <> +
setIsVisible(true)} + > + +
+ {isVisible && ( +
+ +
+ +
+
+
setIsVisible(false)} + >
+
setIsVisible(false)} + >
+
setIsVisible(false)} + >
+
+
+ {/* content */} + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+ )} + + ); +} diff --git a/src/components/editor/tools/resize/Resizer.js b/src/components/editor/tools/resize/Resizer.js new file mode 100644 index 0000000..eac177e --- /dev/null +++ b/src/components/editor/tools/resize/Resizer.js @@ -0,0 +1,28 @@ +"use client" +import Image from "next/image"; +import React from "react"; + +export default function Resizer({ app, label, aspect, ring = false }) { + function resizerFun() { + document.getElementById("my-node").style.aspectRatio = aspect; + document.getElementById("close-btn").click(); + } + return ( +
+
+ {label} +
+ {label} +
+ ); +} diff --git a/src/components/editor/tools/shadow/Shadow.js b/src/components/editor/tools/shadow/Shadow.js new file mode 100644 index 0000000..4606993 --- /dev/null +++ b/src/components/editor/tools/shadow/Shadow.js @@ -0,0 +1,107 @@ +"use client" +import { + RectangleStackIcon, +} from "@heroicons/react/24/outline"; +import { useState } from "react"; +import ClickAwayListener from "react-click-away-listener"; + +export default function Shadow() { + const [isVisible, setIsVisible] = useState(false); + // Click away handle + const handleClickAway = () => { + setIsVisible(false); + }; + function setShadow(s) { + document.getElementById("parent-img").style.boxShadow = `${s}`; + } + return ( + <> +
setIsVisible(true)} + > + +
+ {isVisible && ( +
+ +
+ +
+
+
setIsVisible(false)} + >
+
setIsVisible(false)} + >
+
setIsVisible(false)} + >
+
+
+ {/* content */} + Hover to see Shadow Effect + + {/* None */} +
setShadow("0 0 #0000")} + > +
+ None +
+ {/* Small */} +
setShadow("0 1px 2px 0 rgb(0 0 0 / 0.05)")} + > +
+ Small +
+ {/* Large */} +
+ setShadow( + "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)" + ) + } + > +
+ Large +
+ {/* 2XL */} +
+ setShadow("0 25px 50px -12px rgb(0 0 0 / 0.25)") + } + > +
+ 2XL +
+
+
+ +
+ +
+ )} + + ); +} diff --git a/src/components/snapcut-editor.tsx b/src/components/snapcut-editor.tsx index a53ebab..a563e66 100644 --- a/src/components/snapcut-editor.tsx +++ b/src/components/snapcut-editor.tsx @@ -17,6 +17,7 @@ import { Download } from 'lucide-react' import Image from 'next/image' +import { toast } from 'sonner' export function SnapcutEditor() { const [darkMode, setDarkMode] = useState(false) @@ -61,7 +62,7 @@ export function SnapcutEditor() { return (
-

+

SnapCut

@@ -145,6 +146,10 @@ export function SnapcutEditor() {