Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,22 @@
0% { background-position: 200% 0%; }
100% { background-position: -100% 0%; }
}
@keyframes pulse-glow {
0%, 100% {
box-shadow: 0 0 20px 0px rgba(255, 165, 0, 0.2);
transform: scale(1);
}
50% {
box-shadow: 0 0 40px 10px rgba(255, 165, 0, 0.4);
transform: scale(1.02);
}
}

.animate-pulse-glow {
border-radius: 9999px; /* Ensures the glow effect is rounded */
transition: box-shadow 0.5s ease-in-out, transform 0.5s ease-in-out;
animation: pulse-glow 4s infinite ease-in-out;
}

/* Custom Instrument Font Classes */
.instrument-sans {
Expand Down
120 changes: 15 additions & 105 deletions app/hacktoberfest/page.tsx
Original file line number Diff line number Diff line change
@@ -1,120 +1,30 @@
import { Badge } from "@/components/ui/badge";
import { CleanCountdown } from "@/components/utils/clean-countdown";
import { BookOpen, Bug } from "lucide-react";
import { Icons } from "@/components/utils/icons";
import { AuroraText } from "@/components/ui/aurora-text";
import HacktoberfestClientContent from "@/components/hacktoberfest-client-content";

export default function HacktoberfestPage() {
// Determine the relevant Hacktoberfest year dynamically
const now = new Date();
const currentYear = now.getFullYear();
// If we're in October, use current year; if before October, use current year; if after October, use next year
const eventYear = now.getMonth() === 9
? currentYear
: (now.getMonth() > 9 ? currentYear + 1 : currentYear);

const eventYear = 2025;
const start = new Date(`${eventYear}-10-01T00:00:00`);
const end = new Date(`${eventYear}-10-31T23:59:59`);
const active = now >= start && now <= end;
const active = true;
const hacktoberfestEnd = end;

return (
<div className="bg-background relative overflow-x-hidden">
{/* Decorative radial gradient background */}
<div className="pointer-events-none absolute inset-0 -z-10">
<div className="relative overflow-x-hidden min-h-screen">
{/* Dedicated div for background color */}
<div className="absolute inset-0 -z-50 bg-background" />

{/* Static radial gradients */}
<div className="pointer-events-none absolute inset-0 -z-30">
<div className="absolute left-1/2 top-10 -translate-x-1/2 h-56 w-56 rounded-full bg-orange-400/20 blur-3xl" />
<div className="absolute right-10 top-20 h-40 w-40 rounded-full bg-purple-500/10 blur-3xl" />
<div className="absolute left-10 bottom-10 h-44 w-44 rounded-full bg-amber-300/10 blur-3xl" />
</div>
{/* Page Title Section */}
<div className={active ? "pt-10 pb-16" : "pt-10 pb-12"}>
<div className="max-w-5xl mx-auto px-6 lg:px-10 text-center">
<div className="flex items-center justify-center gap-3 mb-6">
<span role="img" aria-label="pumpkin" className="text-2xl">🎃</span>
<Badge
variant="secondary"
className="px-3 py-1 text-orange-600 bg-orange-100 dark:bg-orange-900/30 dark:text-orange-400 shadow-sm"
>
{active ? "Hacktoberfest is Live!" : "Coming Soon"}
</Badge>
<span role="img" aria-label="pumpkin" className="text-2xl">🎃</span>
</div>

<h1 className="text-foreground text-4xl sm:text-5xl md:text-6xl font-extrabold tracking-tight leading-[1.15] mb-4">
{/* Join Helixque for <span className="text-orange-500">Hacktoberfest</span> */}
Join Helixque for <AuroraText>Hacktoberfest</AuroraText>
</h1>

<p className="text-muted-foreground text-base tracking-tight mt-6 max-w-2xl mx-auto sm:text-lg">
{active
? (
<>
<span className="block">Join us in celebrating open source!</span>
<span className="block">Contribute to our projects and be part of the Hacktoberfest community.</span>
</>
)
: "We understand your eagerness to contribute and we're thankful for that, but you'll need to wait until the event begins."
}
</p>
</div>
</div>

{/* Countdown Timer */}
{active && (
<div className="mb-16 flex justify-center">
<CleanCountdown
endDate={hacktoberfestEnd}
label={`Time left in Hacktoberfest ${eventYear}`}
expiredMessage={`🎉 Hacktoberfest ${eventYear} has ended! 🎉`}
/>
</div>
)}

{/* Content Section */}
<div className="max-w-5xl mx-auto px-6 mb-10 lg:px-10 text-center">
<p className="text-lg text-muted-foreground mb-8">
{active
? "Ready to contribute? Check out our repositories and start making a difference!"
: "Meanwhile, explore our work and get ready to contribute."
}
</p>

<div className="flex flex-wrap items-center justify-center gap-3 sm:gap-4">
<a
href="https://github.com/orgs/HXQLabs/repositories"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm sm:text-[13.5px] hover:bg-muted transition-colors bg-gradient-to-b from-background to-muted/30"
>
<Icons.github className="w-4 h-4" />
Browse our repositories
</a>

<a
href="https://github.com/HXQLabs/HelixQue/blob/main/CONTRIBUTING.md"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm sm:text-[13.5px] hover:bg-muted transition-colors bg-gradient-to-b from-background to-muted/30"
>
<BookOpen className="w-4 h-4" />
See contributing guidelines
</a>

<a
href="https://github.com/search?q=org%3AHXQLabs+state%3Aopen&type=Issues"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm sm:text-[13.5px] hover:bg-muted transition-colors bg-gradient-to-b from-background to-muted/30"
>
<Bug className="w-4 h-4" />
Find issues
</a>
</div>

<p className="mt-6 text-sm sm:text-base text-muted-foreground">
Gear up your issues, sharpen those PRs, and let the commits roll in! ⚡️
</p>
</div>
{/* Client content with animations */}
<HacktoberfestClientContent
active={active}
eventYear={eventYear}
hacktoberfestEnd={hacktoberfestEnd}
/>
</div>
);
}
70 changes: 70 additions & 0 deletions components/effects/falling-leaves-3d.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"use client";

import React, { Suspense, useMemo } from 'react';
import { Canvas } from '@react-three/fiber';
import { Environment } from '@react-three/drei';
import { usePrefersReducedMotion } from '@/hooks/use-prefers-reduced-motion';
import { Leaf3D } from './leaf-3d';

interface FallingLeaves3DProps {
count?: number;
}

export function FallingLeaves3D({ count = 50 }: FallingLeaves3DProps) {
// All hooks must be called at the top level, before any returns.
const prefersReducedMotion = usePrefersReducedMotion();

const leaves = useMemo(() => {
// ✨ FIX: Check if `window` exists to prevent errors during server-side rendering.
const effectiveWidth = typeof window !== "undefined" ? window.innerWidth : 1024;
const numLeaves = effectiveWidth < 768 ? Math.floor(count / 2) : count;

return Array.from({ length: numLeaves }).map((_, i) => ({
id: i,
initialPosition: [
Math.random() * 20 - 10,
Math.random() * 20 + 5,
Math.random() * 10 - 5
] as [number, number, number],
speed: 0.5 + Math.random() * 0.5,
rotationSpeed: 0.5 + Math.random() * 0.5,
windForce: 0.1 + Math.random() * 0.2,
}));
}, [count]);

// ✨ FIX: The `if` check is now moved *after* all hooks have been called.
if (prefersReducedMotion) {
return null;
}

return (
<div className="absolute inset-0 -z-10">
<Canvas
camera={{ position: [0, 0, 15], fov: 75 }}
style={{ background: 'transparent' }}
// ✨ FIX: Added `dpr` prop for performance optimization on high-res screens.
dpr={[1, 2]}
gl={{ antialias: true, powerPreference: "high-performance" }}
>
<ambientLight intensity={0.5} />
<spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} />
<pointLight position={[-10, -10, -10]} />
<Environment preset="forest" />

<Suspense fallback={null}>
{leaves.map((leaf) => (
<Leaf3D
key={leaf.id}
initialPosition={leaf.initialPosition}
speed={leaf.speed}
rotationSpeed={leaf.rotationSpeed}
windForce={leaf.windForce}
ground={-10}
boundary={{ x: [-15, 15], z: [-10, 10] }}
/>
))}
</Suspense>
</Canvas>
</div>
);
}
112 changes: 112 additions & 0 deletions components/effects/festive-background.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
"use client";

