diff --git a/CODE_STYLE.md b/CODE_STYLE.md index adac833..c78e7c8 100644 --- a/CODE_STYLE.md +++ b/CODE_STYLE.md @@ -117,10 +117,10 @@ import { z } from "zod"; import DEFAULT_AVATAR from "$assets/images/default-avatar.png"; // Components -import Avatar from "$components/avatar"; -import Button from "$components/button"; -import Modal from "$components/modal"; -import Spinner from "$components/spinner"; +import { Avatar } from "$components/avatar"; +import { Button } from "$components/button"; +import { Modal } from "$components/modal"; +import { Spinner } from "$components/spinner"; // Data import { USER_DEFAULTS } from "$data/constants"; @@ -155,9 +155,9 @@ import { useMemo, useState } from "react"; import HERO_IMAGE from "$assets/images/events-hero.jpg"; // Components -import EventCard from "$components/event-card"; -import FilterBar from "$components/filter-bar"; -import Pagination from "$components/pagination"; +import { EventCard } from "$components/event-card"; +import { FilterBar } from "$components/filter-bar"; +import { Pagination } from "$components/pagination"; // Data import { EVENT_CATEGORIES } from "$data/categories"; @@ -209,7 +209,7 @@ import { useState } from "react"; import ICON from "$assets/icons/star.svg"; -import Button from "$components/button"; +import { Button } from "$components/button"; import { api } from "$lib/api"; @@ -223,7 +223,7 @@ import { useQuery, useSuspenseQuery } from "@tanstack/react-query"; import { api, auth, cache } from "$lib/api"; // Avoid - Mixed categories without separation -import Button from "$components/button"; +import { Button } from "$components/button"; import styles from "$styles/app.module.scss"; import { useState } from "react"; import type { Props } from "./types"; diff --git a/package.json b/package.json index f03a2f9..d4cd4c3 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "email:dev": "email dev --dir=./src/emails --port=2999" }, "dependencies": { + "@base-ui/react": "^1.3.0", "@elysiajs/eden": "^1.4.8", "@elysiajs/openapi": "^1.4.14", "@fontsource/space-grotesk": "^5.2.10", @@ -36,7 +37,8 @@ "@netlify/vite-plugin-tanstack-start": "^1.3.2", "@react-email/components": "1.0.10", "@t3-oss/env-core": "^0.13.11", - "@tailwindcss/vite": "^4.1.18", + "@tabler/icons-react": "^3.41.1", + "@tailwindcss/vite": "^4.2.2", "@tanstack/react-devtools": "^0.10.0", "@tanstack/react-form": "^1.28.5", "@tanstack/react-form-start": "^1.28.0", @@ -45,13 +47,15 @@ "@tanstack/react-router-ssr-query": "^1.166.10", "@tanstack/react-start": "^1.167.5", "@tanstack/router-plugin": "^1.167.4", + "clsx": "^2.1.1", "concurrently": "^9.2.1", "dotenv": "^17.2.4", "elysia": "^1.4.28", "nodemailer": "^8.0.3", "react": "^19.2.4", "react-dom": "^19.2.4", - "tailwindcss": "^4.1.18", + "tailwind-merge": "^3.5.0", + "tailwindcss": "^4.2.2", "zod": "^4.3.6" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 80fd356..4a4dbe6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@base-ui/react': + specifier: ^1.3.0 + version: 1.3.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@elysiajs/eden': specifier: ^1.4.8 version: 1.4.8(elysia@1.4.28(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@6.0.2)) @@ -35,8 +38,11 @@ importers: '@t3-oss/env-core': specifier: ^0.13.11 version: 0.13.11(typescript@6.0.2)(zod@4.3.6) + '@tabler/icons-react': + specifier: ^3.41.1 + version: 3.41.1(react@19.2.4) '@tailwindcss/vite': - specifier: ^4.1.18 + specifier: ^4.2.2 version: 4.2.2(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.7.1)(@types/node@22.19.1)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.94.0)(tsx@4.20.6)(yaml@2.8.3)) '@tanstack/react-devtools': specifier: ^0.10.0 @@ -62,6 +68,9 @@ importers: '@tanstack/router-plugin': specifier: ^1.167.4 version: 1.167.10(@tanstack/react-router@1.168.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.7.1)(@types/node@22.19.1)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.94.0)(tsx@4.20.6)(yaml@2.8.3)) + clsx: + specifier: ^2.1.1 + version: 2.1.1 concurrently: specifier: ^9.2.1 version: 9.2.1 @@ -80,9 +89,12 @@ importers: react-dom: specifier: ^19.2.4 version: 19.2.4(react@19.2.4) + tailwind-merge: + specifier: ^3.5.0 + version: 3.5.0 tailwindcss: - specifier: ^4.1.18 - version: 4.1.18 + specifier: ^4.2.2 + version: 4.2.2 zod: specifier: ^4.3.6 version: 4.3.6 @@ -310,6 +322,10 @@ packages: resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} + '@babel/runtime@7.29.2': + resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} + engines: {node: '>=6.9.0'} + '@babel/template@7.27.2': resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} @@ -338,6 +354,27 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} + '@base-ui/react@1.3.0': + resolution: {integrity: sha512-FwpKqZbPz14AITp1CVgf4AjhKPe1OeeVKSBMdgD10zbFlj3QSWelmtCMLi2+/PFZZcIm3l87G7rwtCZJwHyXWA==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@types/react': ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true + + '@base-ui/utils@0.2.6': + resolution: {integrity: sha512-yQ+qeuqohwhsNpoYDqqXaLllYAkPCP4vYdDrVo8FQXaAPfHWm1pG/Vm+jmGTA5JFS0BAIjookyapuJFY8F9PIw==} + peerDependencies: + '@types/react': ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true + '@borewit/text-codec@0.1.1': resolution: {integrity: sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA==} @@ -745,6 +782,21 @@ packages: '@fastify/busboy@3.2.0': resolution: {integrity: sha512-m9FVDXU3GT2ITSe0UaMA5rU3QkfC/UXtCU8y0gSN/GugTqtVldOBWIB5V6V3sbmenVZUIpU6f+mPEO2+m5iTaA==} + '@floating-ui/core@1.7.5': + resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} + + '@floating-ui/dom@1.7.6': + resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} + + '@floating-ui/react-dom@2.1.8': + resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.11': + resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + '@fontsource/space-grotesk@5.2.10': resolution: {integrity: sha512-XNXEbT74OIITPqw2H6HXwPDp85fy43uxfBwFR5PU+9sLnjuLj12KlhVM9nZVN6q6dlKjkuN8JisW/OBxwxgUew==} @@ -785,89 +837,105 @@ packages: resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.4': resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.4': resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-riscv64@1.2.4': resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.4': resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.4': resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.2.4': resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.4': resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.34.5': resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.34.5': resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-ppc64@0.34.5': resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-linux-riscv64@0.34.5': resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.34.5': resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.34.5': resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.5': resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.34.5': resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.34.5': resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} @@ -1095,24 +1163,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@next/swc-linux-arm64-musl@16.1.7': resolution: {integrity: sha512-uufcze7LYv0FQg9GnNeZ3/whYfo+1Q3HnQpm16o6Uyi0OVzLlk2ZWoY7j07KADZFY8qwDbsmFnMQP3p3+Ftprw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@next/swc-linux-x64-gnu@16.1.7': resolution: {integrity: sha512-KWVf2gxYvHtvuT+c4MBOGxuse5TD7DsMFYSxVxRBnOzok/xryNeQSjXgxSv9QpIVlaGzEn/pIuI6Koosx8CGWA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@next/swc-linux-x64-musl@16.1.7': resolution: {integrity: sha512-HguhaGwsGr1YAGs68uRKc4aGWxLET+NevJskOcCAwXbwj0fYX0RgZW2gsOCzr9S11CSQPIkxmoSbuVaBp4Z3dA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@next/swc-win32-arm64-msvc@16.1.7': resolution: {integrity: sha512-S0n3KrDJokKTeFyM/vGGGR8+pCmXYrjNTk2ZozOL1C/JFdfUIL9O1ATaJOl5r2POe56iRChbsszrjMAdWSv7kQ==} @@ -1264,48 +1336,56 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@oxfmt/binding-linux-arm64-musl@0.40.0': resolution: {integrity: sha512-tGmWhLD/0YMotCdfezlT6tC/MJG/wKpo4vnQ3Cq+4eBk/BwNv7EmkD0VkD5F/dYkT3b8FNU01X2e8vvJuWoM1w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@oxfmt/binding-linux-ppc64-gnu@0.40.0': resolution: {integrity: sha512-rVbFyM3e7YhkVnp0IVYjaSHfrBWcTRWb60LEcdNAJcE2mbhTpbqKufx0FrhWfoxOrW/+7UJonAOShoFFLigDqQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@oxfmt/binding-linux-riscv64-gnu@0.40.0': resolution: {integrity: sha512-3ZqBw14JtWeEoLiioJcXSJz8RQyPE+3jLARnYM1HdPzZG4vk+Ua8CUupt2+d+vSAvMyaQBTN2dZK+kbBS/j5mA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxfmt/binding-linux-riscv64-musl@0.40.0': resolution: {integrity: sha512-JJ4PPSdcbGBjPvb+O7xYm2FmAsKCyuEMYhqatBAHMp/6TA6rVlf9Z/sYPa4/3Bommb+8nndm15SPFRHEPU5qFA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [musl] '@oxfmt/binding-linux-s390x-gnu@0.40.0': resolution: {integrity: sha512-Kp0zNJoX9Ik77wUya2tpBY3W9f40VUoMQLWVaob5SgCrblH/t2xr/9B2bWHfs0WCefuGmqXcB+t0Lq77sbBmZw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@oxfmt/binding-linux-x64-gnu@0.40.0': resolution: {integrity: sha512-7YTCNzleWTaQTqNGUNQ66qVjpoV6DjbCOea+RnpMBly2bpzrI/uu7Rr+2zcgRfNxyjXaFTVQKaRKjqVdeUfeVA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@oxfmt/binding-linux-x64-musl@0.40.0': resolution: {integrity: sha512-hWnSzJ0oegeOwfOEeejYXfBqmnRGHusgtHfCPzmvJvHTwy1s3Neo59UKc1CmpE3zxvrCzJoVHos0rr97GHMNPw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@oxfmt/binding-openharmony-arm64@0.40.0': resolution: {integrity: sha512-28sJC1lR4qtBJGzSRRbPnSW3GxU2+4YyQFE6rCmsUYqZ5XYH8jg0/w+CvEzQ8TuAQz5zLkcA25nFQGwoU0PT3Q==} @@ -1408,48 +1488,56 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@oxlint/binding-linux-arm64-musl@1.57.0': resolution: {integrity: sha512-i66WyEPVEvq9bxRUCJ/MP5EBfnTDN3nhwEdFZFTO5MmLLvzngfWEG3NSdXQzTT3vk5B9i6C2XSIYBh+aG6uqyg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@oxlint/binding-linux-ppc64-gnu@1.57.0': resolution: {integrity: sha512-oMZDCwz4NobclZU3pH+V1/upVlJZiZvne4jQP+zhJwt+lmio4XXr4qG47CehvrW1Lx2YZiIHuxM2D4YpkG3KVA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@oxlint/binding-linux-riscv64-gnu@1.57.0': resolution: {integrity: sha512-uoBnjJ3MMEBbfnWC1jSFr7/nSCkcQYa72NYoNtLl1imshDnWSolYCjzb8LVCwYCCfLJXD+0gBLD7fyC14c0+0g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxlint/binding-linux-riscv64-musl@1.57.0': resolution: {integrity: sha512-BdrwD7haPZ8a9KrZhKJRSj6jwCor+Z8tHFZ3PT89Y3Jq5v3LfMfEePeAmD0LOTWpiTmzSzdmyw9ijneapiVHKQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [musl] '@oxlint/binding-linux-s390x-gnu@1.57.0': resolution: {integrity: sha512-BNs+7ZNsRstVg2tpNxAXfMX/Iv5oZh204dVyb8Z37+/gCh+yZqNTlg6YwCLIMPSk5wLWIGOaQjT0GUOahKYImw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@oxlint/binding-linux-x64-gnu@1.57.0': resolution: {integrity: sha512-AghS18w+XcENcAX0+BQGLiqjpqpaxKJa4cWWP0OWNLacs27vHBxu7TYkv9LUSGe5w8lOJHeMxcYfZNOAPqw2bg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@oxlint/binding-linux-x64-musl@1.57.0': resolution: {integrity: sha512-E/FV3GB8phu/Rpkhz5T96hAiJlGzn91qX5yj5gU754P5cmVGXY1Jw/VSjDSlZBCY3VHjsVLdzgdkJaomEmcNOg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@oxlint/binding-openharmony-arm64@1.57.0': resolution: {integrity: sha512-xvZ2yZt0nUVfU14iuGv3V25jpr9pov5N0Wr28RXnHFxHCRxNDMtYPHV61gGLhN9IlXM96gI4pyYpLSJC5ClLCQ==} @@ -1504,36 +1592,42 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.1': resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.1': resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.1': resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.1': resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.1': resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [musl] '@parcel/watcher-wasm@2.5.1': resolution: {integrity: sha512-RJxlQQLkaMMIuWRozy+z2vEqbaQlCuaCgVZIUCzQLYggY22LZbP5Y1+ia+FD724Ids9e+XIyOLXLrLgQSHIthw==} @@ -1764,36 +1858,42 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@rolldown/binding-linux-arm64-musl@1.0.0-rc.12': resolution: {integrity: sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12': resolution: {integrity: sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12': resolution: {integrity: sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@rolldown/binding-linux-x64-gnu@1.0.0-rc.12': resolution: {integrity: sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@rolldown/binding-linux-x64-musl@1.0.0-rc.12': resolution: {integrity: sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@rolldown/binding-openharmony-arm64@1.0.0-rc.12': resolution: {integrity: sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==} @@ -1879,56 +1979,67 @@ packages: resolution: {integrity: sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.53.2': resolution: {integrity: sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.53.2': resolution: {integrity: sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.53.2': resolution: {integrity: sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.53.2': resolution: {integrity: sha512-8ms8sjmyc1jWJS6WdNSA23rEfdjWB30LH8Wqj0Cqvv7qSHnvw6kgMMXRdop6hkmGPlyYBdRPkjJnj3KCUHV/uQ==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.53.2': resolution: {integrity: sha512-3HRQLUQbpBDMmzoxPJYd3W6vrVHOo2cVW8RUo87Xz0JPJcBLBr5kZ1pGcQAhdZgX9VV7NbGNipah1omKKe23/g==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.53.2': resolution: {integrity: sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.53.2': resolution: {integrity: sha512-XuGFGU+VwUUV5kLvoAdi0Wz5Xbh2SrjIxCtZj6Wq8MDp4bflb/+ThZsVxokM7n0pcbkEr2h5/pzqzDYI7cCgLQ==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.53.2': resolution: {integrity: sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.53.2': resolution: {integrity: sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.53.2': resolution: {integrity: sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openharmony-arm64@4.53.2': resolution: {integrity: sha512-4VEd19Wmhr+Zy7hbUsFZ6YXEiP48hE//KPLCSVNY5RMGX2/7HZ+QkN55a3atM1C/BZCGIgqN+xrVgtdak2S9+A==} @@ -2025,6 +2136,14 @@ packages: zod: optional: true + '@tabler/icons-react@3.41.1': + resolution: {integrity: sha512-kUgweE+DJtAlMZVIns1FTDdcbpRVnkK7ZpUOXmoxy3JAF0rSHj0TcP4VHF14+gMJGnF+psH2Zt26BLT6owetBA==} + peerDependencies: + react: '>= 16' + + '@tabler/icons@3.41.1': + resolution: {integrity: sha512-OaRnVbRmH2nHtFeg+RmMJ/7m2oBIF9XCJAUD5gQnMrpK9f05ydj8MZrAf3NZQqOXyxGN1UBL0D5IKLLEUfr74Q==} + '@tailwindcss/node@4.2.2': resolution: {integrity: sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==} @@ -2063,24 +2182,28 @@ packages: engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.2.2': resolution: {integrity: sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.2.2': resolution: {integrity: sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==} engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.2.2': resolution: {integrity: sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==} engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.2.2': resolution: {integrity: sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==} @@ -3554,8 +3677,8 @@ packages: resolution: {integrity: sha512-xQjs+2vrxLnAjCq+omuNkd5UQTld9/bP8+YT0LyYTlKfuSQtgUBvqhUwGugzSAh6sCdN+LnROMuLswn5hZ9Fhg==} engines: {node: '>=20.0.0'} - immutable@5.1.4: - resolution: {integrity: sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==} + immutable@5.1.5: + resolution: {integrity: sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==} import-in-the-middle@1.15.0: resolution: {integrity: sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA==} @@ -3820,24 +3943,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.32.0: resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.32.0: resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.32.0: resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.32.0: resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} @@ -4463,6 +4590,9 @@ packages: require-package-name@2.0.1: resolution: {integrity: sha512-uuoJ1hU/k6M0779t3VMVIYpb2VMJk05cehCaABFhXaibcbvfgR8wKiozLjVFSzJPmQMRqIcO0HMyTFqfV09V6Q==} + reselect@5.1.1: + resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} + resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} @@ -4764,10 +4894,16 @@ packages: resolution: {integrity: sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==} engines: {node: '>=18'} + tabbable@6.4.0: + resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} + tagged-tag@1.0.0: resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} engines: {node: '>=20'} + tailwind-merge@3.5.0: + resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==} + tailwindcss@4.1.18: resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} @@ -5505,6 +5641,8 @@ snapshots: '@babel/runtime@7.28.4': {} + '@babel/runtime@7.29.2': {} + '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 @@ -5563,6 +5701,30 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@base-ui/react@1.3.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.29.2 + '@base-ui/utils': 0.2.6(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@floating-ui/utils': 0.2.11 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + tabbable: 6.4.0 + use-sync-external-store: 1.6.0(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + + '@base-ui/utils@0.2.6(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.29.2 + '@floating-ui/utils': 0.2.11 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + reselect: 5.1.1 + use-sync-external-store: 1.6.0(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@borewit/text-codec@0.1.1': {} '@bramus/specificity@2.4.2': @@ -5799,6 +5961,23 @@ snapshots: '@fastify/busboy@3.2.0': {} + '@floating-ui/core@1.7.5': + dependencies: + '@floating-ui/utils': 0.2.11 + + '@floating-ui/dom@1.7.6': + dependencies: + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 + + '@floating-ui/react-dom@2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@floating-ui/dom': 1.7.6 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@floating-ui/utils@0.2.11': {} + '@fontsource/space-grotesk@5.2.10': {} '@humanwhocodes/momoa@2.0.4': {} @@ -6993,6 +7172,13 @@ snapshots: typescript: 6.0.2 zod: 4.3.6 + '@tabler/icons-react@3.41.1(react@19.2.4)': + dependencies: + '@tabler/icons': 3.41.1 + react: 19.2.4 + + '@tabler/icons@3.41.1': {} + '@tailwindcss/node@4.2.2': dependencies: '@jridgewell/remapping': 2.3.5 @@ -8664,7 +8850,7 @@ snapshots: imagetools-core@9.1.0: {} - immutable@5.1.4: + immutable@5.1.5: optional: true import-in-the-middle@1.15.0: @@ -9626,6 +9812,8 @@ snapshots: require-package-name@2.0.1: {} + reselect@5.1.1: {} + resolve-from@5.0.0: {} resolve-pkg-maps@1.0.0: {} @@ -9727,7 +9915,7 @@ snapshots: sass@1.94.0: dependencies: chokidar: 4.0.3 - immutable: 5.1.4 + immutable: 5.1.5 source-map-js: 1.2.1 optionalDependencies: '@parcel/watcher': 2.5.1 @@ -9986,8 +10174,12 @@ snapshots: system-architecture@0.1.0: {} + tabbable@6.4.0: {} + tagged-tag@1.0.0: {} + tailwind-merge@3.5.0: {} + tailwindcss@4.1.18: {} tailwindcss@4.2.2: {} diff --git a/src/components/footer.tsx b/src/components/footer.tsx new file mode 100644 index 0000000..b4d84fc --- /dev/null +++ b/src/components/footer.tsx @@ -0,0 +1,39 @@ +import { SOCIALS_DATA } from "$data"; + +import ACM_LOGO from "../lib/assets/pec-acm-logo.png"; +import { SocialIcon } from "./social-icon"; + +interface IFooterProps {} + +export function Footer(_props: IFooterProps) { + return ( +
+ +
+ ); +} diff --git a/src/components/navbar/index.tsx b/src/components/navbar/index.tsx new file mode 100644 index 0000000..00e009a --- /dev/null +++ b/src/components/navbar/index.tsx @@ -0,0 +1,131 @@ +import { Separator } from "@base-ui/react"; +import { Drawer } from "@base-ui/react/drawer"; +import { + IconX, + IconGitBranch, + IconLogin, + IconUsersGroup, + IconCalendarWeek, + IconMenu2, +} from "@tabler/icons-react"; +import { Link, useLocation } from "@tanstack/react-router"; + +import { SOCIALS_DATA } from "$data"; + +import { cn } from "$lib/utils"; +import ACM_LOGO from "../../lib/assets/pec-acm-logo.png"; +import { SocialIcon } from "../social-icon"; +import { MobileDrawer } from "./mobile-sheet"; + +const NAVBAR_LINKS = [ + { label: "Team", href: "/team", Icon: IconUsersGroup }, + { label: "Branches", href: "/branches", Icon: IconGitBranch }, + { label: "Events", href: "/events", Icon: IconCalendarWeek }, +]; + +interface INavbarProps {} + +export function Navbar(_props: INavbarProps) { + const { pathname } = useLocation(); + + const drawerHandle = Drawer.createHandle(); + + return ( + <> +
+
+
+ + + + + +
+ + +
+
+ +
+ + + + + + {drawerHandle.isOpen ? : } + +
+ + +
+
+ + + + + + + + + + +
+
+ + ); +} diff --git a/src/components/navbar/mobile-sheet.tsx b/src/components/navbar/mobile-sheet.tsx new file mode 100644 index 0000000..2289e74 --- /dev/null +++ b/src/components/navbar/mobile-sheet.tsx @@ -0,0 +1,24 @@ +import { Drawer } from "@base-ui/react/drawer"; + +interface IMobileDrawerProps { + handle: Drawer.Handle; + children: React.ReactNode; +} + +export function MobileDrawer({ handle, children }: IMobileDrawerProps) { + return ( + + + + + + {children} + + + + + ); +} diff --git a/src/components/social-icon.tsx b/src/components/social-icon.tsx new file mode 100644 index 0000000..7ef4cbc --- /dev/null +++ b/src/components/social-icon.tsx @@ -0,0 +1,30 @@ +import type { TSocialsData } from "$data"; + +import { PLATFORM_ICONS } from "$lib/constants/platforms"; +import { capitalize } from "$lib/utils"; + +interface TSocialIconProps { + link: TSocialsData[number]; +} + +export function SocialIcon({ link }: TSocialIconProps) { + const Icon = PLATFORM_ICONS[link.platform]; + + return ( +
  • + + + +
  • + ); +} diff --git a/src/data/devs.yaml b/src/data/devs.yaml index 4936e82..e88d09a 100644 --- a/src/data/devs.yaml +++ b/src/data/devs.yaml @@ -6,41 +6,41 @@ - Frontend - Documentation links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/harmanjeet-sahota/" - - platform: GitHub + - platform: github url: "https://github.com/Savy011" - name: Vidhi Sethi roles: - Co-Lead - Backend links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/vidhi-sethi-013962319/" - - platform: GitHub + - platform: github url: "https://github.com/vidhipec27" - name: Keshav Dham avatar: "devs/keshav.jpg" roles: - Documentation links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/keshavdham/" - - platform: GitHub + - platform: github url: https://github.com/KD9605 - name: Mithas Janbade roles: - Frontend links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/mithas-janbade-glorytogod/" - - platform: GitHub + - platform: github url: "https://github.com/mjisblessed" - name: Matisha Kansal roles: - Frontend links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/matisha-kansal/" - - platform: GitHub + - platform: github url: "https://github.com/MatishaKansal" diff --git a/src/data/index.ts b/src/data/index.ts index edf6838..30b9413 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -10,13 +10,14 @@ * */ import z from "zod"; +import { PLATFORMS } from "$lib/constants/platforms"; import { resolveStaticImg, slugify } from "$lib/utils"; import DEVS from "./devs.yaml"; import SOCIALS from "./socials.yaml"; import TEAM from "./team.yaml"; const LinkSchema = z.object({ - platform: z.string(), + platform: z.enum(PLATFORMS), url: z.url(), }); @@ -45,12 +46,7 @@ const TeamSchema = z.object({ groups: z.array(GroupSchema), }); -const SocialsSchema = z.array( - z.object({ - platform: z.string(), - url: z.url(), - }), -); +const SocialsSchema = z.array(LinkSchema); const RoleEnum = z.enum(["Project Lead", "Co-Lead", "Backend", "Frontend", "Documentation"]); diff --git a/src/data/socials.yaml b/src/data/socials.yaml index ff83233..6faefb5 100644 --- a/src/data/socials.yaml +++ b/src/data/socials.yaml @@ -1,14 +1,14 @@ -- platform: Discord +- platform: discord url: https://discord.gg/D68nVDjczA -- platform: Github +- platform: github url: https://github.com/PEC-CSS/ -- platform: Instagram +- platform: instagram url: https://www.instagram.com/pecacm -- platform: Youtube +- platform: youtube url: https://www.youtube.com/c/PECACMStudentChapter -- platform: LinkedIn +- platform: linkedin url: https://www.linkedin.com/company/pec-acm-student-chapter diff --git a/src/data/team.yaml b/src/data/team.yaml index 427ab32..44dd9f2 100644 --- a/src/data/team.yaml +++ b/src/data/team.yaml @@ -3,41 +3,41 @@ core: title: Chairperson avatar: "leads/gurmehar.jpg" links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/gurmehar-singh-87636425a/" - - platform: GitHub + - platform: github url: "https://github.com/GURMEHAR-PEC" - - platform: E-Mail + - platform: email url: "mailto:gurmeharsingh.bt22cse@pec.edu.in" - name: Anubhav Pandey title: Vice Chairperson avatar: "leads/anubhav.jpg" links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/anubhav3p/" - - platform: GitHub + - platform: github url: "https://github.com/Anubhavpandey27" - - platform: E-Mail + - platform: email url: "mailto:anubhavpandey.bt22cseds@pec.edu.in" - name: Gaurav Gupta title: Treasurer avatar: "leads/gaurav.jpg" links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/gaurav-gupta-7801a625b/" - - platform: GitHub + - platform: github url: "https://github.com/GauravGupta993" - - platform: E-Mail + - platform: email url: "mailto:gauravgupta.bt22cse@pec.edu.in" - name: Harshul Arora title: Webmaster avatar: "leads/harshul.jpg" links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/harshul-arora-7a264b250/" - - platform: GitHub + - platform: github url: "https://github.com/harshxll" - - platform: E-Mail + - platform: email url: "mailto:harshul.bt22cse@pec.edu.in" groups: @@ -46,16 +46,16 @@ groups: - name: Sambhav Jain avatar: "leads/sambhav.jpg" links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/sambhav2j/" - - platform: GitHub + - platform: github url: "https://github.com/SambhavJain74" - name: Chetanya Mahana avatar: "leads/chetanya.jpg" links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/chetanya-mahana-212a95258/" - - platform: GitHub + - platform: github url: "https://github.com/chetanyamahana" - name: Artificial Intelligence @@ -63,21 +63,21 @@ groups: - name: Arnav Vikas Garg avatar: "leads/arnav.jpg" links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/arnav-vikas-g-6079a2218/" - - platform: GitHub + - platform: github url: "https://github.com/ArnavVikasGarg" - name: Aaditya Sharma avatar: "leads/aaditya.jpg" links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/aaditya-sharma-255133257/" - - platform: GitHub + - platform: github url: "https://github.com/aadityasharma911" - name: Hardik Ahuja avatar: "leads/hardik.jpg" links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/hardik-ahuja-b4bb07252/" - name: Development @@ -85,16 +85,16 @@ groups: - name: Kritika Jari avatar: "leads/kritika.jpg" links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/krittika-jari-676897268/" - - platform: GitHub + - platform: github url: "https://github.com/krittika2004" - name: Harshit Minhas avatar: "leads/harshit.jpg" links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/harshit-minhas-879026253/" - - platform: GitHub + - platform: github url: "https://github.com/harshit-m007" - name: Open Source @@ -102,9 +102,9 @@ groups: - name: Raghav Sharma avatar: "leads/raghav.jpg" links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/raghav-sharma-0b8785270/" - - platform: GitHub + - platform: github url: "https://github.com/RAGHAVS1304" - name: Cyber-Security @@ -112,16 +112,16 @@ groups: - name: Aryan avatar: "leads/aryan.jpg" links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/aryan1006/" - - platform: GitHub + - platform: github url: "https://github.com/ary-a-n" - name: Keshav Arora avatar: "leads/keshav.jpg" links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/keshavarorapec/" - - platform: GitHub + - platform: github url: "https://github.com/CoderOMaster" - name: Socials @@ -129,16 +129,16 @@ groups: - name: Prasuk Jain avatar: "leads/prasuk.jpg" links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/prasuk-jain-1053b5244/" - - platform: GitHub + - platform: github url: "https://github.com/prasukjain07" - name: Shreya Pahuja avatar: "leads/shreya.jpg" links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/sp49/" - - platform: GitHub + - platform: github url: "https://github.com/sp9324" - name: Women In Tech @@ -146,12 +146,12 @@ groups: - name: Akanksha Narula avatar: "leads/akanksha.jpg" links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/akanksha-narula-b6ba26249/" - - platform: GitHub + - platform: github url: "https://github.com/AkankshaNarula" - name: Vanshika Garg avatar: "leads/vanshika.jpg" links: - - platform: LinkedIn + - platform: linkedin url: "https://www.linkedin.com/in/vanshika-330333271/" diff --git a/src/lib/assets/pec-acm-logo.png b/src/lib/assets/pec-acm-logo.png new file mode 100644 index 0000000..47be392 Binary files /dev/null and b/src/lib/assets/pec-acm-logo.png differ diff --git a/src/lib/constants/platforms.ts b/src/lib/constants/platforms.ts new file mode 100644 index 0000000..8dfe424 --- /dev/null +++ b/src/lib/constants/platforms.ts @@ -0,0 +1,30 @@ +import type { TablerIcon } from "@tabler/icons-react"; + +import { + IconMailFilled, + IconBrandLinkedinFilled, + IconBrandDiscordFilled, + IconBrandGithubFilled, + IconBrandInstagramFilled, + IconBrandYoutubeFilled, +} from "@tabler/icons-react"; + +export const PLATFORMS = [ + "discord", + "github", + "instagram", + "youtube", + "linkedin", + "email", +] as const; + +export type TPlatform = (typeof PLATFORMS)[number]; + +export const PLATFORM_ICONS: Record = { + email: IconMailFilled, + linkedin: IconBrandLinkedinFilled, + discord: IconBrandDiscordFilled, + github: IconBrandGithubFilled, + instagram: IconBrandInstagramFilled, + youtube: IconBrandYoutubeFilled, +}; diff --git a/src/lib/utils.ts b/src/lib/utils.ts index bc29a45..7518e4c 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,3 +1,38 @@ +import type { ClassValue } from "clsx"; + +import { clsx } from "clsx"; +import { twMerge } from "tailwind-merge"; + +/** + * Capitalizes the first character of a string. + * Returns the original value if the string is empty. + */ +export function capitalize(str: string) { + if (!str) return str; + return str.charAt(0).toUpperCase() + str.slice(1); +} + +/** + * Converts a string into a URL-friendly slug. + * Lowercases, normalizes unicode (café → cafe), removes special characters, + * and collapses spaces, underscores, and hyphens into a single hyphen. + * + * @example + * slugify("Hello World!") // "hello-world" + * slugify("café latte") // "cafe-latte" + * slugify("hello - world") // "hello-world" + */ +export function slugify(str: string) { + return str + .toLowerCase() + .normalize("NFD") + .replace(/[\u0300-\u036f]/g, "") + .trim() + .replace(/[^\w\s-]/g, "") + .replace(/[\s_-]+/g, "-") + .replace(/^-+|-+$/g, ""); +} + interface JWTPayload { sub: string; exp: number; @@ -13,15 +48,6 @@ export function decodeJWTPayload(token: string): JWTPayload | null { } } -export function slugify(str: string) { - return str - .toLowerCase() - .trim() - .replace(/[^\w\s-]/g, "") - .replace(/[\s_]+/g, "-") - .replace(/^-+|-+$/g, ""); -} - interface IImageMetadata { format: string; width: number; @@ -49,6 +75,16 @@ const allImages = import.meta.glob("/src/lib/assets/images/**/*", { }, }) as Record; +/** + * Resolves a static image asset path and returns its metadata. + * + * Accepts three path formats: + * - `$assets/images/foo.jpg` — alias prefix + * - `/src/lib/assets/images/foo.jpg` — absolute src path + * - `foo.jpg` — bare filename, resolved relative to the images directory + * + * @throws {Error} If the image asset cannot be found in the glob map + */ export function resolveStaticImg(path: string) { const fullPath = path.startsWith("$assets/images/") ? path.replace("$assets/images/", "src/lib/assets/images/") @@ -69,3 +105,18 @@ export function resolveStaticImg(path: string) { src: resolved.src, }; } + +/** + * Merges class names using `clsx` and resolves Tailwind CSS conflicts using `tailwind-merge`. + * + * @param inputs - Class values to merge. Accepts strings, objects, arrays, and falsy values. + * @returns A single merged class name string with Tailwind conflicts resolved. + * + * @example + * cn("p-4", "p-2") // "p-2" (conflict resolved) + * cn("flex", { hidden: false, block: true }) // "flex block" + * cn(undefined, null, "text-sm") // "text-sm" + */ +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index ded7cff..19ea9d0 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -10,19 +10,27 @@ import { Route as rootRouteImport } from './routes/__root' import { Route as AuthedRouteImport } from './routes/_authed' -import { Route as IndexRouteImport } from './routes/index' +import { Route as appRouteRouteImport } from './routes/(app)/route' +import { Route as appIndexRouteImport } from './routes/(app)/index' import { Route as ApiSplatRouteImport } from './routes/api.$' import { Route as authSignInRouteImport } from './routes/(auth)/sign-in' +import { Route as appTeamRouteImport } from './routes/(app)/team' +import { Route as appEventsRouteImport } from './routes/(app)/events' +import { Route as appBranchesRouteImport } from './routes/(app)/branches' import { Route as AuthedDashboardIndexRouteImport } from './routes/_authed/dashboard/index' const AuthedRoute = AuthedRouteImport.update({ id: '/_authed', getParentRoute: () => rootRouteImport, } as any) -const IndexRoute = IndexRouteImport.update({ +const appRouteRoute = appRouteRouteImport.update({ + id: '/(app)', + getParentRoute: () => rootRouteImport, +} as any) +const appIndexRoute = appIndexRouteImport.update({ id: '/', path: '/', - getParentRoute: () => rootRouteImport, + getParentRoute: () => appRouteRoute, } as any) const ApiSplatRoute = ApiSplatRouteImport.update({ id: '/api/$', @@ -34,6 +42,21 @@ const authSignInRoute = authSignInRouteImport.update({ path: '/sign-in', getParentRoute: () => rootRouteImport, } as any) +const appTeamRoute = appTeamRouteImport.update({ + id: '/team', + path: '/team', + getParentRoute: () => appRouteRoute, +} as any) +const appEventsRoute = appEventsRouteImport.update({ + id: '/events', + path: '/events', + getParentRoute: () => appRouteRoute, +} as any) +const appBranchesRoute = appBranchesRouteImport.update({ + id: '/branches', + path: '/branches', + getParentRoute: () => appRouteRoute, +} as any) const AuthedDashboardIndexRoute = AuthedDashboardIndexRouteImport.update({ id: '/dashboard/', path: '/dashboard/', @@ -41,41 +64,69 @@ const AuthedDashboardIndexRoute = AuthedDashboardIndexRouteImport.update({ } as any) export interface FileRoutesByFullPath { - '/': typeof IndexRoute + '/': typeof appIndexRoute + '/branches': typeof appBranchesRoute + '/events': typeof appEventsRoute + '/team': typeof appTeamRoute '/sign-in': typeof authSignInRoute '/api/$': typeof ApiSplatRoute '/dashboard/': typeof AuthedDashboardIndexRoute } export interface FileRoutesByTo { - '/': typeof IndexRoute + '/': typeof appIndexRoute + '/branches': typeof appBranchesRoute + '/events': typeof appEventsRoute + '/team': typeof appTeamRoute '/sign-in': typeof authSignInRoute '/api/$': typeof ApiSplatRoute '/dashboard': typeof AuthedDashboardIndexRoute } export interface FileRoutesById { __root__: typeof rootRouteImport - '/': typeof IndexRoute + '/(app)': typeof appRouteRouteWithChildren '/_authed': typeof AuthedRouteWithChildren + '/(app)/branches': typeof appBranchesRoute + '/(app)/events': typeof appEventsRoute + '/(app)/team': typeof appTeamRoute '/(auth)/sign-in': typeof authSignInRoute '/api/$': typeof ApiSplatRoute + '/(app)/': typeof appIndexRoute '/_authed/dashboard/': typeof AuthedDashboardIndexRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath - fullPaths: '/' | '/sign-in' | '/api/$' | '/dashboard/' + fullPaths: + | '/' + | '/branches' + | '/events' + | '/team' + | '/sign-in' + | '/api/$' + | '/dashboard/' fileRoutesByTo: FileRoutesByTo - to: '/' | '/sign-in' | '/api/$' | '/dashboard' + to: + | '/' + | '/branches' + | '/events' + | '/team' + | '/sign-in' + | '/api/$' + | '/dashboard' id: | '__root__' - | '/' + | '/(app)' | '/_authed' + | '/(app)/branches' + | '/(app)/events' + | '/(app)/team' | '/(auth)/sign-in' | '/api/$' + | '/(app)/' | '/_authed/dashboard/' fileRoutesById: FileRoutesById } export interface RootRouteChildren { - IndexRoute: typeof IndexRoute + appRouteRoute: typeof appRouteRouteWithChildren AuthedRoute: typeof AuthedRouteWithChildren authSignInRoute: typeof authSignInRoute ApiSplatRoute: typeof ApiSplatRoute @@ -90,12 +141,19 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AuthedRouteImport parentRoute: typeof rootRouteImport } - '/': { - id: '/' + '/(app)': { + id: '/(app)' + path: '' + fullPath: '' + preLoaderRoute: typeof appRouteRouteImport + parentRoute: typeof rootRouteImport + } + '/(app)/': { + id: '/(app)/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexRouteImport - parentRoute: typeof rootRouteImport + preLoaderRoute: typeof appIndexRouteImport + parentRoute: typeof appRouteRoute } '/api/$': { id: '/api/$' @@ -111,6 +169,27 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof authSignInRouteImport parentRoute: typeof rootRouteImport } + '/(app)/team': { + id: '/(app)/team' + path: '/team' + fullPath: '/team' + preLoaderRoute: typeof appTeamRouteImport + parentRoute: typeof appRouteRoute + } + '/(app)/events': { + id: '/(app)/events' + path: '/events' + fullPath: '/events' + preLoaderRoute: typeof appEventsRouteImport + parentRoute: typeof appRouteRoute + } + '/(app)/branches': { + id: '/(app)/branches' + path: '/branches' + fullPath: '/branches' + preLoaderRoute: typeof appBranchesRouteImport + parentRoute: typeof appRouteRoute + } '/_authed/dashboard/': { id: '/_authed/dashboard/' path: '/dashboard' @@ -121,6 +200,24 @@ declare module '@tanstack/react-router' { } } +interface appRouteRouteChildren { + appBranchesRoute: typeof appBranchesRoute + appEventsRoute: typeof appEventsRoute + appTeamRoute: typeof appTeamRoute + appIndexRoute: typeof appIndexRoute +} + +const appRouteRouteChildren: appRouteRouteChildren = { + appBranchesRoute: appBranchesRoute, + appEventsRoute: appEventsRoute, + appTeamRoute: appTeamRoute, + appIndexRoute: appIndexRoute, +} + +const appRouteRouteWithChildren = appRouteRoute._addFileChildren( + appRouteRouteChildren, +) + interface AuthedRouteChildren { AuthedDashboardIndexRoute: typeof AuthedDashboardIndexRoute } @@ -133,7 +230,7 @@ const AuthedRouteWithChildren = AuthedRoute._addFileChildren(AuthedRouteChildren) const rootRouteChildren: RootRouteChildren = { - IndexRoute: IndexRoute, + appRouteRoute: appRouteRouteWithChildren, AuthedRoute: AuthedRouteWithChildren, authSignInRoute: authSignInRoute, ApiSplatRoute: ApiSplatRoute, diff --git a/src/routes/(app)/branches.tsx b/src/routes/(app)/branches.tsx new file mode 100644 index 0000000..79c0b83 --- /dev/null +++ b/src/routes/(app)/branches.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/(app)/branches")({ + component: RouteComponent, +}); + +function RouteComponent() { + return
    Hello "/branches"!
    ; +} diff --git a/src/routes/(app)/events.tsx b/src/routes/(app)/events.tsx new file mode 100644 index 0000000..e6fc79b --- /dev/null +++ b/src/routes/(app)/events.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/(app)/events")({ + component: RouteComponent, +}); + +function RouteComponent() { + return
    Hello "/events"!
    ; +} diff --git a/src/routes/index.tsx b/src/routes/(app)/index.tsx similarity index 78% rename from src/routes/index.tsx rename to src/routes/(app)/index.tsx index 85b51f4..fa17063 100644 --- a/src/routes/index.tsx +++ b/src/routes/(app)/index.tsx @@ -1,6 +1,6 @@ import { createFileRoute, Link } from "@tanstack/react-router"; -export const Route = createFileRoute("/")({ component: App }); +export const Route = createFileRoute("/(app)/")({ component: App }); function App() { return ( diff --git a/src/routes/(app)/route.tsx b/src/routes/(app)/route.tsx new file mode 100644 index 0000000..2252e3b --- /dev/null +++ b/src/routes/(app)/route.tsx @@ -0,0 +1,22 @@ +import { createFileRoute, Outlet } from "@tanstack/react-router"; + +import { Footer } from "$components/footer"; +import { Navbar } from "$components/navbar"; + +export const Route = createFileRoute("/(app)")({ + component: RouteComponent, +}); + +function RouteComponent() { + return ( + <> + +
    +
    + +
    +
    +