Skip to content
Merged
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
Binary file modified logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/DevPath-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/logo-circle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 39 additions & 1 deletion src/app/wiki/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import { useState } from 'react';
import { useState, useEffect } from 'react';
import { Search, ChevronRight, Book, Code, FileText, HelpCircle, ThumbsUp, ThumbsDown, Github, Users, MapPin, MessageCircle, Calendar } from 'lucide-react';
import Button from '@/components/ui/Button';
import styles from './Wiki.module.css';
Expand Down Expand Up @@ -42,6 +42,44 @@ export default function WikiPage() {
const [activeArticle, setActiveArticle] = useState("intro");
const [searchQuery, setSearchQuery] = useState("");

useEffect(() => {
const articleBody = document.querySelector(`.${styles.articleBody}`);
if (!articleBody) return;
const preElements = articleBody.querySelectorAll('pre');

preElements.forEach((pre) => {
if (pre.parentElement?.classList.contains('code-wrapper')) return;

const wrapper = document.createElement('div');
wrapper.className = 'code-wrapper relative group w-full';

pre.parentNode?.insertBefore(wrapper, pre);
wrapper.appendChild(pre);
Comment thread
Aditya948351 marked this conversation as resolved.

const button = document.createElement('button');
button.className = 'absolute right-3 top-3 px-2 py-1 text-xs font-semibold bg-zinc-900/80 text-zinc-300 rounded border border-white/10 opacity-0 group-hover:opacity-100 hover:bg-zinc-800 hover:text-white transition-all duration-200 shadow-md cursor-pointer backdrop-blur-sm';
Comment thread
Aditya948351 marked this conversation as resolved.
button.innerHTML = 'Copy';
button.type = 'button';

button.addEventListener('click', async () => {
const codeText = pre.textContent || '';
try {
await navigator.clipboard.writeText(codeText);
button.innerHTML = 'Copied!';
button.className = 'absolute right-3 top-3 px-2 py-1 text-xs font-semibold bg-emerald-600 text-white rounded border border-emerald-500 transition-all duration-200 shadow-md';
setTimeout(() => {
button.innerHTML = 'Copy';
button.className = 'absolute right-3 top-3 px-2 py-1 text-xs font-semibold bg-zinc-900/80 text-zinc-300 rounded border border-white/10 opacity-0 group-hover:opacity-100 hover:bg-zinc-800 hover:text-white transition-all duration-200 shadow-md cursor-pointer backdrop-blur-sm';
}, 2000);
} catch (err) {
console.error('Failed to copy text: ', err);
}
});

wrapper.appendChild(button);
});
}, [activeArticle]);

return (
<div className={styles.container}>
<aside className={styles.sidebar}>
Expand Down
Binary file modified src/assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
192 changes: 139 additions & 53 deletions src/components/resources/RoadmapModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { X, CheckCircle, BookOpen, Code, Database, Brain, Rocket } from 'lucide-react';
import { X, CheckCircle, BookOpen, Code, Database, Brain, Rocket, ChevronLeft, ChevronRight, Check } from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
import { createPortal } from 'react-dom';
import { useState, useEffect } from 'react';
import { useGamification } from '@/context/GamificationContext';

interface RoadmapModalProps {
isOpen: boolean;
Expand All @@ -18,97 +21,182 @@ interface RoadmapModalProps {
} | null;
}

import { createPortal } from 'react-dom';
import { useState, useEffect } from 'react';

export function RoadmapModal({ isOpen, onClose, roadmap }: RoadmapModalProps) {
const [mounted, setMounted] = useState(false);
const [currentPhaseIndex, setCurrentPhaseIndex] = useState(0);
const { addXp } = useGamification();

useEffect(() => {
setMounted(true);
return () => setMounted(false);
}, []);

// Reset current step when modal opens
useEffect(() => {
if (isOpen) {
setCurrentPhaseIndex(0);
}
}, [isOpen]);

if (!isOpen || !roadmap || !mounted) return null;

const activePhase = roadmap.phases[currentPhaseIndex];

const handleNext = () => {
if (currentPhaseIndex < roadmap.phases.length - 1) {
setCurrentPhaseIndex(prev => prev + 1);
}
};

const handleBack = () => {
if (currentPhaseIndex > 0) {
setCurrentPhaseIndex(prev => prev - 1);
}
};

const handleComplete = () => {
try {
addXp(500, `Completed the ${roadmap.title} Pathway!`);
Comment thread
Aditya948351 marked this conversation as resolved.
} catch (err) {
console.error("Failed to add XP: ", err);
}
onClose();
};

return createPortal(
<AnimatePresence>
<div className="fixed inset-0 z-[2000] flex items-center justify-center p-4 bg-black/80 backdrop-blur-sm">
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
className="bg-card w-full max-w-4xl max-h-[90vh] overflow-y-auto rounded-2xl border border-border shadow-2xl custom-scrollbar"
className="bg-card w-full max-w-4xl max-h-[90vh] overflow-y-auto rounded-2xl border border-border shadow-2xl custom-scrollbar flex flex-col"
>
{/* Header */}
<div className="sticky top-0 z-10 flex items-center justify-between p-6 border-b border-border bg-card/95 backdrop-blur">
<div>
<h2 className="text-2xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-purple-400">
{roadmap.title}
</h2>
<p className="text-sm text-muted-foreground mt-1">Placement Focused Roadmap</p>
<p className="text-sm text-muted-foreground mt-1">Interactive Pathway Tutorial</p>
</div>
<button
onClick={onClose}
className="p-2 hover:bg-muted rounded-full transition-colors text-muted-foreground hover:text-foreground"
aria-label="Close modal"
>
<X size={24} />
</button>
</div>

{/* Content */}
<div className="p-6 space-y-8">
{roadmap.phases.map((phase, index) => (
<div key={index} className="relative pl-8 border-l-2 border-border last:border-l-0 pb-8 last:pb-0">
{/* Phase Marker */}
<div className="absolute -left-[11px] top-0 w-5 h-5 rounded-full bg-background border-2 border-primary flex items-center justify-center">
<div className="w-2 h-2 rounded-full bg-primary" />
</div>
{/* Progress Indicator Steps Bar */}
<div className="px-6 pt-6">
<div className="flex items-center justify-between bg-muted/20 p-4 rounded-xl border border-border/50 overflow-x-auto scrollbar-hide">
<div className="flex items-center gap-2 w-full justify-between min-w-[300px]">
{roadmap.phases.map((phase, idx) => (
<div key={idx} className="flex items-center gap-2 flex-grow last:flex-grow-0">
<button
onClick={() => setCurrentPhaseIndex(idx)}
className={`w-8 h-8 rounded-full flex items-center justify-center text-xs font-bold transition-all ${
idx === currentPhaseIndex
? 'bg-primary text-white scale-110 shadow-lg shadow-primary/25'
: idx < currentPhaseIndex
? 'bg-primary/20 text-primary border border-primary/30'
: 'bg-muted text-muted-foreground border border-border'
}`}
title={phase.title}
Comment thread
Aditya948351 marked this conversation as resolved.
aria-label={`Step ${idx + 1}: ${phase.title}`}
aria-current={idx === currentPhaseIndex ? 'step' : undefined}
>
{idx < currentPhaseIndex ? <Check size={14} /> : idx + 1}
</button>
{idx < roadmap.phases.length - 1 && (
<div className={`h-[2px] flex-grow rounded ${
idx < currentPhaseIndex ? 'bg-primary' : 'bg-muted'
}`} />
)}
</div>
))}
</div>
</div>
</div>

<div className="mb-6">
<h3 className="text-xl font-bold flex items-center gap-2 text-foreground">
{phase.icon}
{phase.title}
</h3>
<span className="text-xs font-mono text-primary bg-primary/10 px-2 py-1 rounded mt-2 inline-block">
{phase.duration}
</span>
{/* Content */}
<div className="p-6 flex-grow">
<AnimatePresence mode="wait">
<motion.div
key={currentPhaseIndex}
initial={{ opacity: 0, x: 10 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -10 }}
transition={{ duration: 0.2 }}
className="space-y-6 min-h-[300px]"
>
<div className="mb-6 flex flex-col md:flex-row md:items-center justify-between gap-4">
<div>
<h3 className="text-2xl font-bold flex items-center gap-2 text-foreground">
{activePhase.icon}
{activePhase.title}
</h3>
<span className="text-xs font-mono text-primary bg-primary/10 px-3 py-1 rounded-full mt-2 inline-block">
{activePhase.duration}
</span>
</div>
<div className="text-sm text-muted-foreground font-mono bg-muted/40 px-3 py-1.5 rounded-lg border border-border/50 select-none">
Step {currentPhaseIndex + 1} of {roadmap.phases.length}
</div>
</div>

<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{phase.items.map((item, i) => (
<div key={i} className="bg-muted/30 rounded-xl p-4 border border-border/50 hover:border-primary/30 transition-colors">
<h4 className="font-semibold text-foreground mb-3 flex items-start gap-2">
<CheckCircle size={16} className="text-green-500 mt-1 shrink-0" />
{item.subtitle}
</h4>
<ul className="space-y-2">
{item.points.map((point, j) => (
<li key={j} className="text-sm text-muted-foreground pl-6 relative before:content-['•'] before:absolute before:left-2 before:text-muted-foreground/50">
{point}
</li>
))}
</ul>
{activePhase.items.map((item, i) => (
<div key={i} className="bg-muted/30 rounded-xl p-5 border border-border/50 hover:border-primary/30 transition-colors flex flex-col justify-between">
<div>
<h4 className="font-semibold text-foreground mb-3 flex items-start gap-2">
<CheckCircle size={16} className="text-green-500 mt-1 shrink-0" />
{item.subtitle}
</h4>
<ul className="space-y-2">
{item.points.map((point, j) => (
<li key={j} className="text-sm text-muted-foreground pl-6 relative before:content-['•'] before:absolute before:left-2 before:text-muted-foreground/50 leading-relaxed">
{point}
</li>
))}
</ul>
</div>
</div>
))}
</div>
</div>
))}
</motion.div>
</AnimatePresence>

{/* Final CTA */}
<div className="mt-8 p-6 bg-gradient-to-r from-primary/10 to-purple-500/10 rounded-xl border border-primary/20 text-center">
<h3 className="text-lg font-bold mb-2">Need Expert Guidance?</h3>
<p className="text-muted-foreground text-sm mb-4">
Join the Coders Circle Community on WhatsApp for mentorship and doubts.
</p>
<a
href="https://chat.whatsapp.com/your-group-link" // Replace with actual link if available
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2 px-6 py-2 bg-green-600 hover:bg-green-700 text-white rounded-full font-medium transition-colors"
>
<MessageSquare size={18} /> Join Community
</a>
{/* Navigation Actions */}
<div className="flex items-center justify-between pt-6 border-t border-border mt-8">
{currentPhaseIndex > 0 ? (
<button
onClick={handleBack}
className="flex items-center gap-2 px-5 py-2.5 bg-muted hover:bg-muted/80 text-foreground text-sm font-semibold rounded-xl transition-all border border-border cursor-pointer select-none"
>
<ChevronLeft size={16} /> Previous Step
</button>
) : (
<div />
)}

{currentPhaseIndex < roadmap.phases.length - 1 ? (
<button
onClick={handleNext}
className="flex items-center gap-2 px-6 py-2.5 bg-primary hover:bg-primary/95 text-white text-sm font-semibold rounded-xl transition-all shadow-md hover:shadow-lg shadow-primary/20 cursor-pointer select-none"
>
Next Step <ChevronRight size={16} />
</button>
) : (
<button
onClick={handleComplete}
className="flex items-center gap-2 px-6 py-2.5 bg-emerald-600 hover:bg-emerald-700 text-white text-sm font-semibold rounded-xl transition-all shadow-md hover:shadow-lg shadow-emerald-500/20 cursor-pointer select-none"
>
Complete Pathway <Check size={16} />
</button>
)}
</div>
</div>
</motion.div>
Expand All @@ -117,5 +205,3 @@ export function RoadmapModal({ isOpen, onClose, roadmap }: RoadmapModalProps) {
document.body
);
}

import { MessageSquare } from 'lucide-react';
22 changes: 22 additions & 0 deletions src/data/wikiContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,20 @@ export const wikiContent: Record<string, WikiArticle> = {
<li>Node.js & Express</li>
<li>MongoDB & Mongoose</li>
</ul>
<h2>Sample Component</h2>
<p>Here is a basic React functional counter component using state hooks:</p>
<pre className="bg-zinc-950 text-zinc-200 p-4 rounded-xl font-mono text-sm overflow-x-auto my-4 block border border-zinc-800">
{`import React, { useState } from 'react';

export default function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}`}
</pre>
</>
)
},
Expand Down Expand Up @@ -272,6 +286,14 @@ export const wikiContent: Record<string, WikiArticle> = {
<li>Push to the branch.</li>
<li>Open a Pull Request.</li>
</ol>
<h2>Quick Commands</h2>
<p>Run these terminal commands to initialize your feature work:</p>
<pre className="bg-zinc-950 text-zinc-200 p-4 rounded-xl font-mono text-sm overflow-x-auto my-4 block border border-zinc-800">
{`git checkout -b feature/cool-new-feature
git add .
git commit -m "feat: implement extremely cool feature"
git push origin feature/cool-new-feature`}
</pre>
</>
)
},
Expand Down
Loading