-
Notifications
You must be signed in to change notification settings - Fork 4
feat(seo): add comprehensive SEO engine #37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # robots.txt — Citronics 2026 (cdgicitronics.in) | ||
| # Generated for optimal Google / Bing / Edge crawling | ||
|
|
||
| User-agent: * | ||
| Allow: / | ||
| Allow: /about | ||
| Allow: /events | ||
| Allow: /events/ | ||
| Allow: /gallery | ||
| Allow: /team | ||
| Allow: /register | ||
|
|
||
| # Exclude auth, transactional, and private pages from indexation | ||
| Disallow: /login | ||
| Disallow: /dashboard | ||
| Disallow: /tickets | ||
| Disallow: /api/ | ||
| Disallow: /401 | ||
| Disallow: /404 | ||
| Disallow: /500 | ||
|
|
||
| # Next.js internals — allow render-critical JS/CSS but block image optimizer | ||
| Disallow: /_next/ | ||
| Allow: /_next/static/ | ||
| Disallow: /_next/image | ||
|
|
||
| # Exclude admin routes | ||
| Disallow: /admin | ||
| Disallow: /admin/ | ||
|
|
||
| # Sitemap location | ||
| Sitemap: https://cdgicitronics.in/sitemap.xml | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| /** | ||
| * ┌──────────────────────────────────────────────────────────────────────────┐ | ||
| * │ SEOHead — Core <Head> Component │ | ||
| * │ │ | ||
| * │ Renders title, meta description, keywords, canonical URL, Open Graph, │ | ||
| * │ Twitter Card, and JSON-LD structured data. │ | ||
| * │ │ | ||
| * │ NOT imported directly in pages — wrapped by per-page components like │ | ||
| * │ HomeSEO, AboutSEO, etc. that pre-fill all props. │ | ||
| * └──────────────────────────────────────────────────────────────────────────┘ | ||
| */ | ||
| import Head from 'next/head' | ||
| import { SITE, buildCanonical } from './seo.config' | ||
|
|
||
| const SEOHead = ({ | ||
| title, | ||
| description, | ||
| keywords, | ||
| canonicalPath = '/', | ||
| ogType = 'website', | ||
| ogImage, | ||
| noIndex = false, | ||
| schemas = [], | ||
| }) => { | ||
| const pageTitle = title || SITE.name | ||
| const pageDescription = description || `${SITE.name} — ${SITE.tagline}.` | ||
| const canonical = buildCanonical(canonicalPath) | ||
|
|
||
| // Ensure OG image is absolute | ||
| const rawOgImage = ogImage || SITE.ogImage | ||
| const absoluteOgImage = rawOgImage.startsWith('http') | ||
| ? rawOgImage | ||
| : `${SITE.url}${rawOgImage.startsWith('/') ? rawOgImage : `/${rawOgImage}`}` | ||
|
|
||
| return ( | ||
| <Head> | ||
| {/* ── Title ──────────────────────────────────────────── */} | ||
| <title>{pageTitle}</title> | ||
|
|
||
| {/* ── Core meta — what crawlers and AI models read first */} | ||
| <meta name='description' content={pageDescription} /> | ||
| {keywords && <meta name='keywords' content={keywords} />} | ||
| <meta name='robots' content={noIndex ? 'noindex,nofollow' : 'index,follow,max-image-preview:large,max-snippet:-1,max-video-preview:-1'} /> | ||
| <meta name='googlebot' content={noIndex ? 'noindex,nofollow' : 'index,follow,max-image-preview:large,max-snippet:-1,max-video-preview:-1'} /> | ||
| <meta name='bingbot' content={noIndex ? 'noindex,nofollow' : 'index,follow'} /> | ||
|
|
||
| {/* ── Canonical URL ──────────────────────────────────── */} | ||
| <link rel='canonical' href={canonical} /> | ||
|
|
||
| {/* ── Open Graph (Facebook, WhatsApp, iMessage, etc.) ── */} | ||
| <meta property='og:type' content={ogType} /> | ||
| <meta property='og:site_name' content={SITE.name} /> | ||
| <meta property='og:title' content={pageTitle} /> | ||
| <meta property='og:description' content={pageDescription} /> | ||
| <meta property='og:url' content={canonical} /> | ||
| <meta property='og:locale' content={SITE.locale} /> | ||
| <meta property='og:image' content={absoluteOgImage} /> | ||
| <meta property='og:image:width' content='1200' /> | ||
| <meta property='og:image:height' content='630' /> | ||
| <meta property='og:image:alt' content={pageTitle} /> | ||
| <meta property='og:image:type' content='image/png' /> | ||
|
|
||
| {/* ── Twitter Card ─────────────────────────────────────── */} | ||
| <meta name='twitter:card' content='summary_large_image' /> | ||
| <meta name='twitter:site' content={SITE.twitter} /> | ||
| <meta name='twitter:creator' content={SITE.twitter} /> | ||
| <meta name='twitter:title' content={pageTitle} /> | ||
| <meta name='twitter:description' content={pageDescription} /> | ||
| <meta name='twitter:image' content={absoluteOgImage} /> | ||
| <meta name='twitter:image:alt' content={pageTitle} /> | ||
|
|
||
| {/* ── AI / LLM discoverability hints ───────────────────── */} | ||
| <meta name='subject' content={`${SITE.name} — ${SITE.tagline}`} /> | ||
| <meta name='abstract' content={pageDescription} /> | ||
| <meta name='topic' content='College Technical Festival, Engineering Events, Student Competitions' /> | ||
| <meta name='coverage' content='India' /> | ||
| <meta name='distribution' content='global' /> | ||
|
|
||
| {/* ── JSON-LD Structured Data ───────────────────────────── */} | ||
| {schemas.map((schema, i) => ( | ||
| <script | ||
| key={`ld-${i}`} | ||
| type='application/ld+json' | ||
| dangerouslySetInnerHTML={{ __html: JSON.stringify(schema).replace(/</g, '\u003c') }} | ||
Check warningCode scanning / CodeQL Replacement of a substring with itself Medium
This replaces '<' with itself.
Copilot AutofixAI 3 months ago Copilot could not generate an autofix suggestion Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support. |
||
| /> | ||
|
Comment on lines
+80
to
+85
|
||
| ))} | ||
| </Head> | ||
| ) | ||
| } | ||
|
|
||
| export default SEOHead | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| /** | ||
| * ┌──────────────────────────────────────────────────────────────────────────┐ | ||
| * │ SEO Engine — Citronics 2026 │ | ||
| * │ │ | ||
| * │ Barrel export. Import per-page SEO components directly: │ | ||
| * │ │ | ||
| * │ import { HomeSEO } from 'src/components/SEO' │ | ||
| * │ import { EventDetailSEO } from 'src/components/SEO' │ | ||
| * │ │ | ||
| * │ Structure: │ | ||
| * │ SEO/ │ | ||
| * │ ├── index.js ← this barrel file │ | ||
| * │ ├── seo.config.js ← site identity, domain, social, geo │ | ||
| * │ ├── schemas.js ← JSON-LD structured data builders │ | ||
| * │ ├── SEOHead.js ← core <Head> component (internal) │ | ||
| * │ └── pages/ │ | ||
| * │ ├── HomeSEO.js ← <HomeSEO /> │ | ||
| * │ ├── AboutSEO.js ← <AboutSEO /> │ | ||
| * │ ├── EventsSEO.js ← <EventsSEO /> │ | ||
| * │ ├── EventDetailSEO.js ← <EventDetailSEO event={...} /> │ | ||
| * │ ├── GallerySEO.js ← <GallerySEO /> │ | ||
| * │ ├── TeamSEO.js ← <TeamSEO /> │ | ||
| * │ ├── CartSEO.js ← <CartSEO /> │ | ||
| * │ ├── CheckoutSEO.js ← <CheckoutSEO /> │ | ||
| * │ ├── LoginSEO.js ← <LoginSEO /> │ | ||
| * │ └── RegisterSEO.js ← <RegisterSEO /> │ | ||
| * └──────────────────────────────────────────────────────────────────────────┘ | ||
| */ | ||
|
|
||
| // Per-page SEO components — one import, one JSX tag per page | ||
| export { default as HomeSEO } from './pages/HomeSEO' | ||
| export { default as AboutSEO } from './pages/AboutSEO' | ||
| export { default as EventsSEO } from './pages/EventsSEO' | ||
| export { default as EventDetailSEO } from './pages/EventDetailSEO' | ||
| export { default as GallerySEO } from './pages/GallerySEO' | ||
| export { default as TeamSEO } from './pages/TeamSEO' | ||
| export { default as CartSEO } from './pages/CartSEO' | ||
| export { default as CheckoutSEO } from './pages/CheckoutSEO' | ||
| export { default as LoginSEO } from './pages/LoginSEO' | ||
| export { default as RegisterSEO } from './pages/RegisterSEO' | ||
| export { default as TicketsSEO } from './pages/TicketsSEO' | ||
| export { default as TicketVerifySEO } from './pages/TicketVerifySEO' | ||
| export { default as PaymentStatusSEO } from './pages/PaymentStatusSEO' | ||
|
|
||
| // Low-level exports (for advanced use / sitemap / events/[id] getServerSideProps) | ||
| export { SITE, buildCanonical } from './seo.config' | ||
| export { eventSchema } from './schemas' |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| /** | ||
| * AboutSEO — drop-in SEO for /about | ||
| * | ||
| * Schemas: Organization · festEvent · Breadcrumb · FAQ | ||
| * Target queries: "about Citronics", "CDGI fest info", "Citronics 2026 details" | ||
| */ | ||
| import SEOHead from '../SEOHead' | ||
| import { | ||
| organizationSchema, | ||
| festEventSchema, | ||
| breadcrumbSchema, | ||
| faqSchema, | ||
| } from '../schemas' | ||
|
|
||
| const ABOUT_FAQS = [ | ||
| { | ||
| question: 'What is Citronics 2026?', | ||
| answer: 'Citronics 2026 is the flagship annual techno-management fest of Chameli Devi Group of Institutions (CDGI), Indore. It features 35+ competitions across AI, robotics, coding, management, and cultural events with 5000+ participants from colleges all over India.', | ||
| }, | ||
| { | ||
| question: 'When and where is Citronics 2026 held?', | ||
| answer: 'Citronics 2026 takes place from April 7 to April 9, 2026 at the CDGI campus on Airport Road, Indore, Madhya Pradesh, India.', | ||
| }, | ||
| { | ||
| question: 'How can I register for Citronics 2026?', | ||
| answer: 'Visit cdgicitronics.in, create a free account, browse all 35+ events, and register for the competitions you want to participate in. You can purchase tickets directly through the website.', | ||
| }, | ||
| { | ||
| question: 'Is Citronics 2026 open to students from other colleges?', | ||
| answer: 'Yes, Citronics is a national-level fest open to students from all colleges and universities across India. Students from engineering, management, design, and other disciplines are welcome.', | ||
| }, | ||
| { | ||
| question: 'What kind of events does Citronics have?', | ||
| answer: 'Citronics features technical events (AI/ML challenges, robotics, hackathons, coding battles), management case studies, cultural performances, debates, quizzes, workshops, keynote sessions, and more across 14+ departments.', | ||
| }, | ||
| ] | ||
|
|
||
| const AboutSEO = () => ( | ||
| <SEOHead | ||
| title='About Citronics 2026 — CDGI Flagship Tech Fest | 35+ Events · 5000+ Participants · 3 Days' | ||
| description='Citronics is the annual techno-management fest of Chameli Devi Group of Institutions (CDGI), Indore. 35+ technical and cultural competitions, 5000+ student participants, 14+ departments, keynotes, workshops, and 3 packed days of innovation — April 7–9, 2026.' | ||
| keywords='about Citronics 2026, CDGI annual fest, Citronics 2026, Citronics 2k26, CDGI tech fest 2026, Chameli Devi Group of Institutions, CDGI Indore, Central India tech fest, Indore technical festival, CDGI departments, tech fest 3 days, Central India biggest college fest, what is Citronics, CDGI fest information, engineering fest MP' | ||
| canonicalPath='/about' | ||
| schemas={[ | ||
| organizationSchema(), | ||
| festEventSchema(), | ||
| breadcrumbSchema([ | ||
| { name: 'Home', path: '/' }, | ||
| { name: 'About Citronics 2026', path: '/about' }, | ||
| ]), | ||
| faqSchema(ABOUT_FAQS), | ||
| ]} | ||
| /> | ||
| ) | ||
|
|
||
| export default AboutSEO |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| /** | ||
| * CartSEO — SEO for /cart (noindex — transactional page) | ||
| */ | ||
| import SEOHead from '../SEOHead' | ||
|
|
||
| const CartSEO = () => ( | ||
| <SEOHead | ||
| title='Cart | Citronics 2026' | ||
| description='Review your selected event tickets for Citronics 2026 before proceeding to secure checkout.' | ||
| canonicalPath='/cart' | ||
| noIndex | ||
| /> | ||
| ) | ||
|
|
||
| export default CartSEO |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| /** | ||
| * CheckoutSEO — SEO for /checkout (noindex — transactional page) | ||
| */ | ||
| import SEOHead from '../SEOHead' | ||
|
|
||
| const CheckoutSEO = () => ( | ||
| <SEOHead | ||
| title='Checkout | Citronics 2026' | ||
| description='Complete your registration and ticket purchase for Citronics 2026 events at CDGI, Indore.' | ||
| canonicalPath='/checkout' | ||
| noIndex | ||
| /> | ||
| ) | ||
|
|
||
| export default CheckoutSEO |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| /** | ||
| * EventDetailSEO — dynamic SEO for /events/[id] | ||
| * | ||
| * Accepts an event object (from getServerSideProps) and generates | ||
| * title, description, keywords, and JSON-LD dynamically. | ||
| * | ||
| * Schemas: Event (single) · Breadcrumb | ||
| */ | ||
| import SEOHead from '../SEOHead' | ||
| import { SITE } from '../seo.config' | ||
| import { eventSchema, breadcrumbSchema } from '../schemas' | ||
|
|
||
| /** | ||
| * @param {{ event: object|null }} props | ||
| * event — serialized event row from getServerSideProps (can be null) | ||
| */ | ||
| const EventDetailSEO = ({ event }) => { | ||
| if (!event) { | ||
| return ( | ||
| <SEOHead | ||
| title='Event | Citronics 2026 — CDGI Tech Fest' | ||
| description='View event details, timings, venue, and registration info for this competition at Citronics 2026, CDGI Indore.' | ||
| canonicalPath='/events' | ||
| noIndex | ||
| /> | ||
| ) | ||
| } | ||
|
|
||
| const { id, name, tagline, description, venue, department_name, ticket_price, banner_url } = event | ||
|
|
||
| const eventName = name || 'Event' | ||
| const dept = department_name ? ` · ${department_name}` : '' | ||
| const priceTag = ticket_price != null && ticket_price > 0 ? ` | ₹${ticket_price}` : ' | Free Entry' | ||
|
|
||
| // Build a natural description — crawlers and AI models prefer complete sentences | ||
| const rawDesc = tagline || description || '' | ||
| const pageDesc = rawDesc | ||
| ? `${rawDesc.slice(0, 140).trim()}${rawDesc.length > 140 ? '…' : ''} — at Citronics 2026, CDGI Indore.` | ||
| : `${eventName} at Citronics 2026 — compete, collaborate and win at ${SITE.college}, Indore. ${department_name ? `Organised by ${department_name}.` : ''} April 7–9, 2026.` | ||
|
|
||
| return ( | ||
| <SEOHead | ||
| title={`${eventName}${dept} | Citronics 2026 — CDGI Tech Fest${priceTag}`} | ||
| description={pageDesc.slice(0, 160)} | ||
| keywords={`${eventName}, ${department_name || 'CDGI'}, Citronics 2026 event, CDGI competition, ${venue || 'Indore'}, college tech fest event, register ${eventName}, Citronics 2k26`} | ||
| canonicalPath={`/events/${id}`} | ||
| ogType='article' | ||
| ogImage={banner_url || undefined} | ||
| schemas={[ | ||
| eventSchema(event), | ||
| breadcrumbSchema([ | ||
| { name: 'Home', path: '/' }, | ||
| { name: 'Events', path: '/events' }, | ||
| { name: eventName, path: `/events/${id}` }, | ||
| ]), | ||
| ]} | ||
| /> | ||
| ) | ||
| } | ||
|
|
||
| export default EventDetailSEO |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| /** | ||
| * EventsSEO — drop-in SEO for /events (listing page) | ||
| * | ||
| * Schemas: Organization · Breadcrumb | ||
| * Target queries: "Citronics events", "CDGI competitions 2026", "tech fest events Indore" | ||
| */ | ||
| import SEOHead from '../SEOHead' | ||
| import { organizationSchema, breadcrumbSchema } from '../schemas' | ||
|
|
||
| const EventsSEO = () => ( | ||
| <SEOHead | ||
| title='Events & Competitions | Citronics 2026 — CDGI Tech Fest Indore' | ||
| description='Explore 35+ competitive events at Citronics 2026: AI/ML challenges, robotics, coding hackathons, management case studies, cultural performances, debates, quizzes, and workshops. CDGI, Indore — April 7–9, 2026. Filter by category and register online.' | ||
| keywords='events Citronics 2026, CDGI competitions 2026, technical events Indore, robotics competition, coding competition, hackathon CDGI, AI ML challenge 2026, management case study, cultural fest events, debate competition college, college tech fest events, national level technical fest events, hackathon Indore 2026, Citronics 2k26 events, CDGI event list' | ||
| canonicalPath='/events' | ||
| schemas={[ | ||
| organizationSchema(), | ||
| breadcrumbSchema([ | ||
| { name: 'Home', path: '/' }, | ||
| { name: 'Events & Competitions', path: '/events' }, | ||
| ]), | ||
| ]} | ||
| /> | ||
| ) | ||
|
|
||
| export default EventsSEO |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| /** | ||
| * GallerySEO — drop-in SEO for /gallery | ||
| * | ||
| * Schemas: ImageGallery · Breadcrumb | ||
| * Target queries: "Citronics photos", "CDGI fest gallery", "tech fest highlights" | ||
| */ | ||
| import SEOHead from '../SEOHead' | ||
| import { imageGallerySchema, breadcrumbSchema } from '../schemas' | ||
|
|
||
| const GallerySEO = () => ( | ||
| <SEOHead | ||
| title='Gallery — Citronics 2026 | CDGI Tech Fest Photos, Highlights & Moments' | ||
| description="Browse photos and highlights from Citronics — CDGI annual tech fest in Indore. Explore event moments, cultural performances, workshops, competition finals, campus life, and behind-the-scenes captures from one of Central India's biggest college festivals." | ||
| keywords='Citronics gallery, CDGI fest photos, tech fest highlights, Citronics 2026 images, college fest moments 2026, CDGI campus photos, cultural fest Indore pictures, competition highlights, behind the scenes tech fest, Citronics 2k26 gallery' | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| canonicalPath='/gallery' | ||
| schemas={[ | ||
| imageGallerySchema(), | ||
| breadcrumbSchema([ | ||
| { name: 'Home', path: '/' }, | ||
| { name: 'Gallery', path: '/gallery' }, | ||
| ]), | ||
| ]} | ||
| /> | ||
| ) | ||
|
|
||
| export default GallerySEO | ||
Uh oh!
There was an error while loading. Please reload this page.