diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml new file mode 100644 index 0000000..2b27a99 --- /dev/null +++ b/.github/workflows/dev.yml @@ -0,0 +1,36 @@ +name: Branch Preview + +on: + push: + branches: + - dev +jobs: + build: + runs-on: ubuntu-latest + permissions: + deployments: write + steps: + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: 18.18.0 + - uses: actions/checkout@v4 + - name: Cache node modules + uses: actions/cache@v2 + with: + path: | + **/node_modules + key: ${{ runner.os }}-modules-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + **/package-lock.json + - name: Install dependencies + run: | + npm install + + - name: Build and Deploy to Netlify + run: | + netlify deploy --prod --build + + env: + NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} + NETLIFY_SITE_ID: ${{ secrets.NETLIFY_DEV_SITE_ID }} diff --git a/README.md b/README.md index 41619f1..7314cce 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Welcome to the NIBM Computing Society website repository. This website is built - [Next.js](https://nextjs.org/) - A React framework for building fast and scalable applications. - [Sanity](https://www.sanity.io/) - A headless CMS that provides a powerful and flexible content backend. - [Tailwind CSS](https://tailwindcss.com/) - A utility-first CSS framework for rapidly building custom designs. +- [Vercel](https://vercel.com/) - A cloud platform for static sites and serverless functions. ## Getting Started @@ -67,7 +68,7 @@ Follow these steps to set up and run the project locally: docker run -p 3000:3000 nibmcs-website ``` - This will build a Docker image for the website and run it on port 3000. After running the container, you can access the website by opening your web browser and visiting http://localhost:3000. + This will build a Docker image for the website and run it on port 3000. After running the container, you can access the website by opening your web browser and visiting . **Local Development (Without Docker)**: @@ -78,7 +79,7 @@ Follow these steps to set up and run the project locally: npm run dev ``` - This will start the application without Docker, and you can access it by opening your web browser and visiting http://localhost:3000. + This will start the application without Docker, and you can access it by opening your web browser and visiting . ## Contributing diff --git a/next.config.js b/next.config.js index 820d953..fc7542a 100644 --- a/next.config.js +++ b/next.config.js @@ -1,14 +1,14 @@ -// /** @type {import('next').NextConfig} */ -// const nextConfig = { -// experimental: { -// appDir: true, -// }, -// distDir: 'build', -// }; - -// module.exports = nextConfig; - /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const nextConfig = { + images: { + remotePatterns: [ + { + protocol: 'https', + hostname: 'cdn.sanity.io', + port: '', + }, + ], + }, +}; module.exports = nextConfig; diff --git a/package-lock.json b/package-lock.json index 93ccab3..9c38d94 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "nibmcs.org", "version": "0.1.0", "dependencies": { + "@emailjs/browser": "^3.11.0", "@nextui-org/react": "^2.1.13", "@sanity/image-url": "^1.0.2", "@sanity/vision": "^3.16.7", @@ -16,8 +17,11 @@ "framer-motion": "^10.16.4", "next": "^13.5.6", "next-sanity": "^5.5.4", + "next-themes": "^0.2.1", "react": "latest", "react-dom": "latest", + "react-icons": "^4.11.0", + "react-toastify": "^9.1.3", "sanity": "^3.16.7", "styled-components": "5.2" }, @@ -744,6 +748,14 @@ "react": ">=16.8.0" } }, + "node_modules/@emailjs/browser": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/@emailjs/browser/-/browser-3.11.0.tgz", + "integrity": "sha512-RkY3FKZ3fPdK++OeF46mRTFpmmQWCHUVHZH209P3NE4D5sg2Atg7S2wa3gw5062Gl4clt4Wn5SyC4WhlVZC5pA==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@emotion/is-prop-valid": { "version": "0.8.8", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", @@ -10200,6 +10212,16 @@ "styled-components": "^5.2.0 || ^6.0.0" } }, + "node_modules/next-themes": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.2.1.tgz", + "integrity": "sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==", + "peerDependencies": { + "next": "*", + "react": "*", + "react-dom": "*" + } + }, "node_modules/node-abi": { "version": "3.47.0", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.47.0.tgz", @@ -11406,6 +11428,14 @@ } } }, + "node_modules/react-icons": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.11.0.tgz", + "integrity": "sha512-V+4khzYcE5EBk/BvcuYRq6V/osf11ODUM2J8hg2FDSswRrGvqiYUYPRy4OdrWaQOBj4NcpJfmHZLNaD+VH0TyA==", + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", @@ -11542,6 +11572,18 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/react-toastify": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.3.tgz", + "integrity": "sha512-fPfb8ghtn/XMxw3LkxQBk3IyagNpF/LIKjOBflbexr2AWxAH1MJgvnESwEwBn9liLFXgTKWgBSdZpw9m4OTHTg==", + "dependencies": { + "clsx": "^1.1.1" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", diff --git a/package.json b/package.json index 9bb0f52..ba1e3cd 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "lint": "next lint" }, "dependencies": { + "@emailjs/browser": "^3.11.0", "@nextui-org/react": "^2.1.13", "@sanity/image-url": "^1.0.2", "@sanity/vision": "^3.16.7", @@ -17,8 +18,11 @@ "framer-motion": "^10.16.4", "next": "^13.5.6", "next-sanity": "^5.5.4", + "next-themes": "^0.2.1", "react": "latest", "react-dom": "latest", + "react-icons": "^4.11.0", + "react-toastify": "^9.1.3", "sanity": "^3.16.7", "styled-components": "5.2" }, diff --git a/public/NCS-logo-color.png b/public/NCS-logo-color.png new file mode 100644 index 0000000..328f1bd Binary files /dev/null and b/public/NCS-logo-color.png differ diff --git a/public/events/01/01.jpg b/public/events/01/01.jpg new file mode 100644 index 0000000..4736c2a Binary files /dev/null and b/public/events/01/01.jpg differ diff --git a/public/events/01/02.jpg b/public/events/01/02.jpg new file mode 100644 index 0000000..89c9bcd Binary files /dev/null and b/public/events/01/02.jpg differ diff --git a/public/events/01/03.jpg b/public/events/01/03.jpg new file mode 100644 index 0000000..60fa23d Binary files /dev/null and b/public/events/01/03.jpg differ diff --git a/public/events/01/04.jpg b/public/events/01/04.jpg new file mode 100644 index 0000000..6525d34 Binary files /dev/null and b/public/events/01/04.jpg differ diff --git a/public/events/01/05.jpg b/public/events/01/05.jpg new file mode 100644 index 0000000..6d85ddc Binary files /dev/null and b/public/events/01/05.jpg differ diff --git a/public/events/01/06.jpg b/public/events/01/06.jpg new file mode 100644 index 0000000..1db6a11 Binary files /dev/null and b/public/events/01/06.jpg differ diff --git a/public/events/01/07.jpg b/public/events/01/07.jpg new file mode 100644 index 0000000..41626a0 Binary files /dev/null and b/public/events/01/07.jpg differ diff --git a/public/events/01/thumbnail.jpg b/public/events/01/thumbnail.jpg new file mode 100644 index 0000000..49dd929 Binary files /dev/null and b/public/events/01/thumbnail.jpg differ diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000..a104f02 Binary files /dev/null and b/public/logo.png differ diff --git a/sanity/lib/client.ts b/sanity/lib/client.ts index 49349a6..7ed68db 100644 --- a/sanity/lib/client.ts +++ b/sanity/lib/client.ts @@ -1,10 +1,12 @@ -import { createClient } from 'next-sanity' +import { createClient } from 'next-sanity'; -import { apiVersion, dataset, projectId, useCdn } from '../env' +import { apiVersion, dataset, projectId, useCdn } from '../env'; -export const client = createClient({ +const client = createClient({ apiVersion, dataset, projectId, useCdn, -}) +}); + +export default client; diff --git a/sanity/lib/queries.ts b/sanity/lib/queries.ts new file mode 100644 index 0000000..5432fa9 --- /dev/null +++ b/sanity/lib/queries.ts @@ -0,0 +1,33 @@ +import { groq } from 'next-sanity'; +import client from '../lib/client'; + +export async function getEvents() { + return client.fetch( + groq`*[_type == 'event'] | order(date desc) { + _id, + title, + slug, + date, + description, + location, + conductedBy, + mainImage {"image": asset->url}, + eventImages[] {"image": asset->url}, + }` + ); +} + +export async function getEventBySlug(slug: any) { + const query = groq`*[_type == 'event' && slug.current == $slug][0]{ + ..., + title, + mainImage {"image": asset->url}, + eventImages[] {"image": asset->url}, + description, + location, + conductedBy, + sponsors[]-> {title, logo{"image": asset->url }, link}, + }`; + + return client.fetch(query, { slug }); +} diff --git a/sanity/schema.ts b/sanity/schema.ts index 1da7a7a..a75abaa 100644 --- a/sanity/schema.ts +++ b/sanity/schema.ts @@ -1,5 +1,7 @@ -import { type SchemaTypeDefinition } from 'sanity' +import { type SchemaTypeDefinition } from 'sanity'; +import events from './schemas/events'; +import sponsors from './schemas/sponsors'; export const schema: { types: SchemaTypeDefinition[] } = { - types: [], -} + types: [events, sponsors], +}; diff --git a/sanity/schemas/events.ts b/sanity/schemas/events.ts new file mode 100644 index 0000000..3768b32 --- /dev/null +++ b/sanity/schemas/events.ts @@ -0,0 +1,80 @@ +import { defineType } from 'sanity'; + +export default defineType({ + name: 'event', + title: 'Event', + type: 'document', + fields: [ + { + name: 'title', + title: 'Event Title', + type: 'string', + validation: (Rule: any) => Rule.required(), + }, + { + name: 'mainImage', + title: 'Main Image', + type: 'image', + description: 'Main image for the event', + options: { hotspot: true }, + validation: (Rule: any) => Rule.required(), + }, + { + name: 'slug', + title: 'Slug', + type: 'slug', + options: { + source: 'title', + }, + validation: (Rule: any) => Rule.required(), + }, + { + name: 'date', + title: 'Date', + type: 'datetime', + validation: (Rule: any) => Rule.required(), + }, + { + name: 'description', + title: 'Description', + type: 'text', + validation: (Rule: any) => Rule.required(), + }, + { + name: 'location', + title: 'Location', + type: 'string', + validation: (Rule: any) => Rule.required(), + }, + { + name: 'conductedBy', + title: 'Conducted By', + type: 'array', + of: [ + { + type: 'object', + name: 'Speaker', + fields: [ + { type: 'string', name: 'speaker' }, + { type: 'string', name: 'role' }, + ], + }, + ], + validation: (Rule: any) => Rule.required(), + }, + { + name: 'eventImages', + title: 'Event Images', + type: 'array', + of: [{ type: 'image' }], + description: 'Images for the event', + options: { hotspot: true }, + }, + { + name: 'sponsors', + title: 'Sponsors', + type: 'array', + of: [{ type: 'reference', to: { type: 'sponsors' } }], + }, + ], +}); diff --git a/sanity/schemas/sponsors.ts b/sanity/schemas/sponsors.ts new file mode 100644 index 0000000..2cc2209 --- /dev/null +++ b/sanity/schemas/sponsors.ts @@ -0,0 +1,29 @@ +import { defineType } from 'sanity'; + +export default defineType({ + name: 'sponsors', + title: 'Sponsors', + type: 'document', + fields: [ + { + name: 'title', + title: 'Sponsor Title', + type: 'string', + validation: (Rule: any) => Rule.required(), + }, + { + name: 'logo', + title: 'Sponsor Logo', + type: 'image', + description: 'Sponsor logo', + options: { hotspot: true }, + validation: (Rule: any) => Rule.required(), + }, + { + name: 'link', + title: 'Sponsor Link', + type: 'url', + validation: (Rule: any) => Rule.required(), + }, + ], +}); diff --git a/src/app/about/layout.tsx b/src/app/about/layout.tsx new file mode 100644 index 0000000..71f2488 --- /dev/null +++ b/src/app/about/layout.tsx @@ -0,0 +1,15 @@ +export default function AboutLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( +
+
+
+ {children} +
+
+
+ ); +} diff --git a/src/app/about/page.tsx b/src/app/about/page.tsx new file mode 100644 index 0000000..9e4b155 --- /dev/null +++ b/src/app/about/page.tsx @@ -0,0 +1,7 @@ +export default function AboutPage() { + return ( +
+

About

+
+ ); +} diff --git a/src/app/blog/layout.tsx b/src/app/blog/layout.tsx new file mode 100644 index 0000000..cc334b5 --- /dev/null +++ b/src/app/blog/layout.tsx @@ -0,0 +1,15 @@ +export default function BlogLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( +
+
+
+ {children} +
+
+
+ ); +} diff --git a/src/app/blog/page.tsx b/src/app/blog/page.tsx new file mode 100644 index 0000000..9990b69 --- /dev/null +++ b/src/app/blog/page.tsx @@ -0,0 +1,7 @@ +export default function BlogPage() { + return ( +
+

Blog

+
+ ); +} diff --git a/src/app/contact/layout.tsx b/src/app/contact/layout.tsx new file mode 100644 index 0000000..23d6b95 --- /dev/null +++ b/src/app/contact/layout.tsx @@ -0,0 +1,15 @@ +export default function ContactLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( +
+
+
+ {children} +
+
+
+ ); +} diff --git a/src/app/contact/page.tsx b/src/app/contact/page.tsx new file mode 100644 index 0000000..6c5cb02 --- /dev/null +++ b/src/app/contact/page.tsx @@ -0,0 +1,156 @@ +'use client'; + +import React, { useRef } from 'react'; +import { motion } from 'framer-motion'; +import { BsArrowRight } from 'react-icons/bs'; +import { + HiOutlineMapPin, + HiOutlineEnvelope, + HiOutlinePhone, +} from 'react-icons/hi2'; +import { ToastContainer, toast } from 'react-toastify'; +import { fadeIn } from '../../utils/variants'; +import emailjs from '@emailjs/browser'; +import 'react-toastify/dist/ReactToastify.css'; +import Map from '../../components/map'; +import Box from '../../components/box'; + +export default function ContactPage() { + const ref: any = useRef(); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + const formData = new FormData(ref.current); + const requiredFields = ['user_name', 'user_email', 'subject', 'message']; + let isFormValid = true; + + requiredFields.forEach((field) => { + const value = formData.get(field); + if (!value || '') { + toast.error(`Please fill in ${field} field.`, { + theme: 'dark', + }); + isFormValid = false; + } + }); + + if (!isFormValid) { + return; + } + + emailjs + .sendForm( + 'service_ap4wbtw', + 'template_grf4xdq', + ref.current, + 'dStWJXq6rdaw4xHWs' + ) + .then( + () => { + toast.success('Message sent successfully!', { + theme: 'dark', + }); + + ref.current.reset(); + }, + () => { + toast.error('Something went wrong!', { + theme: 'dark', + }); + } + ); + }; + + return ( + <> +
+
+
+ + Let's connect. + + + +
+ + +
+ + + + +
+
+
+
+
+
+ +
+ + } + name={'Address'} + para={'120/5 Vidya Mawatha, Colombo 00700'} + /> + } + name={'Email'} + para={'info@nibmcs.org'} + /> + } name={'Phone'} para={'+94712691003'} /> + +
+ + ); +} diff --git a/src/app/events/[slug]/error.tsx b/src/app/events/[slug]/error.tsx new file mode 100644 index 0000000..5c49aa2 --- /dev/null +++ b/src/app/events/[slug]/error.tsx @@ -0,0 +1,27 @@ +'use client'; +import { Button } from '@nextui-org/react'; +// Error components must be Client Components +import { useEffect } from 'react'; + +export default function Error({ + error, + reset, +}: { + error: Error; + reset: () => void; +}) { + useEffect(() => { + // Log the error to an error reporting service + console.error(error); + }, [error]); + + return ( +
+

