diff --git a/package.json b/package.json index 3f805f7..5f36b61 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,11 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "geist": "^1.3.0", + "lodash": "^4.17.21", "lucide-react": "^0.446.0", "next": "^14.2.4", + "polished": "^4.3.1", + "random": "^5.1.0", "react": "^18.3.1", "react-dom": "^18.3.1", "tailwind-merge": "^2.5.2", @@ -31,6 +34,7 @@ "@cloudflare/workers-types": "^4.20240925.0", "@playwright/test": "^1.47.2", "@types/eslint": "^8.56.10", + "@types/lodash": "^4.17.9", "@types/node": "^20.14.10", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 63f5243..b9bfecf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,12 +35,21 @@ importers: geist: specifier: ^1.3.0 version: 1.3.1(next@14.2.13(@playwright/test@1.47.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + lodash: + specifier: ^4.17.21 + version: 4.17.21 lucide-react: specifier: ^0.446.0 version: 0.446.0(react@18.3.1) next: specifier: ^14.2.4 version: 14.2.13(@playwright/test@1.47.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + polished: + specifier: ^4.3.1 + version: 4.3.1 + random: + specifier: ^5.1.0 + version: 5.1.0 react: specifier: ^18.3.1 version: 18.3.1 @@ -66,6 +75,9 @@ importers: '@types/eslint': specifier: ^8.56.10 version: 8.56.12 + '@types/lodash': + specifier: ^4.17.9 + version: 4.17.9 '@types/node': specifier: ^20.14.10 version: 20.16.10 @@ -118,6 +130,10 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@babel/runtime@7.25.6': + resolution: {integrity: sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==} + engines: {node: '>=6.9.0'} + '@cloudflare/kv-asset-handler@0.3.4': resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==} engines: {node: '>=16.13'} @@ -861,6 +877,9 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@types/lodash@4.17.9': + resolution: {integrity: sha512-w9iWudx1XWOHW5lQRS9iKpK/XuRhnN+0T7HvdCCd802FYkT1AMTnxndJHGrNJwRoRHkslGr4S29tjm1cT7x/7w==} + '@types/node-forge@1.3.11': resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} @@ -2321,6 +2340,9 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -2665,6 +2687,10 @@ packages: engines: {node: '>=18'} hasBin: true + polished@4.3.1: + resolution: {integrity: sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==} + engines: {node: '>=10'} + possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} @@ -2805,6 +2831,10 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + random@5.1.0: + resolution: {integrity: sha512-0NGG4HMW9sTstLbignEDasSQJlCGkNQZICIWStZ+h4SzSJfZXpecGKV7qL0AOKcIT8XX9pJ49uZnvI0n/Y+vWA==} + engines: {node: '>=18'} + raw-body@2.4.1: resolution: {integrity: sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==} engines: {node: '>= 0.8'} @@ -2870,6 +2900,9 @@ packages: resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} engines: {node: '>= 0.4'} + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + regexp.prototype.flags@1.5.2: resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} engines: {node: '>= 0.4'} @@ -3441,6 +3474,10 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@babel/runtime@7.25.6': + dependencies: + regenerator-runtime: 0.14.1 + '@cloudflare/kv-asset-handler@0.3.4': dependencies: mime: 3.0.0 @@ -4053,6 +4090,8 @@ snapshots: '@types/json5@0.0.29': {} + '@types/lodash@4.17.9': {} + '@types/node-forge@1.3.11': dependencies: '@types/node': 20.16.10 @@ -5754,6 +5793,8 @@ snapshots: lodash.merge@4.6.2: {} + lodash@4.17.21: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -6074,6 +6115,10 @@ snapshots: optionalDependencies: fsevents: 2.3.2 + polished@4.3.1: + dependencies: + '@babel/runtime': 7.25.6 + possible-typed-array-names@1.0.0: {} postcss-import@15.1.0(postcss@8.4.47): @@ -6155,6 +6200,8 @@ snapshots: queue-microtask@1.2.3: {} + random@5.1.0: {} + raw-body@2.4.1: dependencies: bytes: 3.1.0 @@ -6230,6 +6277,8 @@ snapshots: globalthis: 1.0.4 which-builtin-type: 1.1.4 + regenerator-runtime@0.14.1: {} + regexp.prototype.flags@1.5.2: dependencies: call-bind: 1.0.7 diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 5176be5..3ba75ec 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -3,6 +3,8 @@ import '~/styles/globals.css' import { GeistSans } from 'geist/font/sans' import { type Metadata } from 'next' +import { Background } from '~/components/background' + export const metadata: Metadata = { title: 'Create T3 App', description: 'Generated by create-t3-app', @@ -14,7 +16,10 @@ export default function RootLayout({ }: Readonly<{ children: React.ReactNode }>) { return ( - {children} + + + {children} + ) } diff --git a/src/app/page.tsx b/src/app/page.tsx index 0638181..460d7d6 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,37 +1,5 @@ -import Link from 'next/link' - export default function HomePage() { return ( -
-
-

