diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ef6a52 --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/README.md b/README.md new file mode 100644 index 0000000..95dbffc --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# IRNOG Website + +Welcome to the IRNOG Website project! 🚀 This is a **Next.js** application designed to power the official website for IRNOG, providing information, updates, and resources for the IRNOG community. + +## 🌐 About the Project + +IRNOG is a community-driven initiative that brings together networking professionals and enthusiasts. This website serves as the central hub for: + +- Event announcements and schedules +- Blog posts and technical articles +- Community discussions +- Networking resources and guides + +## 🛠 Tech Stack +- **Next.js** - React Framework +- **Tailwind CSS** - Styling +- **TypeScript** - Strongly Typed Codebase +- **Vercel** - Deployment platform + + +## 🚀 Getting Started +To run the project locally, follow these steps: +1. **Clone the repository**: + +2. **Install dependencies**: + ```sh + npm install + ``` +3. **Start the development server**: + ```sh + npm run dev + ``` +4. Open [http://localhost:3000](http://localhost:3000) in your browser to view the site. + + +## 🙌 Join the Community +Feel free to ask questions, suggest improvements, or just say hi! Connect with us via: +- **GitHub Issues** +- **Discussions Tab** + + diff --git a/app/buyTicket/page.tsx b/app/buyTicket/page.tsx new file mode 100644 index 0000000..f133833 --- /dev/null +++ b/app/buyTicket/page.tsx @@ -0,0 +1,159 @@ +"use client"; +import { Card } from "@/components/ui/card"; +import { FC } from "react"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; + +import { toast } from "react-toastify"; +import { Button } from "@/components/ui/button"; +import { + Form, + FormControl, + FormField, + FormItem, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; + +const FormSchema = z.object({ + username: z.string().min(2, { message: "نام باید حداقل ۲ کاراکتر باشد" }), + lastName: z + .string() + .min(2, { message: "نام خانوادگی باید حداقل ۲ کاراکتر باشد" }), + phone: z.string().min(10, { message: "شماره تماس معتبر وارد کنید" }), + email: z.string().email({ message: "ایمیل معتبر وارد کنید" }), + company: z.string().optional(), +}); + +const BuyTicket: FC = () => { + const form = useForm>({ + resolver: zodResolver(FormSchema), + defaultValues: { + username: "", + lastName: "", + phone: "", + email: "", + company: "", + }, + }); + + function onSubmit(data: z.infer) { + toast.success(`اطلاعات ارسال شد `); + } + + return ( +
+ +

+ تهیه بلیط +