import { useEffect, useMemo, useState, useCallback } from "react";
import Particles from "react-tsparticles"; // ✨ FIX: Removed the incorrect named import here
import { loadSlim } from "tsparticles-slim";
import { type Container, type ISourceOptions, initParticlesEngine } from "@tsparticles/engine"; // ✨ FIX: This is the ONLY place to import the engine
import { usePrefersReducedMotion } from "@/hooks/use-prefers-reduced-motion";

export function FestiveBackground() {
const [init, setInit] = useState(false);
const prefersReducedMotion = usePrefersReducedMotion();

// This useEffect should only run once on mount to initialize the engine
useEffect(() => {
initParticlesEngine(async (engine) => {
await loadSlim(engine);
}).then(() => {
setInit(true);
});
}, []);

const particlesLoaded = useCallback(async (container?: Container) => {
// Optional: console.log("Particles loaded", container);
}, []);

const options: ISourceOptions = useMemo(
() => ({
background: {
color: {
value: "transparent",
},
},
fpsLimit: 60,
particles: {
number: {
value: prefersReducedMotion ? 0 : 60,
density: {
enable: true,
value_area: 800,
},
},
color: {
value: ["#ff7f50", "#ff6347", "#ffa500", "#ffffff"],
},
shape: {
type: "circle",
},
opacity: {
value: { min: 0.3, max: 0.8 },
animation: {
enable: true,
speed: 1,
sync: false,
},
},
size: {
value: { min: 1, max: 4 },
},
move: {
enable: !prefersReducedMotion, // Disable movement if reduced motion is on
direction: "bottom",
speed: 2,
straight: true,
outModes: {
default: "out",
},
},
},
interactivity: {
events: {
onHover: {
enable: !prefersReducedMotion,
mode: "trail",
},
},
modes: {
trail: {
quantity: 3,
delay: 0.1,
particles: {
size: {
value: { min: 1, max: 3 },
animation: {
enable: true,
speed: 20,
sync: true,
startValue: "min",
destroy: "max",
},
},
},
},
},
},
detectRetina: true,
}),
[prefersReducedMotion]
);

if (init) {
return (
<Particles
id="tsparticles"
particlesLoaded={particlesLoaded}
options={options}
className="absolute inset-0 -z-10"
/>
);
}

return null;
}
Loading