- Create T3 App -

-
- -

First Steps →

-
- Just the basics - Everything you need to know to set up your - database and authentication. -
- - -

Documentation →

-
- Learn more about Create T3 App, the libraries it uses, and how to - deploy it. -
- -
-
-
+
) } diff --git a/src/components/background.tsx b/src/components/background.tsx new file mode 100644 index 0000000..46d7c66 --- /dev/null +++ b/src/components/background.tsx @@ -0,0 +1,110 @@ +'use client' + +import debounce from 'lodash/debounce' +import times from 'lodash/times' +import { rgba } from 'polished' +import random from 'random' +import { useEffect, useRef } from 'react' + +/** + * Draws an hexagone + * @param ctx canvas context + * @param x x coordinate + * @param y y coordinate + * @param r radius or edge length + * @param fillStyle fill style + * @param strokeStyle stroke style + */ +const drawHexagone = ( + ctx: CanvasRenderingContext2D, + x: number, + y: number, + r: number, + fillStyle: CanvasFillStrokeStyles['fillStyle'], + strokeStyle: CanvasFillStrokeStyles['strokeStyle'], +) => { + ctx.beginPath() + + ctx.moveTo(x, y - r) + + const unit = Math.PI / 3 + // anti-clockwise + times(6, (n: number) => { + const angle = Math.PI / 2 + unit * (n + 1) + ctx.lineTo(x + r * Math.cos(angle), y - r * Math.sin(angle)) + }) + ctx.closePath() + ctx.fillStyle = fillStyle + ctx.strokeStyle = strokeStyle + ctx.lineWidth = 1 + ctx.fill() + ctx.stroke() +} + +const normal = random.normal(0.75, 0.25) + +/** + * get a random x,y coordinate with provide width and height + * @param w width + * @param h height + */ +const getRandomXY = (w: number, h: number) => { + const x = Math.floor(w * Math.random()) + const y = Math.floor(h * normal()) + + return { x, y } +} + +export const Background = () => { + const canvas = useRef(null) + + // const theme = useContext(ThemeContext) + + const drawCanvasRef = useRef<() => void>() + + useEffect(() => { + const drawCanvas = () => { + const foreground = `hsl(${getComputedStyle( + document.documentElement, + ).getPropertyValue('--foreground')})` + + console.log(foreground) + if (!canvas.current) { + return + } + const cvs = canvas.current + const ctx = cvs.getContext('2d')! + const pr = window.devicePixelRatio || 1 + const w = window.innerWidth + const h = window.innerHeight + + cvs.width = w * pr + cvs.height = h * pr + cvs.style.width = `${w}px` + cvs.style.height = `${h}px` + ctx.scale(pr, pr) + ctx.clearRect(0, 0, w, h) + + times(30, () => { + const { x, y } = getRandomXY(w, h) + + drawHexagone(ctx, x, y, 50, `${rgba(foreground, 0.1)}`, 'transparent') + }) + times(30, () => { + const { x, y } = getRandomXY(w, h) + + drawHexagone(ctx, x, y, 50, 'transparent', `${rgba(foreground, 0.1)}`) + }) + } + + if (drawCanvasRef.current) { + window.removeEventListener('resize', drawCanvasRef.current) + } + drawCanvasRef.current = debounce(drawCanvas, 100) + + drawCanvas() + window.addEventListener('resize', drawCanvasRef.current) + }, [canvas]) + + return +}