+ Something went wrong! +

+

{error.message}

+ +
+ ); +} diff --git a/src/app/events/[slug]/loading.tsx b/src/app/events/[slug]/loading.tsx new file mode 100644 index 0000000..8a4eb86 --- /dev/null +++ b/src/app/events/[slug]/loading.tsx @@ -0,0 +1,15 @@ +'use client'; +import { CircularProgress } from "@nextui-org/react"; + +export default function Loading() { + return ( +
+
+
+ + Loading... +
+
+
+ ) +} diff --git a/src/app/events/[slug]/not-found.tsx b/src/app/events/[slug]/not-found.tsx new file mode 100644 index 0000000..7bdfc0e --- /dev/null +++ b/src/app/events/[slug]/not-found.tsx @@ -0,0 +1,10 @@ +'use client'; +import NextLink from "next/link"; + +export default function NotFound() { + return ( + + Go BACK HOME + + ) +} diff --git a/src/app/events/[slug]/page.tsx b/src/app/events/[slug]/page.tsx new file mode 100644 index 0000000..d4b8b90 --- /dev/null +++ b/src/app/events/[slug]/page.tsx @@ -0,0 +1,21 @@ +import { getEventBySlug } from '../../../../sanity/lib/queries'; +import Body from '../components/body'; +import Header from '../components/header'; + +type Props = { + params: { + slug: string + } +} + +export default async function EventPage({ params: { slug } }: Props) { + + const event = await getEventBySlug(slug); + + return ( + <> +
+ + + ) +} \ No newline at end of file diff --git a/src/app/events/components/body.tsx b/src/app/events/components/body.tsx new file mode 100644 index 0000000..bc1b060 --- /dev/null +++ b/src/app/events/components/body.tsx @@ -0,0 +1,15 @@ +import EventDescription from "./eventDescription" +import Sponsors from "./sponsors" + +interface Props { + event: any +} + +export default function Body({ event }: Props) { + return ( + <> + {event.sponsors && } + + + ) +} \ No newline at end of file diff --git a/src/app/events/components/eventCard.tsx b/src/app/events/components/eventCard.tsx new file mode 100644 index 0000000..dd897e1 --- /dev/null +++ b/src/app/events/components/eventCard.tsx @@ -0,0 +1,63 @@ +import React from "react"; +import { Card, CardFooter, Button, Image, CardBody } from "@nextui-org/react"; +import { DateIcon, LocationPinIcon } from "@/components/icons"; +import NextLink from "next/link"; +import ClientSideRoute from '@/components/ClientSideRoute'; + +type Props = { + event: any +} + +export default function EventsCard({ event }: Props) { + return ( + + + + Git & Github Event + +
Already Held!
+ +
+
+ +

{event.title}

+
+
+ + {new Date(event.date).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })} +
+
+ + {event.location} +
+
+
+
{event.title} conducted by
+ {event.conductedBy.map((speaker: any, index: any) => ( +
{speaker.role} {speaker.speaker}
+ ))} +
+
+
+
+ ); +} diff --git a/src/app/events/components/eventDescription.tsx b/src/app/events/components/eventDescription.tsx new file mode 100644 index 0000000..44c6a08 --- /dev/null +++ b/src/app/events/components/eventDescription.tsx @@ -0,0 +1,82 @@ +'use client' +import { Card } from "@nextui-org/react"; + +interface Props { + event: any +} + +export default function EventDescription({ event }: Props) { + return ( + <> +
+
+
+ +
+
+
+
+

Details

+
+
+
+
Venue
+
+
+ {event.location} +
+
+
+
+
Time/Date
+
+
+ {new Date(event.date).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })} | {new Date(event.date).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} Onwards +
+
+
+
+
Conducted By
+
+
+ {event.conductedBy.map((speaker: any, index: any) => ( + <> + {speaker.role} {speaker.speaker} + , + + ))} +
+
+
+
+
+
+
+ +
+
+
+
+

