diff --git a/app/(landing)/page.tsx b/app/(landing)/page.tsx index 9e522d2..61befc1 100644 --- a/app/(landing)/page.tsx +++ b/app/(landing)/page.tsx @@ -9,10 +9,14 @@ import { Suspense } from 'react'; import Sponsors from './sections/Sponsors'; import About from './sections/About'; import FAQ from './sections/FAQ/FAQ'; +import Cursor from '@/app/ui/cursor'; export default function Page() { return (
+ + +
diff --git a/app/ui/cursor.tsx b/app/ui/cursor.tsx new file mode 100644 index 0000000..81dd259 --- /dev/null +++ b/app/ui/cursor.tsx @@ -0,0 +1,83 @@ +"use client"; + +import React, { useState, useEffect } from "react"; +import Image from 'next/image'; +import LugeReact from "./luge"; + +/** + * + * Documentation: https://luge.cool/docs/custom-cursor/ + * Compatibility with Next.js Discussion: https://github.com/AntoineW/luge/discussions/9 + * + * The day that Luge becomes deprecated or starts to break, cause problems, etc., it must be removed. + * + * 1. pnpm uninstall @waaark/luge + * 2. Delete the TrailEffect component + * 3. Delete all instances of data-lg-[...] in global.css + */ +const TrailEffect = () => { + return ( + <> + +
+
+
+ + ); +} + +const Cursor = () => { + const [position, setPosition] = useState({ x: 0, y: 0 }); + + const [isPointer, setIsPointer] = useState(false); + + const handleMouseMove = (e: any) => { + setPosition({ x: e.clientX, y: e.clientY }); + + const target = e.target; + + setIsPointer( + window.getComputedStyle(target).getPropertyValue("cursor") === "pointer" + ); + // target.style.cursor = "none"; + + e.stopPropagation(); + }; + + useEffect(() => { + window.addEventListener("mousemove", handleMouseMove); + + return () => window.removeEventListener("mousemove", handleMouseMove); + }, []); + + const YSize = isPointer ? -100 : 100; + const XSize = isPointer ? -100 : 20; + const rotationAngle = isPointer ? 0 : 315; + const topPos = (position.y - YSize / 4) + 10; + const leftPos = (position.x - XSize / 4) + 30; + + const hasNotMoved = position.x === 0 && position.y === 0; + + return ( + <> + + Custom Cursor + + ); +}; + +export default Cursor; \ No newline at end of file diff --git a/app/ui/global.css b/app/ui/global.css index c06d6d6..49b3fd5 100644 --- a/app/ui/global.css +++ b/app/ui/global.css @@ -16,3 +16,23 @@ input[type='number']::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; } + +.lg-cursor-pointer:before { + margin: -5px 0 0 -5px; + width: 10px; + height: 10px; + + background-color: cyan; + border-radius: 50%; +} + +.lg-cursor-trail path { + stroke: cyan; + stroke-linecap: round; + stroke-linejoin: round; + stroke-width: 12px; +} +.lg-cursor--hover .lg-cursor-pointer:before { + background-color: red; + transform: scale(2); +} diff --git a/app/ui/luge.js b/app/ui/luge.js new file mode 100644 index 0000000..5a8b51e --- /dev/null +++ b/app/ui/luge.js @@ -0,0 +1,27 @@ +'use client'; +import { useEffect } from 'react'; + +import '@/node_modules/@waaark/luge/dist/css/luge.css'; + +/** + * This is for the trailing effect for the wand in the Cursor component. + * + * Delete this when necessary. This adds a whole another library to this project + * and we don't need the clutter later on if we don't need it. + * + * But magic wand trail effect is very cool. So we keep for Spring '24. + */ + +const LugeReact = () => { + useEffect(() => { + import('@waaark/luge/dist/js/luge') + .then((luge) => { + luge.lifecycle.refresh(); + }) + .catch((error) => console.error(error)); + }); + + return null; +}; + +export default LugeReact; diff --git a/package.json b/package.json index c1c2993..cd4d3b3 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@tailwindcss/forms": "^0.5.7", "@types/node": "20.5.7", "@vercel/postgres": "^0.5.0", + "@waaark/luge": "0.6.18-beta.2", "autoprefixer": "10.4.15", "bcrypt": "^5.1.1", "clsx": "^2.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fe1e374..cc525ec 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ dependencies: '@vercel/postgres': specifier: ^0.5.0 version: 0.5.1 + '@waaark/luge': + specifier: 0.6.18-beta.2 + version: 0.6.18-beta.2 autoprefixer: specifier: 10.4.15 version: 10.4.15(postcss@8.4.31) @@ -924,9 +927,9 @@ packages: eslint: 8.56.0 eslint-config-prettier: 9.0.0(eslint@8.56.0) eslint-import-resolver-alias: 1.1.2(eslint-plugin-import@2.29.1) - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.17.0)(eslint-plugin-import@2.29.1)(eslint@8.56.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0) eslint-plugin-eslint-comments: 3.2.0(eslint@8.56.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.17.0)(eslint@8.56.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) eslint-plugin-jest: 27.6.1(@typescript-eslint/eslint-plugin@6.17.0)(eslint@8.56.0)(typescript@5.2.2) eslint-plugin-jsx-a11y: 6.8.0(eslint@8.56.0) eslint-plugin-playwright: 0.16.0(eslint-plugin-jest@27.6.1)(eslint@8.56.0) @@ -945,6 +948,14 @@ packages: - supports-color dev: true + /@waaark/luge@0.6.18-beta.2: + resolution: {integrity: sha512-lPhqzMhpmf2aTaVfPFUkQGjQtQjJs1BiVYJvxoiAyaT0cYDJWJwS6Tr0cqbZW+kCaY0/5fMe7VROSnoClFKqBw==} + dependencies: + bowser: 2.11.0 + virtual-scroll: 2.2.1 + whatwg-fetch: 3.6.20 + dev: false + /abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} dev: false @@ -1184,6 +1195,10 @@ packages: engines: {node: '>=8'} dev: false + /bowser@2.11.0: + resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} + dev: false + /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -1644,7 +1659,7 @@ packages: peerDependencies: eslint-plugin-import: '>=1.4.0' dependencies: - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.17.0)(eslint@8.56.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) dev: true /eslint-import-resolver-node@0.3.9: @@ -1680,29 +1695,6 @@ packages: - supports-color dev: true - /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.17.0)(eslint-plugin-import@2.29.1)(eslint@8.56.0): - resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - eslint: '*' - eslint-plugin-import: '*' - dependencies: - debug: 4.3.4 - enhanced-resolve: 5.15.0 - eslint: 8.56.0 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.17.0)(eslint@8.56.0) - fast-glob: 3.3.2 - get-tsconfig: 4.7.2 - is-core-module: 2.13.1 - is-glob: 4.0.3 - transitivePeerDependencies: - - '@typescript-eslint/parser' - - eslint-import-resolver-node - - eslint-import-resolver-webpack - - supports-color - dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} @@ -1733,64 +1725,6 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-node@0.3.9)(eslint@8.56.0): - resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - dependencies: - '@typescript-eslint/parser': 6.17.0(eslint@8.56.0)(typescript@5.2.2) - debug: 3.2.7 - eslint: 8.56.0 - eslint-import-resolver-node: 0.3.9 - transitivePeerDependencies: - - supports-color - dev: true - - /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0): - resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - dependencies: - '@typescript-eslint/parser': 6.17.0(eslint@8.56.0)(typescript@5.2.2) - debug: 3.2.7 - eslint: 8.56.0 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.17.0)(eslint-plugin-import@2.29.1)(eslint@8.56.0) - transitivePeerDependencies: - - supports-color - dev: true - /eslint-plugin-eslint-comments@3.2.0(eslint@8.56.0): resolution: {integrity: sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==} engines: {node: '>=6.5.0'} @@ -1837,41 +1771,6 @@ packages: - supports-color dev: true - /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.17.0)(eslint@8.56.0): - resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - dependencies: - '@typescript-eslint/parser': 6.17.0(eslint@8.56.0)(typescript@5.2.2) - array-includes: 3.1.7 - array.prototype.findlastindex: 1.2.3 - array.prototype.flat: 1.3.2 - array.prototype.flatmap: 1.3.2 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.56.0 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-node@0.3.9)(eslint@8.56.0) - hasown: 2.0.0 - is-core-module: 2.13.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.7 - object.groupby: 1.0.1 - object.values: 1.1.7 - semver: 6.3.1 - tsconfig-paths: 3.15.0 - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - dev: true - /eslint-plugin-jest@27.6.1(@typescript-eslint/eslint-plugin@6.17.0)(eslint@8.56.0)(typescript@5.2.2): resolution: {integrity: sha512-WEYkyVXD9NlmFBKvrkmzrC+C9yZoz5pAml2hO19PlS3spJtoiwj4p2u8spd/7zx5IvRsZsCmsoImaAvBB9X93Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4014,6 +3913,10 @@ packages: any-promise: 1.3.0 dev: false + /tiny-emitter@2.1.0: + resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==} + dev: false + /to-fast-properties@2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} @@ -4185,6 +4088,12 @@ packages: spdx-expression-parse: 3.0.1 dev: true + /virtual-scroll@2.2.1: + resolution: {integrity: sha512-RvjcLxluh7B/6GPzLgQ9d0NYG4yqEguTc3MU7AvxyPVltuo2Cq5RokTL9RKUaZCMJ64in2hus0d03gTtoHp55g==} + dependencies: + tiny-emitter: 2.1.0 + dev: false + /watchpack@2.4.0: resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==} engines: {node: '>=10.13.0'} @@ -4197,6 +4106,10 @@ packages: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} dev: false + /whatwg-fetch@3.6.20: + resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} + dev: false + /whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} dependencies: diff --git a/public/landing/wand.png b/public/landing/wand.png new file mode 100644 index 0000000..f504d69 Binary files /dev/null and b/public/landing/wand.png differ diff --git a/tsconfig.json b/tsconfig.json index 8c283d1..bc1f43d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -28,7 +28,8 @@ "**/*.tsx", ".next/types/**/*.ts", "app/lib/placeholder-data.js", - "scripts/seed.js" + "scripts/seed.js", + "app/ui/luge.js" ], "exclude": ["node_modules"] } diff --git a/types/global.d.ts b/types/global.d.ts index ab0f681..1be8f64 100644 --- a/types/global.d.ts +++ b/types/global.d.ts @@ -1,3 +1,5 @@ +declare module '@waaark/luge'; + interface DayInfo { day: string; times: { time: string; event: string }[];