diff --git a/Basin/next.config.js b/Basin/next.config.js new file mode 100644 index 0000000..0e5d877 --- /dev/null +++ b/Basin/next.config.js @@ -0,0 +1,22 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + async headers() { + return [ + { + source: '/(.*)', + headers: [ + { key: 'X-Content-Type-Options', value: 'nosniff' }, + { key: 'X-Frame-Options', value: 'DENY' }, + { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' }, + { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' }, + { + key: 'Content-Security-Policy', + value: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' https: data:; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self';" + }, + ], + }, + ]; + }, +}; + +module.exports = nextConfig; diff --git a/Basin/package-lock.json b/Basin/package-lock.json index 0d357c1..31f8d58 100644 --- a/Basin/package-lock.json +++ b/Basin/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "clsx": "^2.1.0", "lucide-react": "^0.344.0", - "next": "^14.0.4", + "next": "^14.2.30", "react": "^18.3.1", "react-dom": "^18.3.1", "tailwind-merge": "^2.2.1" @@ -21,7 +21,7 @@ "@types/react-dom": "^18.3.0", "autoprefixer": "^10.4.18", "eslint": "^8.56.0", - "eslint-config-next": "^14.0.4", + "eslint-config-next": "^14.2.30", "postcss": "^8.4.35", "tailwindcss": "^3.4.1", "typescript": "^5.5.3" @@ -200,15 +200,15 @@ } }, "node_modules/@next/env": { - "version": "14.2.20", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.20.tgz", - "integrity": "sha512-JfDpuOCB0UBKlEgEy/H6qcBSzHimn/YWjUHzKl1jMeUO+QVRdzmTTl8gFJaNO87c8DXmVKhFCtwxQ9acqB3+Pw==", + "version": "14.2.35", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.35.tgz", + "integrity": "sha512-DuhvCtj4t9Gwrx80dmz2F4t/zKQ4ktN8WrMwOuVzkJfBilwAwGr6v16M5eI8yCuZ63H9TTuEU09Iu2HqkzFPVQ==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { - "version": "14.2.20", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.2.20.tgz", - "integrity": "sha512-T0JRi706KLbvR1Uc46t56VtawbhR/igdBagzOrA7G+vv4rvjwnlu/Y4/Iq6X9TDVj5UZjyot4lUdkNd3V2kLhw==", + "version": "14.2.35", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.2.35.tgz", + "integrity": "sha512-Jw9A3ICz2183qSsqwi7fgq4SBPiNfmOLmTPXKvlnzstUwyvBrtySiY+8RXJweNAs9KThb1+bYhZh9XWcNOr2zQ==", "dev": true, "license": "MIT", "dependencies": { @@ -216,9 +216,9 @@ } }, "node_modules/@next/eslint-plugin-next/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -229,6 +229,7 @@ "version": "10.3.10", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { @@ -268,13 +269,13 @@ } }, "node_modules/@next/eslint-plugin-next/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -284,9 +285,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "14.2.20", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.20.tgz", - "integrity": "sha512-WDfq7bmROa5cIlk6ZNonNdVhKmbCv38XteVFYsxea1vDJt3SnYGgxLGMTXQNfs5OkFvAhmfKKrwe7Y0Hs+rWOg==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.33.tgz", + "integrity": "sha512-HqYnb6pxlsshoSTubdXKu15g3iivcbsMXg4bYpjL2iS/V6aQot+iyF4BUc2qA/J/n55YtvE4PHMKWBKGCF/+wA==", "cpu": [ "arm64" ], @@ -300,9 +301,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "14.2.20", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.20.tgz", - "integrity": "sha512-XIQlC+NAmJPfa2hruLvr1H1QJJeqOTDV+v7tl/jIdoFvqhoihvSNykLU/G6NMgoeo+e/H7p/VeWSOvMUHKtTIg==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.33.tgz", + "integrity": "sha512-8HGBeAE5rX3jzKvF593XTTFg3gxeU4f+UWnswa6JPhzaR6+zblO5+fjltJWIZc4aUalqTclvN2QtTC37LxvZAA==", "cpu": [ "x64" ], @@ -316,9 +317,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.2.20", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.20.tgz", - "integrity": "sha512-pnzBrHTPXIMm5QX3QC8XeMkpVuoAYOmyfsO4VlPn+0NrHraNuWjdhe+3xLq01xR++iCvX+uoeZmJDKcOxI201Q==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.33.tgz", + "integrity": "sha512-JXMBka6lNNmqbkvcTtaX8Gu5by9547bukHQvPoLe9VRBx1gHwzf5tdt4AaezW85HAB3pikcvyqBToRTDA4DeLw==", "cpu": [ "arm64" ], @@ -332,9 +333,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.2.20", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.20.tgz", - "integrity": "sha512-WhJJAFpi6yqmUx1momewSdcm/iRXFQS0HU2qlUGlGE/+98eu7JWLD5AAaP/tkK1mudS/rH2f9E3WCEF2iYDydQ==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.33.tgz", + "integrity": "sha512-Bm+QulsAItD/x6Ih8wGIMfRJy4G73tu1HJsrccPW6AfqdZd0Sfm5Imhgkgq2+kly065rYMnCOxTBvmvFY1BKfg==", "cpu": [ "arm64" ], @@ -348,9 +349,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.2.20", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.20.tgz", - "integrity": "sha512-ao5HCbw9+iG1Kxm8XsGa3X174Ahn17mSYBQlY6VGsdsYDAbz/ZP13wSLfvlYoIDn1Ger6uYA+yt/3Y9KTIupRg==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.33.tgz", + "integrity": "sha512-FnFn+ZBgsVMbGDsTqo8zsnRzydvsGV8vfiWwUo1LD8FTmPTdV+otGSWKc4LJec0oSexFnCYVO4hX8P8qQKaSlg==", "cpu": [ "x64" ], @@ -364,9 +365,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "14.2.20", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.20.tgz", - "integrity": "sha512-CXm/kpnltKTT7945np6Td3w7shj/92TMRPyI/VvveFe8+YE+/YOJ5hyAWK5rpx711XO1jBCgXl211TWaxOtkaA==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.33.tgz", + "integrity": "sha512-345tsIWMzoXaQndUTDv1qypDRiebFxGYx9pYkhwY4hBRaOLt8UGfiWKr9FSSHs25dFIf8ZqIFaPdy5MljdoawA==", "cpu": [ "x64" ], @@ -380,9 +381,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.2.20", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.20.tgz", - "integrity": "sha512-upJn2HGQgKNDbXVfIgmqT2BN8f3z/mX8ddoyi1I565FHbfowVK5pnMEwauvLvaJf4iijvuKq3kw/b6E9oIVRWA==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.33.tgz", + "integrity": "sha512-nscpt0G6UCTkrT2ppnJnFsYbPDQwmum4GNXYTeoTIdsmMydSKFz9Iny2jpaRupTb+Wl298+Rh82WKzt9LCcqSQ==", "cpu": [ "arm64" ], @@ -396,9 +397,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.2.20", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.20.tgz", - "integrity": "sha512-igQW/JWciTGJwj3G1ipalD2V20Xfx3ywQy17IV0ciOUBbFhNfyU1DILWsTi32c8KmqgIDviUEulW/yPb2FF90w==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.33.tgz", + "integrity": "sha512-pc9LpGNKhJ0dXQhZ5QMmYxtARwwmWLpeocFmVG5Z0DzWq5Uf0izcI8tLc+qOpqxO1PWqZ5A7J1blrUIKrIFc7Q==", "cpu": [ "ia32" ], @@ -412,9 +413,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.2.20", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.20.tgz", - "integrity": "sha512-AFmqeLW6LtxeFTuoB+MXFeM5fm5052i3MU6xD0WzJDOwku6SkZaxb1bxjBaRC8uNqTRTSPl0yMFtjNowIVI67w==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.33.tgz", + "integrity": "sha512-nOjfZMy8B94MdisuzZo9/57xuFVLHJaDj5e/xrduJp9CV2/HrfxTRH2fbyLe+K9QT41WBLUd4iXX3R7jBp0EUg==", "cpu": [ "x64" ], @@ -542,6 +543,7 @@ "integrity": "sha512-opAQ5no6LqJNo9TqnxBKsgnkIYHozW9KSTlFVoSUJYh1Fl/sswkEoqIugRSm7tbh6pABtYjGAjW+GOS23j8qbw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -593,6 +595,7 @@ "integrity": "sha512-rBnTWHCdbYM2lh7hjyXqxk70wvon3p2FyaniZuey5TrcGBpfhVp0OxOa6gxr9Q9YhZFKyfbEnxc24ZnVbbUkCA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.18.1", "@typescript-eslint/types": "8.18.1", @@ -802,6 +805,7 @@ "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1188,6 +1192,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001663", "electron-to-chromium": "^1.5.28", @@ -1749,6 +1754,7 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -1800,13 +1806,13 @@ } }, "node_modules/eslint-config-next": { - "version": "14.2.20", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.2.20.tgz", - "integrity": "sha512-gHBvp4RDd51DAaDco7KiWFy731EwcItkDtGUaZH1EUXEnHCzsVRjMceT+b8aThjMLjOScz6Q27MGlePASvK4Aw==", + "version": "14.2.35", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.2.35.tgz", + "integrity": "sha512-BpLsv01UisH193WyT/1lpHqq5iJ/Orfz9h/NOOlAmTUq4GY349PextQ62K4XpnaM9supeiEn3TaOTeQO07gURg==", "dev": true, "license": "MIT", "dependencies": { - "@next/eslint-plugin-next": "14.2.20", + "@next/eslint-plugin-next": "14.2.35", "@rushstack/eslint-patch": "^1.3.3", "@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", @@ -3515,12 +3521,12 @@ "dev": true }, "node_modules/next": { - "version": "14.2.20", - "resolved": "https://registry.npmjs.org/next/-/next-14.2.20.tgz", - "integrity": "sha512-yPvIiWsiyVYqJlSQxwmzMIReXn5HxFNq4+tlVQ812N1FbvhmE+fDpIAD7bcS2mGYQwPJ5vAsQouyme2eKsxaug==", + "version": "14.2.35", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.35.tgz", + "integrity": "sha512-KhYd2Hjt/O1/1aZVX3dCwGXM1QmOV4eNM2UTacK5gipDdPN/oHHK/4oVGy7X8GMfPMsUTUEmGlsy0EY1YGAkig==", "license": "MIT", "dependencies": { - "@next/env": "14.2.20", + "@next/env": "14.2.35", "@swc/helpers": "0.5.5", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", @@ -3535,15 +3541,15 @@ "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "14.2.20", - "@next/swc-darwin-x64": "14.2.20", - "@next/swc-linux-arm64-gnu": "14.2.20", - "@next/swc-linux-arm64-musl": "14.2.20", - "@next/swc-linux-x64-gnu": "14.2.20", - "@next/swc-linux-x64-musl": "14.2.20", - "@next/swc-win32-arm64-msvc": "14.2.20", - "@next/swc-win32-ia32-msvc": "14.2.20", - "@next/swc-win32-x64-msvc": "14.2.20" + "@next/swc-darwin-arm64": "14.2.33", + "@next/swc-darwin-x64": "14.2.33", + "@next/swc-linux-arm64-gnu": "14.2.33", + "@next/swc-linux-arm64-musl": "14.2.33", + "@next/swc-linux-x64-gnu": "14.2.33", + "@next/swc-linux-x64-musl": "14.2.33", + "@next/swc-win32-arm64-msvc": "14.2.33", + "@next/swc-win32-ia32-msvc": "14.2.33", + "@next/swc-win32-x64-msvc": "14.2.33" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", @@ -3939,6 +3945,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.0", @@ -4131,6 +4138,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -4143,6 +4151,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -5028,6 +5037,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "dev": true, + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/Basin/package.json b/Basin/package.json index 078f82f..415f3d8 100644 --- a/Basin/package.json +++ b/Basin/package.json @@ -9,11 +9,11 @@ "lint": "next lint" }, "dependencies": { - "next": "14.2.35", + "clsx": "^2.1.0", + "lucide-react": "^0.344.0", + "next": "^14.2.30", "react": "^18.3.1", "react-dom": "^18.3.1", - "lucide-react": "^0.344.0", - "clsx": "^2.1.0", "tailwind-merge": "^2.2.1" }, "devDependencies": { @@ -22,7 +22,7 @@ "@types/react-dom": "^18.3.0", "autoprefixer": "^10.4.18", "eslint": "^8.56.0", - "eslint-config-next": "^14.0.4", + "eslint-config-next": "^14.2.30", "postcss": "^8.4.35", "tailwindcss": "^3.4.1", "typescript": "^5.5.3" diff --git a/Basin/public/email-signature/index.html b/Basin/public/email-signature/index.html new file mode 100644 index 0000000..674cfbe --- /dev/null +++ b/Basin/public/email-signature/index.html @@ -0,0 +1,483 @@ + + + + + +Email Signature Generator — AuthZed + + + + + + +
+ + + +
+
+

Preview

+

Live preview — this is how it looks in email clients.

+
+
+
+
+
Signature Preview
+
White background mirrors the email client environment
+
+
+
Fill in your details to preview
+
+ + +
+

Gmail: Settings → Signature → Paste  ·  Outlook: Settings → Email signature → Paste

+
+
+
+
HTML Source
+ +
+
// enter your name to generate HTML
+
+
+ +
+
+ + + diff --git a/Basin/public/voronoi/index.html b/Basin/public/voronoi/index.html new file mode 100644 index 0000000..e1c31eb --- /dev/null +++ b/Basin/public/voronoi/index.html @@ -0,0 +1,2873 @@ + + + + +Voronoi Chromatic Aberration Explorer + + + + + +
+

Bad Lens Voronoi

+
+ Click canvas for full-size + +
+
+ +
+
+ +
+ + + + diff --git a/Basin/src/app/page.tsx b/Basin/src/app/page.tsx index eadf751..450ae7a 100644 --- a/Basin/src/app/page.tsx +++ b/Basin/src/app/page.tsx @@ -1,9 +1,29 @@ 'use client'; -import { Header } from '../components/Header' -import { ProjectGrid } from '../components/ProjectGrid' -import { ThemeToggle } from '../components/ThemeToggle' -import { projects } from '../data/projects' +import { ThemeToggle } from '../components/ThemeToggle'; +import { tools } from '../data/projects'; +import type { Tool } from '../types'; + +function ToolCard({ title, description, path, tag }: Tool) { + return ( + +
+

+ {title} +

+ + {tag} + +
+

+ {description} +

+
+ ); +} export default function Home() { return ( @@ -11,47 +31,30 @@ export default function Home() {
-
-
- A collection of tools born from our own design challenges, now shared to empower others. - Like a hidden desert basin, these resources have been uncovered, refined, and made accessible - to support thoughtful, scalable, and consistent design. -

- Basin is our way of giving back—helping teams everywhere innovate and create with ease. -

- Explore Basin and discover tools to support your journey. - - } - footnote={ - - Built by design at{' '} - - authzed - - , using{' '} - - bolt.new - - . - - } - /> +
+
+

+ Basin +

+

+ Internal tools built by design at{' '} + + AuthZed + . +

+
- +
+ {tools.map((tool) => ( + + ))} +
- ) + ); } diff --git a/Basin/src/components/CategoryFilter.tsx b/Basin/src/components/CategoryFilter.tsx deleted file mode 100644 index 5a23a30..0000000 --- a/Basin/src/components/CategoryFilter.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import { Hash } from 'lucide-react'; - -interface CategoryFilterProps { - categories: string[]; - selectedCategory: string; - onSelectCategory: (category: string) => void; -} - -export function CategoryFilter({ - categories, - selectedCategory, - onSelectCategory -}: CategoryFilterProps) { - return ( - <> - - {categories.map((category) => ( - - ))} - - ); -} \ No newline at end of file diff --git a/Basin/src/components/Header.tsx b/Basin/src/components/Header.tsx deleted file mode 100644 index c9f2800..0000000 --- a/Basin/src/components/Header.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; - -interface HeaderProps { - title: string; - description: React.ReactNode; - footnote?: React.ReactNode; -} - -export function Header({ title, description, footnote }: HeaderProps) { - return ( -
-

- {title} -

-
-
{description}
- {footnote} -
-
- ); -} \ No newline at end of file diff --git a/Basin/src/components/MobileFilters.tsx b/Basin/src/components/MobileFilters.tsx deleted file mode 100644 index dac4e9f..0000000 --- a/Basin/src/components/MobileFilters.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import React from 'react'; -import { ChevronDown } from 'lucide-react'; -import type { SortOption } from './SortSelect'; - -interface MobileFiltersProps { - categories: string[]; - selectedCategory: string; - onSelectCategory: (category: string) => void; - sortOptions: SortOption[]; - sortBy: string; - onSortChange: (value: string) => void; -} - -export function MobileFilters({ - categories, - selectedCategory, - onSelectCategory, - sortOptions, - sortBy, - onSortChange, -}: MobileFiltersProps) { - return ( -
-
- -
-
- -
-
- ); -} \ No newline at end of file diff --git a/Basin/src/components/ProjectCard.tsx b/Basin/src/components/ProjectCard.tsx deleted file mode 100644 index 7ba5eb8..0000000 --- a/Basin/src/components/ProjectCard.tsx +++ /dev/null @@ -1,178 +0,0 @@ -import React from 'react'; -import { ArrowRight, Github, ExternalLink, X } from 'lucide-react'; -import type { Project } from '../types'; -import { useProjectCard } from '../hooks/useProjectCard'; -import { cn } from '../utils/cn'; - -type ProjectCardProps = Project; - -export function ProjectCard(props: ProjectCardProps) { - const { - isExpanded, - containerRef, - contentRef, - toggleExpanded, - animationClass, - } = useProjectCard(); - - const { - icon: Icon, - title, - description, - technology, - color, - demoUrl, - sourceUrl, - category, - createdAt, - tags - } = props; - - return ( -
{ - if (e.key === 'Enter' || e.key === ' ') { - e.preventDefault(); - !isExpanded && toggleExpanded(); - } - if (e.key === 'Escape' && isExpanded) { - toggleExpanded(); - } - }} - aria-expanded={isExpanded} - > - {!isExpanded ? ( - // Collapsed View -
-
-
- -
-
-

- {title} -

-

{technology}

-
- -
-

{description}

-
- {category} - - {new Date(createdAt).toLocaleDateString()} - -
-
- ) : ( - // Expanded View -
-
-
- -
-

{title}

-

{technology}

-
-
- -
- -
-
-
- {`${title} -
-
-

About this project

-

{description}

- -

Development Process

-
    -
  • Initial planning and architecture design
  • -
  • Core functionality implementation
  • -
  • UI/UX refinement and testing
  • -
  • Performance optimization
  • -
- -

Key Challenges

-
    -
  • Optimizing performance for large datasets
  • -
  • Implementing real-time updates
  • -
  • Ensuring cross-browser compatibility
  • -
-
-
- -
-
-

Project Links

- -
- -
-

Project Details

-
-
- {tags.map((tag) => ( - - {tag} - - ))} -
-

Category: {category}

-

Created: {new Date(createdAt).toLocaleDateString()}

-

Technology: {technology}

-
-
-
-
-
- )} -
- ); -} \ No newline at end of file diff --git a/Basin/src/components/ProjectGrid.tsx b/Basin/src/components/ProjectGrid.tsx deleted file mode 100644 index b9d86a6..0000000 --- a/Basin/src/components/ProjectGrid.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import React from 'react'; -import { Hash } from 'lucide-react'; -import { ProjectCard } from './ProjectCard'; -import { SortSelect, type SortOption } from './SortSelect'; -import type { Project } from '../types'; -import { SearchBar } from './SearchBar'; -import { CategoryFilter } from './CategoryFilter'; -import { useLocalStorage } from '../hooks/useLocalStorage'; -import { MobileFilters } from './MobileFilters'; - -const sortOptions: SortOption[] = [ - { label: 'Name (A-Z)', value: 'name-asc' }, - { label: 'Name (Z-A)', value: 'name-desc' }, - { label: 'Newest First', value: 'date-desc' }, - { label: 'Oldest First', value: 'date-asc' }, - { label: 'Category', value: 'category' }, -]; - -interface ProjectGridProps { - projects: Project[]; -} - -export function ProjectGrid({ projects }: ProjectGridProps) { - const [search, setSearch] = React.useState(''); - const [selectedCategory, setSelectedCategory] = React.useState('all'); - const [sortBy, setSortBy] = React.useState('name-asc'); - const [favorites, setFavorites] = useLocalStorage('favorites', []); - - const categories = React.useMemo(() => { - return Array.from(new Set(projects.map(p => p.category))); - }, [projects]); - - const filteredProjects = React.useMemo(() => { - return projects.filter(project => { - const matchesSearch = project.title.toLowerCase().includes(search.toLowerCase()) || - project.description.toLowerCase().includes(search.toLowerCase()) || - project.technology.toLowerCase().includes(search.toLowerCase()); - const matchesCategory = selectedCategory === 'all' || project.category === selectedCategory; - return matchesSearch && matchesCategory; - }); - }, [projects, search, selectedCategory]) - .sort((a, b) => { - switch (sortBy) { - case 'name-desc': - return b.title.localeCompare(a.title); - case 'date-desc': - return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(); - case 'date-asc': - return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(); - case 'category': - return a.category.localeCompare(b.category); - default: // name-asc - return a.title.localeCompare(b.title); - } - }); - - return ( -
-
- -
- -
-
- -
- -
-
- -
- -
- -
-
-
- -
- {filteredProjects.map((project) => ( - - ))} - {filteredProjects.length === 0 && ( -
-

- No projects found matching your criteria -

-
- )} -
-
- ); -} \ No newline at end of file diff --git a/Basin/src/components/ProjectList.tsx b/Basin/src/components/ProjectList.tsx deleted file mode 100644 index 2187ac4..0000000 --- a/Basin/src/components/ProjectList.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import React from 'react'; -import { ExternalLink, Github } from 'lucide-react'; -import type { Project } from '../types'; - -interface ProjectListProps { - projects: Project[]; -} - -export function ProjectList({ projects }: ProjectListProps) { - return ( -
- {projects.map((project) => ( -
-
- -
-
-
-

- {project.title} -

- -
-

- {project.description} -

-
- - {project.technology} - - - {project.category} - -
-
-
- ))} -
- ); -} \ No newline at end of file diff --git a/Basin/src/components/SearchBar.tsx b/Basin/src/components/SearchBar.tsx deleted file mode 100644 index 13ad8dd..0000000 --- a/Basin/src/components/SearchBar.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import { Search } from 'lucide-react'; - -interface SearchBarProps { - value: string; - onChange: (value: string) => void; -} - -export function SearchBar({ value, onChange }: SearchBarProps) { - return ( -
-
- -
- onChange(e.target.value)} - className="w-[200px] pl-9 pr-3 py-2 bg-background text-foreground - placeholder-muted-foreground rounded-lg border border-input text-sm - focus:outline-none focus:ring-1 focus:ring-ring" - placeholder="Search projects..." - /> -
- ); -} \ No newline at end of file diff --git a/Basin/src/components/SortSelect.tsx b/Basin/src/components/SortSelect.tsx deleted file mode 100644 index de466b6..0000000 --- a/Basin/src/components/SortSelect.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import React from 'react'; -import { ArrowUpDown } from 'lucide-react'; - -export type SortOption = { - label: string; - value: string; -}; - -interface SortSelectProps { - value: string; - onChange: (value: string) => void; - options: SortOption[]; -} - -export function SortSelect({ value, onChange, options }: SortSelectProps) { - return ( -
- - -
- ); -} \ No newline at end of file diff --git a/Basin/src/components/ViewToggle.tsx b/Basin/src/components/ViewToggle.tsx deleted file mode 100644 index 1d714e4..0000000 --- a/Basin/src/components/ViewToggle.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; -import { LayoutGrid, List } from 'lucide-react'; - -interface ViewToggleProps { - view: 'grid' | 'list'; - onViewChange: (view: 'grid' | 'list') => void; -} - -export function ViewToggle({ view, onViewChange }: ViewToggleProps) { - return ( -
- - -
- ); -} \ No newline at end of file diff --git a/Basin/src/data/projects.ts b/Basin/src/data/projects.ts index feffc07..895a2e8 100644 --- a/Basin/src/data/projects.ts +++ b/Basin/src/data/projects.ts @@ -1,132 +1,16 @@ -import { - Palette, - Box, - Layers, - Sparkles, - Shapes, - Layout, - Paintbrush, - Component, - Pencil, -} from 'lucide-react'; -import type { Project } from '../types'; +import type { Tool } from '../types'; -export const projects: Project[] = [ +export const tools: Tool[] = [ { - icon: Palette, - title: 'Tailwind CSS', - technology: 'CSS Framework', - description: 'A utility-first CSS framework packed with classes that can be composed to build any design, directly in your markup.', - color: 'text-blue-600', - demoUrl: 'https://tailwindcss.com', - previewUrl: 'https://opengraph.githubassets.com/1/tailwindlabs/tailwindcss', - sourceUrl: 'https://github.com/tailwindlabs/tailwindcss', - category: 'CSS Framework', - tags: ['CSS', 'Utility-First', 'PostCSS', 'Design System'], - createdAt: '2024-03-15' + title: 'Email Signature', + description: 'Generate on-brand email signatures for Gmail and Outlook with live preview, drag-and-drop ordering, and one-click copy.', + path: '/email-signature', + tag: 'Brand', }, - { - icon: Box, - title: 'Chakra UI', - technology: 'React Component Library', - description: 'A simple, modular and accessible component library that gives you the building blocks to build React applications.', - color: 'text-green-600', - demoUrl: 'https://chakra-ui.com', - previewUrl: 'https://opengraph.githubassets.com/1/chakra-ui/chakra-ui', - sourceUrl: 'https://github.com/chakra-ui/chakra-ui', - category: 'Component Library', - tags: ['React', 'Accessible', 'Themeable', 'Components'], - createdAt: '2024-03-10' - }, - { - icon: Layers, - title: 'Radix UI', - technology: 'Headless Components', - description: 'Unstyled, accessible components for building high‑quality design systems and web apps in React.', - color: 'text-purple-600', - demoUrl: 'https://www.radix-ui.com', - previewUrl: 'https://opengraph.githubassets.com/1/radix-ui/primitives', - sourceUrl: 'https://github.com/radix-ui/primitives', - category: 'Design System', - tags: ['Headless UI', 'Accessible', 'React', 'Primitives'], - createdAt: '2024-03-05' - }, - { - icon: Sparkles, - title: 'Framer Motion', - technology: 'Animation Library', - description: 'A production-ready motion library for React. Utilize the power of animation to create engaging user interfaces.', - color: 'text-orange-600', - demoUrl: 'https://www.framer.com/motion', - previewUrl: 'https://opengraph.githubassets.com/1/framer/motion', - sourceUrl: 'https://github.com/framer/motion', - category: 'Animation', - tags: ['Animation', 'React', 'Motion', 'Gestures'], - createdAt: '2024-03-01' - }, - { - icon: Shapes, - title: 'Storybook', - technology: 'Development Environment', - description: 'Build UI components and pages in isolation. It streamlines UI development, testing, and documentation.', - color: 'text-red-600', - demoUrl: 'https://storybook.js.org', - previewUrl: 'https://opengraph.githubassets.com/1/storybookjs/storybook', - sourceUrl: 'https://github.com/storybookjs/storybook', - category: 'Development Tools', - tags: ['Documentation', 'Testing', 'Components', 'Development'], - createdAt: '2024-02-28' +{ + title: 'Voronoi Explorer', + description: 'Interactive Voronoi diagram generator with chromatic aberration, layered rendering, and preset management.', + path: '/voronoi', + tag: 'Generative', }, - { - icon: Layout, - title: 'shadcn/ui', - technology: 'React Components', - description: 'Beautifully designed components built with Radix UI and Tailwind CSS. Copy and paste into your apps.', - color: 'text-indigo-600', - demoUrl: 'https://ui.shadcn.com', - previewUrl: 'https://opengraph.githubassets.com/1/shadcn-ui/ui', - sourceUrl: 'https://github.com/shadcn-ui/ui', - category: 'Component Library', - tags: ['React', 'Tailwind CSS', 'Radix UI', 'Components'], - createdAt: '2024-02-25' - }, - { - icon: Paintbrush, - title: 'Material UI', - technology: 'React UI Framework', - description: 'A comprehensive suite of UI tools and components, implementing Google\'s Material Design.', - color: 'text-pink-600', - demoUrl: 'https://mui.com', - previewUrl: 'https://opengraph.githubassets.com/1/mui/material-ui', - sourceUrl: 'https://github.com/mui/material-ui', - category: 'Design System', - tags: ['Material Design', 'React', 'Components', 'Theme'], - createdAt: '2024-02-20' - }, - { - icon: Component, - title: 'Mantine', - technology: 'React Components', - description: 'A fully featured React components library with 100+ customizable components and hooks.', - color: 'text-cyan-600', - demoUrl: 'https://mantine.dev', - previewUrl: 'https://opengraph.githubassets.com/1/mantinedev/mantine', - sourceUrl: 'https://github.com/mantinedev/mantine', - category: 'Component Library', - tags: ['React', 'TypeScript', 'Hooks', 'Theming'], - createdAt: '2024-02-15' - }, - { - icon: Pencil, - title: 'Figma UI Kit', - technology: 'Design Resources', - description: 'Open-source UI kit for Figma with comprehensive design components and styles.', - color: 'text-yellow-600', - demoUrl: 'https://www.figma.com/community/file/768809027799962739', - previewUrl: 'https://opengraph.githubassets.com/1/figma/figma-api-demo', - sourceUrl: 'https://github.com/figma/figma-api-demo', - category: 'Design Tools', - tags: ['Figma', 'UI Kit', 'Design System', 'Resources'], - createdAt: '2024-02-10' - } -]; \ No newline at end of file +]; diff --git a/Basin/src/hooks/useLocalStorage.ts b/Basin/src/hooks/useLocalStorage.ts deleted file mode 100644 index 4516ea1..0000000 --- a/Basin/src/hooks/useLocalStorage.ts +++ /dev/null @@ -1,25 +0,0 @@ -'use client'; - -import { useState, useEffect } from 'react'; - -export function useLocalStorage(key: string, initialValue: T) { - const [storedValue, setStoredValue] = useState(() => { - try { - const item = window.localStorage.getItem(key); - return item ? JSON.parse(item) : initialValue; - } catch (error) { - console.error(error); - return initialValue; - } - }); - - useEffect(() => { - try { - window.localStorage.setItem(key, JSON.stringify(storedValue)); - } catch (error) { - console.error(error); - } - }, [key, storedValue]); - - return [storedValue, setStoredValue] as const; -} \ No newline at end of file diff --git a/Basin/src/hooks/useProjectCard.ts b/Basin/src/hooks/useProjectCard.ts deleted file mode 100644 index e32c7fa..0000000 --- a/Basin/src/hooks/useProjectCard.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { useRef, useState, useEffect } from 'react'; - -export function useProjectCard() { - const [isExpanded, setIsExpanded] = useState(false); - const [animationClass, setAnimationClass] = useState(''); - const containerRef = useRef(null); - const contentRef = useRef(null); - - useEffect(() => { - if (isExpanded) { - // Add overlay to other cards - const cards = document.querySelectorAll('.project-card'); - cards.forEach((card) => { - if (card !== containerRef.current) { - card.classList.add('opacity-50'); - } - }); - - // Animate content - if (contentRef.current) { - requestAnimationFrame(() => { - contentRef.current?.classList.remove('opacity-0'); - }); - } - - // Scroll into view if needed - containerRef.current?.scrollIntoView({ - behavior: 'smooth', - block: 'nearest', - }); - } else { - // Remove overlay from other cards - const cards = document.querySelectorAll('.project-card'); - cards.forEach((card) => { - card.classList.remove('opacity-50'); - }); - - // Hide content - if (contentRef.current) { - contentRef.current.classList.add('opacity-0'); - } - } - }, [isExpanded]); - - const toggleExpanded = () => { - if (!isExpanded) { - setAnimationClass('scale-[1.02]'); - setTimeout(() => setAnimationClass(''), 300); - } - setIsExpanded(!isExpanded); - }; - - return { - isExpanded, - containerRef, - contentRef, - toggleExpanded, - animationClass, - }; -} \ No newline at end of file diff --git a/Basin/src/hooks/useTheme.ts b/Basin/src/hooks/useTheme.ts deleted file mode 100644 index 0e90f91..0000000 --- a/Basin/src/hooks/useTheme.ts +++ /dev/null @@ -1,36 +0,0 @@ -'use client'; - -import { useEffect, useState } from 'react'; - -type Theme = 'light' | 'dark'; - -const getSystemTheme = (): Theme => { - if (typeof window === 'undefined') return 'light'; - return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; -}; - -export function useTheme() { - const [mounted, setMounted] = useState(false); - const [theme, setTheme] = useState(() => { - if (typeof window === 'undefined') return 'light'; - return (localStorage.getItem('theme') as Theme) || getSystemTheme(); - }); - - useEffect(() => { - setMounted(true); - }, []); - - useEffect(() => { - if (!mounted) return; - const root = window.document.documentElement; - root.classList.remove('light', 'dark'); - root.classList.add(theme); - localStorage.setItem('theme', theme); - }, [theme, mounted]); - - if (!mounted) { - return { theme: 'light', setTheme: () => {} }; - } - - return { theme, setTheme }; -} \ No newline at end of file diff --git a/Basin/src/types/index.ts b/Basin/src/types/index.ts index 083ad86..5f42a76 100644 --- a/Basin/src/types/index.ts +++ b/Basin/src/types/index.ts @@ -1,15 +1,6 @@ -import { LucideIcon } from 'lucide-react'; - -export interface Project { - icon: LucideIcon; +export interface Tool { title: string; - technology: string; description: string; - color: string; - demoUrl: string; - previewUrl: string; - sourceUrl: string; - category: string; - tags: string[]; - createdAt: string; // ISO date string -} \ No newline at end of file + path: string; + tag: string; +} diff --git a/Basin/src/utils/getOgImage.ts b/Basin/src/utils/getOgImage.ts deleted file mode 100644 index fd95a90..0000000 --- a/Basin/src/utils/getOgImage.ts +++ /dev/null @@ -1,12 +0,0 @@ -export function getOgImage(url: string): string { - // Remove trailing slash if present - const cleanUrl = url.replace(/\/$/, ''); - - // Known patterns for popular sites - if (cleanUrl.includes('github.com')) { - return `https://opengraph.githubassets.com/1/${cleanUrl.split('github.com/')[1]}`; - } - - // For other sites, use a reliable OG image service - return `https://og-image.vercel.app/${encodeURIComponent(cleanUrl)}`; -} \ No newline at end of file