Description

+
+
+

+ {event.description} +

+
+
+
+
+
+
+
+
+
+ + ) +} \ No newline at end of file diff --git a/src/app/events/components/header.tsx b/src/app/events/components/header.tsx new file mode 100644 index 0000000..4224716 --- /dev/null +++ b/src/app/events/components/header.tsx @@ -0,0 +1,75 @@ +import Image from 'next/image' +import { Logo } from "@/components/icons"; + +interface PageProps { + params: { + id: string + } +} + +const images = [ + { id: 1, imgUrl: '/events/01/01.jpg' }, + { id: 2, imgUrl: '/events/01/02.jpg' }, + { id: 3, imgUrl: '/events/01/03.jpg' }, + { id: 4, imgUrl: '/events/01/04.jpg' }, + { id: 5, imgUrl: '/events/01/05.jpg' }, + { id: 6, imgUrl: '/events/01/06.jpg' }, + { id: 7, imgUrl: '/events/01/07.jpg' }, +]; + +type Props = { + event: any +} + +export default function Header({ event }: Props) { + return ( +
+
+
+
+ + + +
+ +

+ + {new Date(event.date).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })} + + + {event.title} + +

+

+ Snaps of {event.title} conducted by + {event.conductedBy.map((speaker: any, index: any) => ( + <> + {speaker.role} {speaker.speaker} + , + + ))} +

