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/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/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/src/app/about/layout.tsx b/src/app/about/layout.tsx new file mode 100644 index 0000000..d5f6271 --- /dev/null +++ b/src/app/about/layout.tsx @@ -0,0 +1,13 @@ +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..45deef1 --- /dev/null +++ b/src/app/blog/layout.tsx @@ -0,0 +1,13 @@ +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..c3c01b7 --- /dev/null +++ b/src/app/contact/layout.tsx @@ -0,0 +1,13 @@ +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/layout.tsx b/src/app/events/layout.tsx new file mode 100644 index 0000000..e119668 --- /dev/null +++ b/src/app/events/layout.tsx @@ -0,0 +1,13 @@ +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..da87c79 --- /dev/null +++ b/src/app/events/page.tsx @@ -0,0 +1,7 @@ +export default function EventsPage() { + return ( +
+

Events

+
+ ); +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 8c106d8..049bee4 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,10 +28,23 @@ export default function RootLayout({ children: React.ReactNode; }) { return ( - - - {children} - + + + +
+ + +
+ {children} +
+
+
+
); diff --git a/src/app/leaderboard/layout.tsx b/src/app/leaderboard/layout.tsx new file mode 100644 index 0000000..953bc91 --- /dev/null +++ b/src/app/leaderboard/layout.tsx @@ -0,0 +1,13 @@ +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..465fb25 --- /dev/null +++ b/src/app/membership/layout.tsx @@ -0,0 +1,13 @@ +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/Footer.tsx b/src/components/Footer.tsx new file mode 100644 index 0000000..edbedfc --- /dev/null +++ b/src/components/Footer.tsx @@ -0,0 +1,11 @@ +import { siteConfig } from "@/config/site"; + +export default function Footer() { + 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..5697f69 --- /dev/null +++ b/src/components/icons.tsx @@ -0,0 +1,76 @@ +import { + RiFacebookLine, + RiGithubLine, + RiInstagramLine, + RiLinkedinLine, + RiTwitterXLine, +} from 'react-icons/ri'; +import { MdDarkMode, MdLightMode } 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 ; +}; 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..fd0444e --- /dev/null +++ b/src/components/navbar.tsx @@ -0,0 +1,136 @@ +'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..bf7cc91 --- /dev/null +++ b/src/components/social.tsx @@ -0,0 +1,43 @@ +'use client'; + +import { + RiInstagramLine, + RiFacebookLine, + RiGithubLine, + RiLinkedinLine, + RiTwitterXLine, +} from 'react-icons/ri'; +import Link from 'next/link'; + +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 ( +
+
+ {socialData.map((link, index) => { + return ( + +
+ {link.icon} +
+ + ); + })} +
+
+ ); +}; + +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