+
+ +
+ {/** Username */} + ( + + + + + + + )} + /> + {/** Last Name */} + ( + + + + + + + )} + /> +
+
+ {/** Phone */} + ( + + + + + + + )} + /> + {/** Email */} + ( + + + + + + + )} + /> +
+ {/** Company (Optional) */} + ( + + + + + + + )} + /> + + + + +
+
+ ); +}; +export default BuyTicket; diff --git a/app/cfp/page.tsx b/app/cfp/page.tsx new file mode 100644 index 0000000..df0ddce --- /dev/null +++ b/app/cfp/page.tsx @@ -0,0 +1,268 @@ +"use client"; +import { Card } from "@/components/ui/card"; +import { FC } from "react"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; + +import { toast } from "react-toastify"; +import { Button } from "@/components/ui/button"; +import { + Form, + FormControl, + FormField, + FormItem, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { Presentation } from "lucide-react"; + +const FormSchema = z.object({ + username: z.string().min(2, { message: "نام باید حداقل ۲ کاراکتر باشد" }), + lastName: z + .string() + .min(2, { message: "نام خانوادگی باید حداقل ۲ کاراکتر باشد" }), + phone: z.string().min(10, { message: "شماره تماس معتبر وارد کنید" }), + email: z.string().email({ message: "ایمیل معتبر وارد کنید" }), + company: z.string().optional(), + PresentationSubject: z + .string() + .min(2, { message: "موضوع ارائه باید حداقل ۲ کاراکتر باشد" }), + TFP: z.string().optional(), + peresentationFile: z + .instanceof(File, { message: "فایل معتبر انتخاب کنید" }) + .refine( + (file) => file.size < 5 * 1024 * 1024, + "فایل نباید بیشتر از 5MB باشد" + ), + + description: z.string().optional(), +}); + +const CfpPage: FC = () => { + const form = useForm>({ + resolver: zodResolver(FormSchema), + defaultValues: { + username: "", + lastName: "", + phone: "", + email: "", + company: "", + PresentationSubject: "", + TFP: "", + }, + }); + + function onSubmit(data: z.infer) { + toast.success(`اطلاعات ارسال شد `); + } + + return ( +
+ +

+ هماهنگی برای ارائه +

+
+ +
+ {/** Last Name */} + ( + + + + + + + )} + /> + {/** Username */} + ( + + + + + + + )} + /> +
+
+ {/** Email */} + ( + + + + + + + )} + /> + {/** Phone */} + ( + + + + + + + )} + /> +
+
+ {/** Company (Optional) */} + ( + + + + + + + )} + /> + + {/** Presentation subject*/} + ( + + + + + + + )} + /> +
+
+ {/** time for Presentation*/} + ( + + + + + + + )} + /> + {/** Presentation File*/} + ( + + +
+ <> + { + const file = event.target.files?.[0]; + if (file) { + onChange(file); + } + }} + ref={ref} + /> + + +
+
+ +
+ )} + /> +
+ {/** Description*/} + ( + + + + + + + )} + /> + + + + +
+
+ ); +}; +export default CfpPage; diff --git a/app/globals.css b/app/globals.css new file mode 100644 index 0000000..1c3fd17 --- /dev/null +++ b/app/globals.css @@ -0,0 +1,61 @@ +@import "tailwindcss"; + +@plugin "tailwindcss-animate"; + +@theme { + --color-primary: oklch(0.3427 0.056 241.38); + --color-secondary: oklch(0.9158 0 0); + --color-Tertiary: oklch(0.4014 0.0685 242.8); + + --animate-shimmer: shimmer 2s linear infinite; + @keyframes shimmer { + from { + background-position: 0 0; + } + to { + background-position: -200% 0; + } + } +} +@layer utilities { + .no-scrollbar::-webkit-scrollbar { + display: none; + } + .no-scrollbar { + -ms-overflow-style: none; + scrollbar-width: none; + } +} + +.shinyButton { + @apply bg-transparent backdrop-blur-lg border-gray-300 uppercase hover:shadow-[0_4px_6px_rgba(255,255,255,0.5)] inline-flex animate-shimmer border bg-[linear-gradient(110deg,#26364f,45%,#677284,55%,#26364f)] bg-[length:200%_100%] font-medium transition-colors; +} + +@font-face { + font-family: "IranSans"; + src: url("/fonts/IRANSansWeb.ttf") format("truetype"); +} + +@font-face { + font-family: "Soraya"; + src: url("/fonts/Soraya.ttf") format("truetype"); +} + +@font-face { + font-family: "Sahel"; + src: url("/fonts/Sahel.ttf") format("truetype"); +} +@font-face { + font-family: "Rust"; + src: url("/fonts/NexaRustSlab-BlackShadow01.otf") format("truetype"); +} +@theme { + --font-IranSans: "IranSanse"; + --font-Soraya: "Soraya"; + --font-Sahel: "Sahel"; + --font-Rust: "Rust"; +} + +body { + @apply font-Sahel; +} diff --git a/app/irnog/[id]/page.tsx b/app/irnog/[id]/page.tsx new file mode 100644 index 0000000..ee998ad --- /dev/null +++ b/app/irnog/[id]/page.tsx @@ -0,0 +1,370 @@ +"use client"; + +import { useParams } from "next/navigation"; +import { FC } from "react"; +import { IrnogPageContent } from "@/components/IrnogPageContent/IrnogPageContent"; +import NotFoundPage from "@/app/not-found"; +import Accordion from "@/components/AccordionTable/Accordion"; +import Image from "next/image"; +import defaultImage from "../../../public/pics/defaultIMage/default.png"; + +const IrnogPage: FC = () => { + const params = useParams(); + const { id } = params; + const page = IrnogPageContent.find((page) => page.key === id); + const handleOpenMapClick = (link: string | undefined) => { + window.open(link); + }; + const allowedID = ["1", "2", "3", "4", "5", "6"]; + if (!allowedID.includes(id as string)) { + return ; + } + return ( +
+ <> +
+ {/* title */} +

+
+ {page?.value.title} همایش رسمی گروه گردانندگان شبکه اینترنت ایران +
+
IRNOG {id}
+

+ {/* time */} + {page?.value.time &&
{page?.value.time}
} + {/* location */} +
+ {page?.value.location.country} - {page?.value.location.city} +
+
{page?.value.location.detail}
+ {page?.value.location.locationLink && ( + + )} + {/* irnog agenda */} + {page?.value.irnogAgenda && ( +
+ + + + + + {page.value.irnogAgenda.some( + (agenda) => agenda.presentationTime + ) && ( + + )} + + {page.value.irnogAgenda.some( + (agenda) => agenda.presentationFile + ) && ( + + )} + + + + {page.value.irnogAgenda.map((irnogAgenda) => ( + + + + {irnogAgenda.presentationTime && ( + + )} + + {irnogAgenda.presentationFile && ( + + )} + + ))} + +
+ شخص ارائه دهنده + + عنوان ارائه + + ساعت + + مستندات + + فایل +
+ {irnogAgenda.presenter} + + {irnogAgenda.presentationTitle} + + {irnogAgenda.presentationTime} + + + window.open(irnogAgenda.presentationLink) + } + className="text-white hover:text-secondary cursor-pointer" + > + مشاهده + + + { + if (irnogAgenda.presentationFile) { + window.open( + irnogAgenda.presentationFile, + "_blank" + ); + } + }} + className="text-white hover:text-secondary cursor-pointer" + > + {irnogAgenda.presentationFile === "#" + ? "_" + : "فایل"} + +
+
+ )} + + {/* sponsors */} + {page?.value.sponsers && ( +
+

+ حامیان همایش +

+ {/* hostSponsors */} + {page?.value.sponsers?.hostSponsors && ( + <> +

+ حامی مالی میزبان +

+
+
+ window.open(page?.value.sponsers?.hostSponsors?.link) + } + > + {page?.value.sponsers.hostSponsors.name} +
+ {page?.value.sponsers.hostSponsors.name} +
+
+
+ + )} + {/* platinumSponsors */} + {page?.value.sponsers?.platinumSponsors && ( + <> +

+ حامیان مالی پلاتینیوم +

+ +
+ {page.value.sponsers.platinumSponsors.map( + (sponsor, index) => ( +
window.open(sponsor.link)} + > + {sponsor.name} +
+ {sponsor.name} +
+
+ ) + )} +
+ + )} + {/* goldSponsors */} + {page?.value.sponsers?.goldSponsors && ( + <> +

+ حامیان مالی طلایی +

+
+ {page.value.sponsers.goldSponsors.map((sponsor, index) => ( +
window.open(sponsor.link)} + > + {sponsor.name} +
+ {sponsor.name} +
+
+ ))} +
+ + )} + {/* silverSponsors */} + {page?.value.sponsers?.silverSponsors && ( + <> +

+ حامیان مالی نقره ای +

+ +
+ {page.value.sponsers.silverSponsors.map( + (sponsor, index) => ( +
window.open(sponsor.link)} + > + {sponsor.name} +
+ {sponsor.name} +
+
+ ) + )} +
+ + )} + {/* ConnectivitySponsors */} + {page?.value.sponsers?.ConnectivitySponsors && ( + <> +

+ Connectivity حامیان +

+
+ {page.value.sponsers.ConnectivitySponsors.map( + (sponsor, index) => ( +
window.open(sponsor.link)} + > + {sponsor.name} +
+ {sponsor.name} +
+
+ ) + )} +
+ + )} + {/* moralSponsor */} + {page?.value.sponsers?.moralSponsor && ( + <> +

حامی معنوی

+
+ {page.value.sponsers.moralSponsor.map((sponsor, index) => ( +
window.open(sponsor.link)} + > + {sponsor.name} +
+ {sponsor.name} +
+
+ ))} +
+ + )} +
+ )} + {/* gallery */} + {page?.value.gallery && ( + <> +

گالری

+
+ {page.value.gallery.map((image, index) => ( + gallery + ))} +
+ + )} + {/* Participants */} + {page?.value.Participants && ( + + )} +
+ +
+ ); +}; +export default IrnogPage; diff --git a/app/layout.tsx b/app/layout.tsx new file mode 100644 index 0000000..c18c728 --- /dev/null +++ b/app/layout.tsx @@ -0,0 +1,32 @@ +import StickyHeader from "@/components/Header/StickyHeader"; +import "./globals.css"; +import AnimatedWallpaper from "@/components/AnimatedWallpaper/AnimatedWallpaper"; +import { ToastContainer } from "react-toastify"; +import Footer from "@/components/Footer/Footer"; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + + + {/* Animated Wallpaper Background */} +
+ +
+ {/* Header */} + + {/* Main Content */} +
{children}
+ {/* Footer */} +