+
+ {event.eventImages.map(({ image, index }: any) => ( +
+ Next.js Conf photo +
+ ))} +
+
+ ) +} \ No newline at end of file diff --git a/src/app/events/components/sponsors.tsx b/src/app/events/components/sponsors.tsx new file mode 100644 index 0000000..cd4cbbb --- /dev/null +++ b/src/app/events/components/sponsors.tsx @@ -0,0 +1,31 @@ +'use client' +import { Logo } from "@/components/icons" +import { Card } from "@nextui-org/react" +import Image from 'next/image' + +type Props = { + event: any +} + +export default function Sponsors({ event }: Props) { + return ( + <> + +
+
+

Partners

+
+ {event.sponsors && event.sponsors.map((sponsor: any, index: any) => ( +
+ {sponsor.title} +
+ ))} +
+
+
+
+ + ) +} \ No newline at end of file diff --git a/src/app/events/layout.tsx b/src/app/events/layout.tsx new file mode 100644 index 0000000..4564019 --- /dev/null +++ b/src/app/events/layout.tsx @@ -0,0 +1,15 @@ +export default function EventsLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( +
+
+
+ {children} +
+
+
+ ); +} diff --git a/src/app/events/page.tsx b/src/app/events/page.tsx new file mode 100644 index 0000000..bd0f8d5 --- /dev/null +++ b/src/app/events/page.tsx @@ -0,0 +1,20 @@ + +import React from "react"; +import EventsCard from "./components/eventCard"; +import { getEvents } from '../../../sanity/lib/queries'; + + +export default async function EventsPage() { + const events = await getEvents(); + return ( +
+
+ {events.map((event: any, index: any) => ( +
+ +
+ ))} +
+
+ ); +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 8c106d8..44a49fe 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,12 +1,25 @@ -import "./globals.css"; -import type { Metadata } from "next"; -import { Providers } from "./providers"; -import { Analytics } from "@vercel/analytics/react"; +import './globals.css'; +import type { Metadata } from 'next'; +import { Providers } from './providers'; +import { siteConfig } from '@/config/site'; +import clsx from 'clsx'; +import { fontSans } from '@/config/fonts'; +import { Navbar } from '@/components/navbar'; +import Footer from '@/components/Footer'; +import Social from '@/components/social'; export const metadata: Metadata = { - title: "NIBM Computing Society", - description: - "We are a student community organization for the NIBM - Sri Lanka, established with the aim of enabling us to learn, share, and build our professions.", + title: siteConfig.name, + description: siteConfig.description, + themeColor: [ + { media: '(prefers-color-scheme: light)', color: 'white' }, + { media: '(prefers-color-scheme: dark)', color: 'black' }, + ], + icons: { + icon: '/favicon.ico', + shortcut: '/favicon-16x16.png', + apple: '/apple-touch-icon.png', + }, }; export default function RootLayout({ @@ -15,11 +28,22 @@ export default function RootLayout({ children: React.ReactNode; }) { return ( - - - {children} - + + + +
+ + + {children} +
+
+
- + ); -} +} \ No newline at end of file diff --git a/src/app/leaderboard/layout.tsx b/src/app/leaderboard/layout.tsx new file mode 100644 index 0000000..7f38912 --- /dev/null +++ b/src/app/leaderboard/layout.tsx @@ -0,0 +1,15 @@ +export default function LeaderBoardLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( +
+
+
+ {children} +
+
+
+ ); +} diff --git a/src/app/leaderboard/page.tsx b/src/app/leaderboard/page.tsx new file mode 100644 index 0000000..c7bbde0 --- /dev/null +++ b/src/app/leaderboard/page.tsx @@ -0,0 +1,7 @@ +export default function LeaderBoardPage() { + return ( +
+

Leaderboard

+
+ ); +} diff --git a/src/app/membership/layout.tsx b/src/app/membership/layout.tsx new file mode 100644 index 0000000..9bc9e26 --- /dev/null +++ b/src/app/membership/layout.tsx @@ -0,0 +1,15 @@ +export default function MembershipLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( +
+
+
+ {children} +
+
+
+ ); +} diff --git a/src/app/membership/page.tsx b/src/app/membership/page.tsx new file mode 100644 index 0000000..22c803d --- /dev/null +++ b/src/app/membership/page.tsx @@ -0,0 +1,7 @@ +export default function MembershipPage() { + return ( +
+

Membership

+
+ ); +} diff --git a/src/app/page.tsx b/src/app/page.tsx index e165fb3..d0f6866 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,9 +1,13 @@ import React from "react"; +import { siteConfig } from "@/config/site"; +import { Logo } from "@/components/icons"; export default function Home() { return ( -
-
Coming Soon
+
+
{siteConfig.name}
+ +
Home Page
); -} \ No newline at end of file +} diff --git a/src/app/providers.tsx b/src/app/providers.tsx index be02117..08e75ea 100644 --- a/src/app/providers.tsx +++ b/src/app/providers.tsx @@ -1,8 +1,28 @@ -'use client'; +// "use client"; -import './globals.css'; -import { NextUIProvider } from '@nextui-org/react'; +// import "./globals.css"; +// import { NextUIProvider } from '@nextui-org/react'; -export function Providers({ children }: { children: React.ReactNode }) { - return {children}; +// export function Providers({ children }: { children: React.ReactNode }) { +// return {children}; +// } + +"use client"; + +import * as React from "react"; +import { NextUIProvider } from "@nextui-org/system"; +import { ThemeProvider as NextThemesProvider } from "next-themes"; +import { ThemeProviderProps } from "next-themes/dist/types"; + +export interface ProvidersProps { + children: React.ReactNode; + themeProps?: ThemeProviderProps; +} + +export function Providers({ children, themeProps }: ProvidersProps) { + return ( + + {children} + + ); } diff --git a/src/components/ClientSideRoute.tsx b/src/components/ClientSideRoute.tsx new file mode 100644 index 0000000..9a44f63 --- /dev/null +++ b/src/components/ClientSideRoute.tsx @@ -0,0 +1,12 @@ +'use client' + +import Link from 'next/link' +import React from 'react' + +const ClientSideRoute = ({ children, route }: { children: React.ReactNode; route: string; }) => { + return ( + {children} + ) +} + +export default ClientSideRoute \ No newline at end of file diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx new file mode 100644 index 0000000..508f4b5 --- /dev/null +++ b/src/components/Footer.tsx @@ -0,0 +1,15 @@ +'use client'; + +import { siteConfig } from "@/config/site"; +import { usePathname } from 'next/navigation'; + +export default function Footer() { + const pathname = usePathname(); + return ( +
+

+ © 2023 {siteConfig.name}. All rights reserved. +

+
+ ); +} diff --git a/src/components/box.tsx b/src/components/box.tsx new file mode 100644 index 0000000..5be63a8 --- /dev/null +++ b/src/components/box.tsx @@ -0,0 +1,17 @@ +import React from 'react'; + +const Box = ({ icon, name, para }: any) => { + return ( +
+
+
{icon}
+

+ {name} +

+

{para}

+
+
+ ); +}; + +export default Box; diff --git a/src/components/icons.tsx b/src/components/icons.tsx new file mode 100644 index 0000000..aefa125 --- /dev/null +++ b/src/components/icons.tsx @@ -0,0 +1,84 @@ +import { + RiFacebookLine, + RiGithubLine, + RiInstagramLine, + RiLinkedinLine, + RiTwitterXLine, +} from 'react-icons/ri'; +import { MdDarkMode, MdLightMode, MdLocationOn, MdCalendarMonth } from 'react-icons/md'; +import Image from 'next/image'; + +const iconSize = 18; +const className = 'text-default-500 hover:text-[#1E50FF] transition-all duration-300 ease-in-out'; + +interface ThemedImageProps { + className?: string; + width?: number; + height?: number; + priority?: boolean; +} + +export const Logo = ({ + className, + width = 200, + height = 112.5, + priority = false, +}: ThemedImageProps) => ( + <> + {/* When the theme is dark */} + NCS LOGO + + {/* When the theme is light */} + NCS LOGO + +); + +export const FacebookIcon = () => { + return ; +}; + +export const InstagramIcon = () => { + return ; +}; + +export const TwitterIcon = () => { + return ; +}; + +export const GithubIcon = () => { + return ; +}; + +export const LinkedinIcon = () => { + return ; +}; + +export const DarkModeIcon = () => { + return ; +}; + +export const LightModeIcon = () => { + return ; +}; + +export const LocationPinIcon = () => { + return ; +}; + +export const DateIcon = () => { + return ; +}; diff --git a/src/components/map.tsx b/src/components/map.tsx new file mode 100644 index 0000000..1f85dd3 --- /dev/null +++ b/src/components/map.tsx @@ -0,0 +1,23 @@ +import { motion } from 'framer-motion'; +import { fadeIn } from '../utils/variants'; + +export default function Map() { + return ( +
+ +
+ ); +} diff --git a/src/components/navbar.tsx b/src/components/navbar.tsx new file mode 100644 index 0000000..c7164dc --- /dev/null +++ b/src/components/navbar.tsx @@ -0,0 +1,133 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { + Navbar as NextUINavbar, + NavbarContent, + NavbarMenu, + NavbarMenuToggle, + NavbarBrand, + NavbarItem, + NavbarMenuItem, +} from '@nextui-org/navbar'; +import { Button } from '@nextui-org/react'; +import { Link } from '@nextui-org/link'; +import { link as linkStyles } from '@nextui-org/theme'; +import { siteConfig } from '@/config/site'; +import NextLink from 'next/link'; +import clsx from 'clsx'; +import { usePathname } from 'next/navigation'; +import { Logo } from '@/components/icons'; + +export const Navbar = () => { + const [scrolling, setScrolling] = useState(false); + const pathname = usePathname(); + + useEffect(() => { + const handleScroll = () => { + if (window.scrollY > 50) { + setScrolling(true); + } else { + setScrolling(false); + } + }; + + window.addEventListener('scroll', handleScroll); + + return () => { + window.removeEventListener('scroll', handleScroll); + }; + }, []); + + return ( + + + + + + + + + + +
    + {siteConfig.navItems.map((item) => ( + + + {item.label} + + + ))} +
+
+ + + + + + + + + + + + +
+ {siteConfig.navItems.map((item, index) => ( + + + {item.label} + + + ))} + + + + Membership + + +
+
+
+ ); +}; diff --git a/src/components/social.tsx b/src/components/social.tsx new file mode 100644 index 0000000..156ce9e --- /dev/null +++ b/src/components/social.tsx @@ -0,0 +1,44 @@ +'use client'; + +import { + RiInstagramLine, + RiFacebookLine, + RiGithubLine, + RiLinkedinLine, + RiTwitterXLine, +} from 'react-icons/ri'; +import Link from 'next/link'; +import { usePathname } from 'next/navigation'; + +export const socialData = [ + { path: 'https://instagram.com/nibmcs', icon: }, + { path: 'https://facebook.com/nibmcs', icon: }, + { path: 'https://github.com/nibmcs', icon: }, + { path: 'https://linkedin.com/company/nibmcs', icon: }, + { path: 'https://twitter.com/nibmcs', icon: }, +]; + +const Social = () => { + return ( + + ); +}; + +export default Social; diff --git a/src/components/theme-switch.tsx b/src/components/theme-switch.tsx new file mode 100644 index 0000000..e4089bc --- /dev/null +++ b/src/components/theme-switch.tsx @@ -0,0 +1,79 @@ +"use client"; + +import { FC } from "react"; +import { VisuallyHidden } from "@react-aria/visually-hidden"; +import { SwitchProps, useSwitch } from "@nextui-org/switch"; +import { useTheme } from "next-themes"; +import { useIsSSR } from "@react-aria/ssr"; +import clsx from "clsx"; + +import { DarkModeIcon, LightModeIcon } from "@/components/icons"; + +export interface ThemeSwitchProps { + className?: string; + classNames?: SwitchProps["classNames"]; +} + +export const ThemeSwitch: FC = ({ + className, + classNames, +}) => { + const { theme, setTheme } = useTheme(); + const isSSR = useIsSSR(); + + const onChange = () => { + theme === "light" ? setTheme("dark") : setTheme("light"); + }; + + const { + Component, + slots, + isSelected, + getBaseProps, + getInputProps, + getWrapperProps, + } = useSwitch({ + isSelected: theme === "light" || isSSR, + "aria-label": `Switch to ${ + theme === "light" || isSSR ? "dark" : "light" + } mode`, + onChange, + }); + + return ( + + + + +
+ {!isSelected || isSSR ? : } +
+
+ ); +}; diff --git a/src/config/fonts.ts b/src/config/fonts.ts new file mode 100644 index 0000000..43a02f4 --- /dev/null +++ b/src/config/fonts.ts @@ -0,0 +1,8 @@ +import { Poppins } from 'next/font/google'; + +export const fontSans = Poppins({ + subsets: ['latin'], + weight: ['400', '500', '600', '700', '800'], + variable: '--font-sans', + style: 'normal', +}); diff --git a/src/config/site.ts b/src/config/site.ts new file mode 100644 index 0000000..c09a802 --- /dev/null +++ b/src/config/site.ts @@ -0,0 +1,41 @@ +export type SiteConfig = typeof siteConfig; + +export const siteConfig = { + name: 'NIBM Computing Society', + description: + 'We are a student community organization for the NIBM - Sri Lanka, established with the aim of enabling us to learn, share, and build our professions.', + navItems: [ + { + label: 'Events', + href: '/events', + active: false, + }, + { + label: 'Leaderboard', + href: '/leaderboard', + active: false, + }, + { + label: 'Blog', + href: '/blog', + active: false, + }, + { + label: 'About', + href: '/about', + active: false, + }, + { + label: 'Contact', + href: '/contact', + active: false, + }, + ], + // links: { + // facebook: 'https://facebook.com/nibmcs', + // instagram: 'https://instagram.com/nibmcs', + // twitter: 'https://twitter.com/nibmcs', + // linkedin: 'https://linkedin.com/company/nibmcs', + // github: 'https://github.com/nibmcs', + // }, +}; diff --git a/src/utils/variants.ts b/src/utils/variants.ts new file mode 100644 index 0000000..d1c8af1 --- /dev/null +++ b/src/utils/variants.ts @@ -0,0 +1,26 @@ +export const fadeIn = (direction: any, delay: any) => { + return { + hidden: { + y: direction === 'up' ? 80 : direction === 'down' ? -80 : 0, + opacity: 0, + x: direction === 'left' ? 80 : direction === 'right' ? -80 : 0, + transition: { + type: 'tween', + duration: 1.5, + delay: delay, + ease: [0.25, 0.6, 0.3, 0.8], + }, + }, + show: { + y: 0, + x: 0, + opacity: 1, + transition: { + type: 'tween', + duration: 1.4, + delay: delay, + ease: [0.25, 0.25, 0.25, 0.75], + }, + }, + }; +}; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy