| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>DevVision | Developer Dashboard</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| |
| .gradient-bg { |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| } |
| .code-editor { |
| background: #1e293b; |
| border-radius: 0.5rem; |
| box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); |
| } |
| .editor-header { |
| background: #0f172a; |
| border-top-left-radius: 0.5rem; |
| border-top-right-radius: 0.5rem; |
| } |
| .editor-dot { |
| width: 12px; |
| height: 12px; |
| border-radius: 50%; |
| display: inline-block; |
| margin-right: 6px; |
| } |
| .terminal { |
| background: #0f172a; |
| font-family: 'Courier New', monospace; |
| color: #4ade80; |
| } |
| .typing-effect::after { |
| content: '|'; |
| animation: blink 1s step-end infinite; |
| } |
| @keyframes blink { |
| from, to { opacity: 1; } |
| 50% { opacity: 0; } |
| } |
| .card-hover:hover { |
| transform: translateY(-5px); |
| box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); |
| } |
| .active-nav { |
| position: relative; |
| } |
| .active-nav::after { |
| content: ''; |
| position: absolute; |
| bottom: -8px; |
| left: 0; |
| width: 100%; |
| height: 2px; |
| background: white; |
| } |
| .mobile-menu { |
| max-height: 0; |
| overflow: hidden; |
| transition: max-height 0.3s ease-out; |
| } |
| .mobile-menu.open { |
| max-height: 500px; |
| } |
| .snippet-code { |
| background: #1e293b; |
| color: #e2e8f0; |
| font-family: 'Courier New', monospace; |
| border-radius: 0.5rem; |
| } |
| .community-post { |
| transition: transform 0.2s; |
| } |
| .community-post:hover { |
| transform: translateX(5px); |
| } |
| |
| .route-transition { |
| animation: fadeIn 0.3s ease-in-out; |
| } |
| @keyframes fadeIn { |
| from { opacity: 0; transform: translateY(10px); } |
| to { opacity: 1; transform: translateY(0); } |
| } |
| |
| ::-webkit-scrollbar { |
| width: 8px; |
| height: 8px; |
| } |
| ::-webkit-scrollbar-track { |
| background: #f1f1f1; |
| } |
| ::-webkit-scrollbar-thumb { |
| background: #888; |
| border-radius: 4px; |
| } |
| ::-webkit-scrollbar-thumb:hover { |
| background: #555; |
| } |
| </style> |
| </head> |
| <body class="bg-gray-100 font-sans antialiased"> |
| |
| <nav class="gradient-bg text-white shadow-lg"> |
| <div class="container mx-auto px-4 py-3 flex justify-between items-center"> |
| <div class="flex items-center space-x-2 cursor-pointer" onclick="navigate('dashboard')"> |
| <i class="fas fa-code text-2xl"></i> |
| <span class="text-xl font-bold">DevVision</span> |
| </div> |
| <div class="hidden md:flex space-x-6"> |
| <a href="#" class="hover:text-gray-200 transition active-nav" id="nav-dashboard" onclick="navigate('dashboard')">Dashboard</a> |
| <a href="#" class="hover:text-gray-200 transition" id="nav-projects" onclick="navigate('projects')">Projects</a> |
| <a href="#" class="hover:text-gray-200 transition" id="nav-snippets" onclick="navigate('snippets')">Snippets</a> |
| <a href="#" class="hover:text-gray-200 transition" id="nav-community" onclick="navigate('community')">Community</a> |
| </div> |
| <div class="flex items-center space-x-4"> |
| <button class="bg-white text-indigo-600 px-4 py-2 rounded-full font-medium hover:bg-gray-100 transition hidden md:block" onclick="showNewProjectModal()"> |
| <i class="fas fa-plus mr-2"></i> New Project |
| </button> |
| <div class="relative cursor-pointer" onclick="toggleProfileMenu()"> |
| <img src="https://randomuser.me/api/portraits/men/32.jpg" alt="Profile" class="w-10 h-10 rounded-full border-2 border-white"> |
| <span class="absolute bottom-0 right-0 w-3 h-3 bg-green-500 rounded-full border-2 border-white"></span> |
| <div id="profile-menu" class="hidden absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg z-10"> |
| <div class="py-1"> |
| <a href="#" class="block px-4 py-2 text-gray-800 hover:bg-gray-100" onclick="navigate('profile')">Profile</a> |
| <a href="#" class="block px-4 py-2 text-gray-800 hover:bg-gray-100" onclick="navigate('settings')">Settings</a> |
| <a href="#" class="block px-4 py-2 text-gray-800 hover:bg-gray-100" onclick="logout()">Sign out</a> |
| </div> |
| </div> |
| </div> |
| <button class="md:hidden text-white" onclick="toggleMobileMenu()"> |
| <i class="fas fa-bars text-xl"></i> |
| </button> |
| </div> |
| </div> |
| |
| <div id="mobile-menu" class="mobile-menu md:hidden gradient-bg px-4"> |
| <div class="py-2 space-y-3"> |
| <a href="#" class="block py-2 text-white hover:text-gray-200" onclick="navigate('dashboard')">Dashboard</a> |
| <a href="#" class="block py-2 text-white hover:text-gray-200" onclick="navigate('projects')">Projects</a> |
| <a href="#" class="block py-2 text-white hover:text-gray-200" onclick="navigate('snippets')">Snippets</a> |
| <a href="#" class="block py-2 text-white hover:text-gray-200" onclick="navigate('community')">Community</a> |
| <button class="w-full bg-white text-indigo-600 px-4 py-2 rounded-full font-medium hover:bg-gray-100 transition mt-2" onclick="showNewProjectModal()"> |
| <i class="fas fa-plus mr-2"></i> New Project |
| </button> |
| </div> |
| </div> |
| </nav> |
|
|
| |
| <div class="container mx-auto px-4 py-8"> |
| |
| <div id="dashboard-content" class="route-transition"> |
| |
| <div class="gradient-bg text-white rounded-xl p-6 mb-8 shadow-lg"> |
| <div class="flex flex-col md:flex-row justify-between items-start md:items-center"> |
| <div> |
| <h1 class="text-2xl md:text-3xl font-bold mb-2">Welcome back, Alex!</h1> |
| <p class="opacity-90">You have 3 active projects and 5 pending tasks. Let's make some progress today!</p> |
| </div> |
| <button class="mt-4 md:mt-0 bg-white text-indigo-600 px-6 py-2 rounded-full font-medium hover:bg-gray-100 transition flex items-center"> |
| <i class="fas fa-rocket mr-2"></i> Quick Start |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8"> |
| <div class="bg-white rounded-xl p-6 shadow-md transition duration-300 card-hover"> |
| <div class="flex justify-between items-center"> |
| <div> |
| <p class="text-gray-500">Projects</p> |
| <h3 class="text-2xl font-bold">12</h3> |
| </div> |
| <div class="bg-indigo-100 text-indigo-600 p-3 rounded-full"> |
| <i class="fas fa-folder-open text-xl"></i> |
| </div> |
| </div> |
| <div class="mt-4 pt-4 border-t border-gray-100"> |
| <span class="text-green-500 text-sm font-medium">+2 this week</span> |
| </div> |
| </div> |
| |
| <div class="bg-white rounded-xl p-6 shadow-md transition duration-300 card-hover"> |
| <div class="flex justify-between items-center"> |
| <div> |
| <p class="text-gray-500">Tasks</p> |
| <h3 class="text-2xl font-bold">24</h3> |
| </div> |
| <div class="bg-blue-100 text-blue-600 p-3 rounded-full"> |
| <i class="fas fa-tasks text-xl"></i> |
| </div> |
| </div> |
| <div class="mt-4 pt-4 border-t border-gray-100"> |
| <span class="text-yellow-500 text-sm font-medium">5 pending</span> |
| </div> |
| </div> |
| |
| <div class="bg-white rounded-xl p-6 shadow-md transition duration-300 card-hover"> |
| <div class="flex justify-between items-center"> |
| <div> |
| <p class="text-gray-500">Snippets</p> |
| <h3 class="text-2xl font-bold">47</h3> |
| </div> |
| <div class="bg-green-100 text-green-600 p-3 rounded-full"> |
| <i class="fas fa-code text-xl"></i> |
| </div> |
| </div> |
| <div class="mt-4 pt-4 border-t border-gray-100"> |
| <span class="text-green-500 text-sm font-medium">+8 this month</span> |
| </div> |
| </div> |
| |
| <div class="bg-white rounded-xl p-6 shadow-md transition duration-300 card-hover"> |
| <div class="flex justify-between items-center"> |
| <div> |
| <p class="text-gray-500">Streak</p> |
| <h3 class="text-2xl font-bold">18 days</h3> |
| </div> |
| <div class="bg-purple-100 text-purple-600 p-3 rounded-full"> |
| <i class="fas fa-fire text-xl"></i> |
| </div> |
| </div> |
| <div class="mt-4 pt-4 border-t border-gray-100"> |
| <span class="text-red-500 text-sm font-medium">Don't break it!</span> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-8"> |
| |
| <div class="lg:col-span-2 space-y-6"> |
| |
| <div class="code-editor p-0 rounded-xl overflow-hidden"> |
| <div class="editor-header px-4 py-3 flex items-center"> |
| <div class="flex space-x-2 mr-4"> |
| <span class="editor-dot bg-red-500"></span> |
| <span class="editor-dot bg-yellow-500"></span> |
| <span class="editor-dot bg-green-500"></span> |
| </div> |
| <div class="text-gray-300 text-sm">index.js</div> |
| </div> |
| <div class="p-4"> |
| <pre class="text-gray-300 font-mono text-sm overflow-x-auto"><code><span class="text-purple-400">import</span> React <span class="text-purple-400">from</span> <span class="text-yellow-300">'react'</span>; |
| <span class="text-purple-400">import</span> { useState } <span class="text-purple-400">from</span> <span class="text-yellow-300">'react'</span>; |
|
|
| <span class="text-purple-400">function</span> <span class="text-blue-400">Counter</span>() { |
| <span class="text-purple-400">const</span> [count, setCount] = useState(<span class="text-green-400">0</span>); |
|
|
| <span class="text-purple-400">return</span> ( |
| <div className=<span class="text-yellow-300">"p-4"</span>> |
| <p>You clicked {count} times</p> |
| <button |
| onClick={<span class="text-purple-400">()</span> <span class="text-purple-400">=></span> setCount(count + <span class="text-green-400">1</span>)} |
| className=<span class="text-yellow-300">"bg-blue-500 text-white px-4 py-2 rounded"</span> |
| > |
| Click me |
| </button> |
| </div> |
| ); |
| } |
|
|
| <span class="text-purple-400">export</span> <span class="text-purple-400">default</span> Counter;</code></pre> |
| </div> |
| </div> |
|
|
| |
| <div class="bg-white rounded-xl shadow-md p-6"> |
| <div class="flex justify-between items-center mb-6"> |
| <h2 class="text-xl font-bold">Recent Projects</h2> |
| <button class="text-indigo-600 hover:text-indigo-800 transition"> |
| <i class="fas fa-ellipsis-h"></i> |
| </button> |
| </div> |
| <div class="space-y-4"> |
| <div class="flex items-center p-3 hover:bg-gray-50 rounded-lg transition cursor-pointer" onclick="viewProject('ecommerce-dashboard')"> |
| <div class="bg-indigo-100 text-indigo-600 p-3 rounded-lg mr-4"> |
| <i class="fas fa-project-diagram"></i> |
| </div> |
| <div class="flex-1"> |
| <h4 class="font-medium">E-commerce Dashboard</h4> |
| <p class="text-gray-500 text-sm">React, Node.js, MongoDB</p> |
| </div> |
| <div class="text-gray-500 text-sm">Updated 2h ago</div> |
| <div class="ml-4"> |
| <i class="fas fa-chevron-right text-gray-400"></i> |
| </div> |
| </div> |
| |
| <div class="flex items-center p-3 hover:bg-gray-50 rounded-lg transition cursor-pointer" onclick="viewProject('fitness-app')"> |
| <div class="bg-blue-100 text-blue-600 p-3 rounded-lg mr-4"> |
| <i class="fas fa-mobile-alt"></i> |
| </div> |
| <div class="flex-1"> |
| <h4 class="font-medium">Fitness App</h4> |
| <p class="text-gray-500 text-sm">React Native, Firebase</p> |
| </div> |
| <div class="text-gray-500 text-sm">Updated yesterday</div> |
| <div class="ml-4"> |
| <i class="fas fa-chevron-right text-gray-400"></i> |
| </div> |
| </div> |
| |
| <div class="flex items-center p-3 hover:bg-gray-50 rounded-lg transition cursor-pointer" onclick="viewProject('portfolio-website')"> |
| <div class="bg-green-100 text-green-600 p-3 rounded-lg mr-4"> |
| <i class="fas fa-globe"></i> |
| </div> |
| <div class="flex-1"> |
| <h4 class="font-medium">Portfolio Website</h4> |
| <p class="text-gray-500 text-sm">Next.js, Tailwind CSS</p> |
| </div> |
| <div class="text-gray-500 text-sm">Updated 3 days ago</div> |
| <div class="ml-4"> |
| <i class="fas fa-chevron-right text-gray-400"></i> |
| </div> |
| </div> |
| </div> |
| <button class="mt-6 w-full py-2 border border-gray-200 rounded-lg text-indigo-600 hover:bg-gray-50 transition" onclick="navigate('projects')"> |
| View All Projects |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div class="space-y-6"> |
| |
| <div class="bg-white rounded-xl shadow-md p-6"> |
| <h2 class="text-xl font-bold mb-6">Quick Actions</h2> |
| <div class="grid grid-cols-2 gap-4"> |
| <button class="flex flex-col items-center justify-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition" onclick="showNewSnippetModal()"> |
| <div class="bg-indigo-100 text-indigo-600 p-3 rounded-full mb-2"> |
| <i class="fas fa-file-code text-xl"></i> |
| </div> |
| <span class="text-sm">New Snippet</span> |
| </button> |
| <button class="flex flex-col items-center justify-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition" onclick="showNewProjectModal()"> |
| <div class="bg-blue-100 text-blue-600 p-3 rounded-full mb-2"> |
| <i class="fas fa-project-diagram text-xl"></i> |
| </div> |
| <span class="text-sm">New Project</span> |
| </button> |
| <button class="flex flex-col items-center justify-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition" onclick="showNewTaskModal()"> |
| <div class="bg-green-100 text-green-600 p-3 rounded-full mb-2"> |
| <i class="fas fa-tasks text-xl"></i> |
| </div> |
| <span class="text-sm">New Task</span> |
| </button> |
| <button class="flex flex-col items-center justify-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition" onclick="showTerminalModal()"> |
| <div class="bg-purple-100 text-purple-600 p-3 rounded-full mb-2"> |
| <i class="fas fa-terminal text-xl"></i> |
| </div> |
| <span class="text-sm">Run Script</span> |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div class="terminal rounded-xl shadow-md overflow-hidden"> |
| <div class="px-4 py-3 bg-gray-900 flex items-center"> |
| <div class="flex space-x-2 mr-4"> |
| <span class="editor-dot bg-red-500"></span> |
| <span class="editor-dot bg-yellow-500"></span> |
| <span class="editor-dot bg-green-500"></span> |
| </div> |
| <div class="text-gray-300 text-sm">bash</div> |
| </div> |
| <div class="p-4"> |
| <div class="mb-2"> |
| <span class="text-blue-400">user@devvision:~$</span> <span class="typing-effect" id="typing"></span> |
| </div> |
| <div id="terminal-output" class="text-sm"></div> |
| </div> |
| </div> |
|
|
| |
| <div class="bg-white rounded-xl shadow-md p-6"> |
| <div class="flex justify-between items-center mb-6"> |
| <h2 class="text-xl font-bold">Upcoming Tasks</h2> |
| <button class="text-indigo-600 hover:text-indigo-800 transition" onclick="showNewTaskModal()"> |
| <i class="fas fa-plus"></i> |
| </button> |
| </div> |
| <div class="space-y-4"> |
| <div class="flex items-start"> |
| <input type="checkbox" class="mt-1 mr-3" checked onclick="toggleTaskCompletion(this, 'task1')"> |
| <div class="flex-1"> |
| <h4 class="font-medium">Fix login bug</h4> |
| <p class="text-gray-500 text-sm">E-commerce project</p> |
| </div> |
| <span class="bg-green-100 text-green-800 text-xs px-2 py-1 rounded">Today</span> |
| </div> |
| <div class="flex items-start"> |
| <input type="checkbox" class="mt-1 mr-3" onclick="toggleTaskCompletion(this, 'task2')"> |
| <div class="flex-1"> |
| <h4 class="font-medium">Implement dark mode</h4> |
| <p class="text-gray-500 text-sm">Portfolio website</p> |
| </div> |
| <span class="bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded">Tomorrow</span> |
| </div> |
| <div class="flex items-start"> |
| <input type="checkbox" class="mt-1 mr-3" onclick="toggleTaskCompletion(this, 'task3')"> |
| <div class="flex-1"> |
| <h4 class="font-medium">Write API documentation</h4> |
| <p class="text-gray-500 text-sm">Fitness app</p> |
| </div> |
| <span class="bg-yellow-100 text-yellow-800 text-xs px-2 py-1 rounded">Fri</span> |
| </div> |
| </div> |
| <button class="mt-6 w-full py-2 border border-gray-200 rounded-lg text-indigo-600 hover:bg-gray-50 transition" onclick="navigate('projects')"> |
| View All Tasks |
| </button> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="projects-content" class="hidden route-transition"> |
| <div class="flex justify-between items-center mb-8"> |
| <h1 class="text-2xl md:text-3xl font-bold">My Projects</h1> |
| <button class="bg-indigo-600 text-white px-4 py-2 rounded-full font-medium hover:bg-indigo-700 transition flex items-center" onclick="showNewProjectModal()"> |
| <i class="fas fa-plus mr-2"></i> New Project |
| </button> |
| </div> |
|
|
| <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> |
| |
| </div> |
| </div> |
|
|
| |
| <div id="snippets-content" class="hidden route-transition"> |
| <div class="flex justify-between items-center mb-8"> |
| <h1 class="text-2xl md:text-3xl font-bold">Code Snippets</h1> |
| <button class="bg-indigo-600 text-white px-4 py-2 rounded-full font-medium hover:bg-indigo-700 transition flex items-center" onclick="showNewSnippetModal()"> |
| <i class="fas fa-plus mr-2"></i> New Snippet |
| </button> |
| </div> |
|
|
| <div class="grid grid-cols-1 lg:grid-cols-2 gap-6"> |
| |
| </div> |
| </div> |
|
|
| |
| <div id="community-content" class="hidden route-transition"> |
| <div class="flex justify-between items-center mb-8"> |
| <h1 class="text-2xl md:text-3xl font-bold">Dev Community</h1> |
| <button class="bg-indigo-600 text-white px-4 py-2 rounded-full font-medium hover:bg-indigo-700 transition flex items-center" onclick="showNewPostModal()"> |
| <i class="fas fa-plus mr-2"></i> New Post |
| </button> |
| </div> |
|
|
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-8"> |
| |
| </div> |
| </div> |
|
|
| |
| <div id="project-detail-content" class="hidden route-transition"> |
| |
| </div> |
|
|
| |
| <div id="snippet-detail-content" class="hidden route-transition"> |
| |
| </div> |
|
|
| |
| <div id="post-detail-content" class="hidden route-transition"> |
| |
| </div> |
|
|
| |
| <div id="profile-content" class="hidden route-transition"> |
| |
| </div> |
|
|
| |
| <div id="settings-content" class="hidden route-transition"> |
| |
| </div> |
| </div> |
|
|
| |
| |
| <div id="new-project-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> |
| <div class="bg-white rounded-xl shadow-xl w-full max-w-md mx-4"> |
| <div class="p-6"> |
| <div class="flex justify-between items-center mb-4"> |
| <h3 class="text-xl font-bold">Create New Project</h3> |
| <button class="text-gray-400 hover:text-gray-500" onclick="hideModal('new-project-modal')"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| <form id="new-project-form" onsubmit="createProject(event)"> |
| <div class="space-y-4"> |
| <div> |
| <label for="project-name" class="block text-sm font-medium text-gray-700 mb-1">Project Name</label> |
| <input type="text" id="project-name" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" required> |
| </div> |
| <div> |
| <label for="project-description" class="block text-sm font-medium text-gray-700 mb-1">Description</label> |
| <textarea id="project-description" rows="3" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"></textarea> |
| </div> |
| <div> |
| <label for="project-tech" class="block text-sm font-medium text-gray-700 mb-1">Technologies</label> |
| <select id="project-tech" multiple class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"> |
| <option value="react">React</option> |
| <option value="vue">Vue.js</option> |
| <option value="angular">Angular</option> |
| <option value="node">Node.js</option> |
| <option value="python">Python</option> |
| <option value="django">Django</option> |
| <option value="flask">Flask</option> |
| <option value="tailwind">Tailwind CSS</option> |
| </select> |
| </div> |
| <div> |
| <label for="project-template" class="block text-sm font-medium text-gray-700 mb-1">Template</label> |
| <select id="project-template" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"> |
| <option value="blank">Blank Project</option> |
| <option value="react">React Starter</option> |
| <option value="vue">Vue Starter</option> |
| <option value="node">Node.js API</option> |
| <option value="fullstack">Fullstack App</option> |
| </select> |
| </div> |
| </div> |
| <div class="mt-6 flex justify-end space-x-3"> |
| <button type="button" class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50" onclick="hideModal('new-project-modal')"> |
| Cancel |
| </button> |
| <button type="submit" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700"> |
| Create Project |
| </button> |
| </div> |
| </form> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="new-snippet-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> |
| <div class="bg-white rounded-xl shadow-xl w-full max-w-2xl mx-4"> |
| <div class="p-6"> |
| <div class="flex justify-between items-center mb-4"> |
| <h3 class="text-xl font-bold">Create New Code Snippet</h3> |
| <button class="text-gray-400 hover:text-gray-500" onclick="hideModal('new-snippet-modal')"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| <form id="new-snippet-form" onsubmit="createSnippet(event)"> |
| <div class="space-y-4"> |
| <div> |
| <label for="snippet-title" class="block text-sm font-medium text-gray-700 mb-1">Title</label> |
| <input type="text" id="snippet-title" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" required> |
| </div> |
| <div> |
| <label for="snippet-description" class="block text-sm font-medium text-gray-700 mb-1">Description</label> |
| <textarea id="snippet-description" rows="2" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"></textarea> |
| </div> |
| <div> |
| <label for="snippet-language" class="block text-sm font-medium text-gray-700 mb-1">Language</label> |
| <select id="snippet-language" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"> |
| <option value="javascript">JavaScript</option> |
| <option value="typescript">TypeScript</option> |
| <option value="python">Python</option> |
| <option value="java">Java</option> |
| <option value="csharp">C#</option> |
| <option value="php">PHP</option> |
| <option value="html">HTML</option> |
| <option value="css">CSS</option> |
| <option value="sql">SQL</option> |
| </select> |
| </div> |
| <div> |
| <label for="snippet-code" class="block text-sm font-medium text-gray-700 mb-1">Code</label> |
| <textarea id="snippet-code" rows="10" class="w-full px-3 py-2 border border-gray-300 rounded-lg font-mono text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500" required></textarea> |
| </div> |
| <div> |
| <label for="snippet-tags" class="block text-sm font-medium text-gray-700 mb-1">Tags</label> |
| <input type="text" id="snippet-tags" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="react, hooks, api"> |
| </div> |
| </div> |
| <div class="mt-6 flex justify-end space-x-3"> |
| <button type="button" class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50" onclick="hideModal('new-snippet-modal')"> |
| Cancel |
| </button> |
| <button type="submit" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700"> |
| Save Snippet |
| </button> |
| </div> |
| </form> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="new-task-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> |
| <div class="bg-white rounded-xl shadow-xl w-full max-w-md mx-4"> |
| <div class="p-6"> |
| <div class="flex justify-between items-center mb-4"> |
| <h3 class="text-xl font-bold">Add New Task</h3> |
| <button class="text-gray-400 hover:text-gray-500" onclick="hideModal('new-task-modal')"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| <form id="new-task-form" onsubmit="createTask(event)"> |
| <div class="space-y-4"> |
| <div> |
| <label for="task-title" class="block text-sm font-medium text-gray-700 mb-1">Task Title</label> |
| <input type="text" id="task-title" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" required> |
| </div> |
| <div> |
| <label for="task-project" class="block text-sm font-medium text-gray-700 mb-1">Project</label> |
| <select id="task-project" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"> |
| <option value="">Select Project</option> |
| <option value="ecommerce-dashboard">E-commerce Dashboard</option> |
| <option value="fitness-app">Fitness App</option> |
| <option value="portfolio-website">Portfolio Website</option> |
| </select> |
| </div> |
| <div> |
| <label for="task-due-date" class="block text-sm font-medium text-gray-700 mb-1">Due Date</label> |
| <input type="date" id="task-due-date" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"> |
| </div> |
| <div> |
| <label for="task-priority" class="block text-sm font-medium text-gray-700 mb-1">Priority</label> |
| <select id="task-priority" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"> |
| <option value="low">Low</option> |
| <option value="medium">Medium</option> |
| <option value="high">High</option> |
| </select> |
| </div> |
| <div> |
| <label for="task-description" class="block text-sm font-medium text-gray-700 mb-1">Description</label> |
| <textarea id="task-description" rows="3" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"></textarea> |
| </div> |
| </div> |
| <div class="mt-6 flex justify-end space-x-3"> |
| <button type="button" class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50" onclick="hideModal('new-task-modal')"> |
| Cancel |
| </button> |
| <button type="submit" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700"> |
| Add Task |
| </button> |
| </div> |
| </form> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="terminal-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> |
| <div class="bg-gray-900 rounded-xl shadow-xl w-full max-w-4xl mx-4 overflow-hidden"> |
| <div class="px-4 py-3 flex items-center justify-between bg-gray-800"> |
| <div class="flex items-center"> |
| <div class="flex space-x-2 mr-4"> |
| <span class="editor-dot bg-red-500"></span> |
| <span class="editor-dot bg-yellow-500"></span> |
| <span class="editor-dot bg-green-500"></span> |
| </div> |
| <div class="text-gray-300 text-sm">Terminal</div> |
| </div> |
| <button class="text-gray-400 hover:text-gray-500" onclick="hideModal('terminal-modal')"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| <div class="p-4 h-96 overflow-y-auto"> |
| <div id="terminal-full-output" class="text-sm font-mono text-green-400"></div> |
| <div class="flex items-center mt-2"> |
| <span class="text-blue-400">user@devvision:~$</span> |
| <input type="text" id="terminal-input" class="flex-1 bg-transparent border-none text-green-400 outline-none ml-2" autofocus> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="new-post-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> |
| <div class="bg-white rounded-xl shadow-xl w-full max-w-2xl mx-4"> |
| <div class="p-6"> |
| <div class="flex justify-between items-center mb-4"> |
| <h3 class="text-xl font-bold">Create New Post</h3> |
| <button class="text-gray-400 hover:text-gray-500" onclick="hideModal('new-post-modal')"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| <form id="new-post-form" onsubmit="createPost(event)"> |
| <div class="space-y-4"> |
| <div> |
| <label for="post-title" class="block text-sm font-medium text-gray-700 mb-1">Title</label> |
| <input type="text" id="post-title" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" required> |
| </div> |
| <div> |
| <label for="post-content" class="block text-sm font-medium text-gray-700 mb-1">Content</label> |
| <textarea id="post-content" rows="8" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" required></textarea> |
| </div> |
| <div> |
| <label for="post-tags" class="block text-sm font-medium text-gray-700 mb-1">Tags</label> |
| <select id="post-tags" multiple class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"> |
| <option value="react">React</option> |
| <option value="javascript">JavaScript</option> |
| <option value="css">CSS</option> |
| <option value="node">Node.js</option> |
| <option value="python">Python</option> |
| <option value="database">Database</option> |
| <option value="webdev">Web Development</option> |
| <option value="mobile">Mobile</option> |
| </select> |
| </div> |
| <div> |
| <label for="post-code" class="block text-sm font-medium text-gray-700 mb-1">Code (optional)</label> |
| <textarea id="post-code" rows="5" class="w-full px-3 py-2 border border-gray-300 rounded-lg font-mono text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500"></textarea> |
| </div> |
| </div> |
| <div class="mt-6 flex justify-end space-x-3"> |
| <button type="button" class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50" onclick="hideModal('new-post-modal')"> |
| Cancel |
| </button> |
| <button type="submit" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700"> |
| Publish Post |
| </button> |
| </div> |
| </form> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="confirmation-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> |
| <div class="bg-white rounded-xl shadow-xl w-full max-w-md mx-4"> |
| <div class="p-6"> |
| <div class="flex justify-between items-center mb-4"> |
| <h3 class="text-xl font-bold" id="confirmation-title">Confirm Action</h3> |
| <button class="text-gray-400 hover:text-gray-500" onclick="hideModal('confirmation-modal')"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| <p class="text-gray-700 mb-6" id="confirmation-message">Are you sure you want to perform this action?</p> |
| <div class="flex justify-end space-x-3"> |
| <button type="button" class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50" onclick="hideModal('confirmation-modal')"> |
| Cancel |
| </button> |
| <button type="button" class="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700" onclick="confirmAction()"> |
| Confirm |
| </button> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="notification-toast" class="fixed bottom-4 right-4 bg-gray-800 text-white px-6 py-3 rounded-lg shadow-lg transform translate-y-10 opacity-0 transition-all duration-300 z-50"> |
| <div class="flex items-center"> |
| <i class="fas fa-check-circle text-green-400 mr-3" id="toast-icon"></i> |
| <span id="toast-message">Action completed successfully</span> |
| </div> |
| </div> |
|
|
| <script> |
| |
| const state = { |
| currentUser: { |
| id: 1, |
| name: "Alex Turner", |
| email: "alex@example.com", |
| avatar: "https://randomuser.me/api/portraits/men/32.jpg", |
| role: "developer", |
| joined: "2022-01-15", |
| lastActive: "2023-06-20" |
| }, |
| projects: [ |
| { |
| id: "ecommerce-dashboard", |
| name: "E-commerce Dashboard", |
| description: "Admin dashboard for online store", |
| technologies: ["React", "Node.js", "MongoDB"], |
| status: "active", |
| createdAt: "2023-05-10", |
| updatedAt: "2023-06-20", |
| collaborators: [ |
| { id: 2, name: "Sarah Johnson", avatar: "https://randomuser.me/api/portraits/women/44.jpg" }, |
| { id: 3, name: "Michael Chen", avatar: "https://randomuser.me/api/portraits/men/75.jpg" } |
| ], |
| tasks: [ |
| { id: "task1", title: "Fix login bug", completed: true, dueDate: "2023-06-20", priority: "high" }, |
| { id: "task2", title: "Add product filters", completed: false, dueDate: "2023-06-25", priority: "medium" } |
| ] |
| }, |
| { |
| id: "fitness-app", |
| name: "Fitness App", |
| description: "Mobile app for workout tracking", |
| technologies: ["React Native", "Firebase"], |
| status: "active", |
| createdAt: "2023-04-15", |
| updatedAt: "2023-06-19", |
| collaborators: [], |
| tasks: [ |
| { id: "task3", title: "Implement dark mode", completed: false, dueDate: "2023-06-23", priority: "medium" } |
| ] |
| }, |
| { |
| id: "portfolio-website", |
| name: "Portfolio Website", |
| description: "Personal portfolio website", |
| technologies: ["Next.js", "Tailwind CSS"], |
| status: "active", |
| createdAt: "2023-03-20", |
| updatedAt: "2023-06-17", |
| collaborators: [], |
| tasks: [ |
| { id: "task4", title: "Write API documentation", completed: false, dueDate: "2023-06-24", priority: "low" } |
| ] |
| }, |
| { |
| id: "blog-platform", |
| name: "Blog Platform", |
| description: "Content management system", |
| technologies: ["Vue.js", "Django"], |
| status: "paused", |
| createdAt: "2023-02-05", |
| updatedAt: "2023-06-10", |
| collaborators: [ |
| { id: 4, name: "Emma Wilson", avatar: "https://randomuser.me/api/portraits/women/68.jpg" } |
| ], |
| tasks: [] |
| }, |
| { |
| id: "weather-app", |
| name: "Weather App", |
| description: "Real-time weather forecasts", |
| technologies: ["React", "API"], |
| status: "completed", |
| createdAt: "2023-01-12", |
| updatedAt: "2023-05-30", |
| collaborators: [], |
| tasks: [] |
| } |
| ], |
| snippets: [ |
| { |
| id: "snippet1", |
| title: "React Hook: useFetch", |
| description: "Custom hook for API calls", |
| language: "javascript", |
| code: `import { useState, useEffect } from 'react'; |
| |
| const useFetch = (url) => { |
| const [data, setData] = useState(null); |
| const [loading, setLoading] = useState(true); |
| const [error, setError] = useState(null); |
| |
| useEffect(() => { |
| const fetchData = async () => { |
| try { |
| const response = await fetch(url); |
| const json = await response.json(); |
| setData(json); |
| } catch (err) { |
| setError(err); |
| } finally { |
| setLoading(false); |
| } |
| }; |
| |
| fetchData(); |
| }, [url]); |
| |
| return { data, loading, error }; |
| }; |
| |
| export default useFetch;`, |
| tags: ["react", "hooks", "api"], |
| createdAt: "2023-06-15", |
| updatedAt: "2023-06-15" |
| }, |
| { |
| id: "snippet2", |
| title: "Debounce Function", |
| description: "JavaScript utility function", |
| language: "javascript", |
| code: `function debounce(func, wait, immediate) { |
| let timeout; |
| |
| return function() { |
| const context = this; |
| const args = arguments; |
| |
| const later = function() { |
| timeout = null; |
| if (!immediate) func.apply(context, args); |
| }; |
| |
| const callNow = immediate && !timeout; |
| clearTimeout(timeout); |
| timeout = setTimeout(later, wait); |
| |
| if (callNow) func.apply(context, args); |
| }; |
| } |
| |
| // Usage: |
| const myEfficientFn = debounce(function() { |
| // All the taxing stuff you do |
| }, 250); |
| |
| window.addEventListener('resize', myEfficientFn);`, |
| tags: ["javascript", "utility"], |
| createdAt: "2023-06-01", |
| updatedAt: "2023-06-01" |
| }, |
| { |
| id: "snippet3", |
| title: "Tailwind Button", |
| description: "Reusable button component", |
| language: "javascript", |
| code: `import React from 'react'; |
| |
| const Button = ({ |
| children, |
| variant = 'primary', |
| size = 'md', |
| disabled = false, |
| className = '', |
| ...props |
| }) => { |
| const baseClasses = \`rounded-lg font-medium transition-all flex items-center justify-center\`; |
| |
| const variantClasses = { |
| primary: \`bg-indigo-600 text-white hover:bg-indigo-700\`, |
| secondary: \`bg-gray-200 text-gray-800 hover:bg-gray-300\`, |
| danger: \`bg-red-600 text-white hover:bg-red-700\`, |
| }; |
| |
| const sizeClasses = { |
| sm: \`py-1 px-3 text-sm\`, |
| md: \`py-2 px-4\`, |
| lg: \`py-3 px-6 text-lg\`, |
| }; |
| |
| return ( |
| <button |
| className={\`\${baseClasses} \${variantClasses[variant]} \${sizeClasses[size]} \${className}\`} |
| disabled={disabled} |
| {...props} |
| > |
| {children} |
| </button> |
| ); |
| }; |
| |
| export default Button;`, |
| tags: ["react", "tailwind", "components"], |
| createdAt: "2023-05-20", |
| updatedAt: "2023-05-20" |
| }, |
| { |
| id: "snippet4", |
| title: "LocalStorage Hook", |
| description: "Persist state with localStorage", |
| language: "javascript", |
| code: `import { useState, useEffect } from 'react'; |
| |
| function useLocalStorage(key, initialValue) { |
| const [storedValue, setStoredValue] = useState(() => { |
| try { |
| const item = window.localStorage.getItem(key); |
| return item ? JSON.parse(item) : initialValue; |
| } catch (error) { |
| console.log(error); |
| return initialValue; |
| } |
| }); |
| |
| const setValue = (value) => { |
| try { |
| const valueToStore = |
| value instanceof Function ? value(storedValue) : value; |
| setStoredValue(valueToStore); |
| window.localStorage.setItem(key, JSON.stringify(valueToStore)); |
| } catch (error) { |
| console.log(error); |
| } |
| }; |
| |
| return [storedValue, setValue]; |
| } |
| |
| export default useLocalStorage;`, |
| tags: ["react", "hooks", "localstorage"], |
| createdAt: "2023-05-10", |
| updatedAt: "2023-05-10" |
| } |
| ], |
| communityPosts: [ |
| { |
| id: "post1", |
| title: "How to optimize React performance?", |
| content: "I've been working on a large React application and noticed some performance issues, especially with re-renders. What are some best practices to optimize React performance in 2023?", |
| author: { |
| id: 2, |
| name: "Sarah Johnson", |
| avatar: "https://randomuser.me/api/portraits/women/44.jpg", |
| role: "senior developer" |
| }, |
| tags: ["react", "performance"], |
| createdAt: "2023-06-20", |
| updatedAt: "2023-06-20", |
| comments: 14, |
| likes: 32, |
| views: 156 |
| }, |
| { |
| id: "post2", |
| title: "Tailwind CSS vs. Traditional CSS", |
| content: "I'm starting a new project and debating between using Tailwind CSS or writing traditional CSS. For those who have used both, what are the pros and cons of each approach?", |
| author: { |
| id: 3, |
| name: "Michael Chen", |
| avatar: "https://randomuser.me/api/portraits/men/75.jpg", |
| role: "frontend lead" |
| }, |
| tags: ["css", "tailwind"], |
| createdAt: "2023-06-19", |
| updatedAt: "2023-06-19", |
| comments: 27, |
| likes: 45, |
| views: 210 |
| }, |
| { |
| id: "post3", |
| title: "State management in 2023", |
| content: "With so many state management options available (Redux, Context API, Zustand, Jotai, etc.), how do you decide which one to use for a new project? What are the current best practices?", |
| author: { |
| id: 4, |
| name: "Emma Wilson", |
| avatar: "https://randomuser.me/api/portraits/women/68.jpg", |
| role: "fullstack developer" |
| }, |
| tags: ["javascript", "react", "state"], |
| createdAt: "2023-06-18", |
| updatedAt: "2023-06-18", |
| comments: 38, |
| likes: 72, |
| views: 320 |
| }, |
| { |
| id: "post4", |
| title: "Building a full-stack app with Next.js", |
| content: "I'm documenting my journey building a full-stack application with Next.js, Prisma, and PostgreSQL. Here are some lessons learned and patterns I've found useful...", |
| author: { |
| id: 1, |
| name: "Alex Turner", |
| avatar: "https://randomuser.me/api/portraits/men/32.jpg", |
| role: "developer" |
| }, |
| tags: ["nextjs", "fullstack", "prisma"], |
| createdAt: "2023-06-17", |
| updatedAt: "2023-06-17", |
| comments: 22, |
| likes: 56, |
| views: 189 |
| } |
| ], |
| currentRoute: "dashboard", |
| pendingAction: null, |
| terminalHistory: [] |
| }; |
| |
| |
| const elements = { |
| contentContainers: { |
| dashboard: document.getElementById('dashboard-content'), |
| projects: document.getElementById('projects-content'), |
| snippets: document.getElementById('snippets-content'), |
| community: document.getElementById('community-content'), |
| projectDetail: document.getElementById('project-detail-content'), |
| snippetDetail: document.getElementById('snippet-detail-content'), |
| postDetail: document.getElementById('post-detail-content'), |
| profile: document.getElementById('profile-content'), |
| settings: document.getElementById('settings-content') |
| }, |
| navLinks: { |
| dashboard: document.getElementById('nav-dashboard'), |
| projects: document.getElementById('nav-projects'), |
| snippets: document.getElementById('nav-snippets'), |
| community: document.getElementById('nav-community') |
| }, |
| modals: { |
| newProject: document.getElementById('new-project-modal'), |
| newSnippet: document.getElementById('new-snippet-modal'), |
| newTask: document.getElementById('new-task-modal'), |
| terminal: document.getElementById('terminal-modal'), |
| newPost: document.getElementById('new-post-modal'), |
| confirmation: document.getElementById('confirmation-modal') |
| }, |
| forms: { |
| newProject: document.getElementById('new-project-form'), |
| newSnippet: document.getElementById('new-snippet-form'), |
| newTask: document.getElementById('new-task-form'), |
| newPost: document.getElementById('new-post-form') |
| }, |
| terminal: { |
| input: document.getElementById('terminal-input'), |
| output: document.getElementById('terminal-output'), |
| fullOutput: document.getElementById('terminal-full-output') |
| }, |
| notification: document.getElementById('notification-toast') |
| }; |
| |
| |
| function formatDate(dateString) { |
| const date = new Date(dateString); |
| const now = new Date(); |
| const diffInDays = Math.floor((now - date) / (1000 * 60 * 60 * 24)); |
| |
| if (diffInDays === 0) return "Today"; |
| if (diffInDays === 1) return "Yesterday"; |
| if (diffInDays < 7) return `${diffInDays} days ago`; |
| if (diffInDays < 30) return `${Math.floor(diffInDays / 7)} weeks ago`; |
| return date.toLocaleDateString(); |
| } |
| |
| function showNotification(message, isSuccess = true) { |
| const toast = elements.notification; |
| const icon = document.getElementById('toast-icon'); |
| const toastMessage = document.getElementById('toast-message'); |
| |
| toastMessage.textContent = message; |
| icon.className = isSuccess ? 'fas fa-check-circle text-green-400 mr-3' : 'fas fa-exclamation-circle text-red-400 mr-3'; |
| |
| toast.classList.remove('translate-y-10', 'opacity-0'); |
| toast.classList.add('translate-y-0', 'opacity-100'); |
| |
| setTimeout(() => { |
| toast.classList.remove('translate-y-0', 'opacity-100'); |
| toast.classList.add('translate-y-10', 'opacity-0'); |
| }, 3000); |
| } |
| |
| function showModal(modalId) { |
| elements.modals[modalId].classList.remove('hidden'); |
| document.body.classList.add('overflow-hidden'); |
| } |
| |
| function hideModal(modalId) { |
| elements.modals[modalId].classList.add('hidden'); |
| document.body.classList.remove('overflow-hidden'); |
| } |
| |
| function showConfirmation(title, message, action) { |
| document.getElementById('confirmation-title').textContent = title; |
| document.getElementById('confirmation-message').textContent = message; |
| state.pendingAction = action; |
| showModal('confirmation'); |
| } |
| |
| function confirmAction() { |
| if (state.pendingAction) { |
| state.pendingAction(); |
| state.pendingAction = null; |
| } |
| hideModal('confirmation'); |
| } |
| |
| |
| function navigate(route, params = {}) { |
| |
| Object.values(elements.contentContainers).forEach(container => { |
| container.classList.add('hidden'); |
| }); |
| |
| |
| Object.values(elements.navLinks).forEach(link => { |
| link.classList.remove('active-nav'); |
| }); |
| |
| |
| state.currentRoute = route; |
| |
| |
| switch (route) { |
| case 'dashboard': |
| elements.navLinks.dashboard.classList.add('active-nav'); |
| elements.contentContainers.dashboard.classList.remove('hidden'); |
| break; |
| case 'projects': |
| elements.navLinks.projects.classList.add('active-nav'); |
| elements.contentContainers.projects.classList.remove('hidden'); |
| renderProjects(); |
| break; |
| case 'snippets': |
| elements.navLinks.snippets.classList.add('active-nav'); |
| elements.contentContainers.snippets.classList.remove('hidden'); |
| renderSnippets(); |
| break; |
| case 'community': |
| elements.navLinks.community.classList.add('active-nav'); |
| elements.contentContainers.community.classList.remove('hidden'); |
| renderCommunity(); |
| break; |
| case 'project': |
| elements.contentContainers.projectDetail.classList.remove('hidden'); |
| renderProjectDetail(params.id); |
| break; |
| case 'snippet': |
| elements.contentContainers.snippetDetail.classList.remove('hidden'); |
| renderSnippetDetail(params.id); |
| break; |
| case 'post': |
| elements.contentContainers.postDetail.classList.remove('hidden'); |
| renderPostDetail(params.id); |
| break; |
| case 'profile': |
| elements.contentContainers.profile.classList.remove('hidden'); |
| renderProfile(); |
| break; |
| case 'settings': |
| elements.contentContainers.settings.classList.remove('hidden'); |
| renderSettings(); |
| break; |
| } |
| } |
| |
| |
| function renderProjects() { |
| const container = document.querySelector('#projects-content .grid'); |
| container.innerHTML = ''; |
| |
| state.projects.forEach(project => { |
| const projectCard = document.createElement('div'); |
| projectCard.className = 'bg-white rounded-xl shadow-md overflow-hidden transition duration-300 card-hover cursor-pointer'; |
| projectCard.onclick = () => navigate('project', { id: project.id }); |
| |
| const statusColors = { |
| active: 'bg-indigo-600', |
| paused: 'bg-yellow-600', |
| completed: 'bg-green-600' |
| }; |
| |
| projectCard.innerHTML = ` |
| <div class="${statusColors[project.status] || 'bg-indigo-600'} p-4 text-white"> |
| <div class="flex justify-between items-center"> |
| <h3 class="font-bold text-lg">${project.name}</h3> |
| <div class="flex space-x-2"> |
| ${project.technologies.slice(0, 2).map(tech => |
| `<span class="bg-white bg-opacity-20 px-2 py-1 rounded-full text-xs">${tech}</span>` |
| ).join('')} |
| </div> |
| </div> |
| <p class="text-sm opacity-90 mt-2">${project.description}</p> |
| </div> |
| <div class="p-4"> |
| <div class="flex justify-between items-center text-sm text-gray-500 mb-3"> |
| <span><i class="fas fa-calendar-alt mr-1"></i> Last updated: ${formatDate(project.updatedAt)}</span> |
| <span><i class="fas fa-code-branch mr-1"></i> main</span> |
| </div> |
| <div class="flex justify-between items-center"> |
| <div class="flex -space-x-2"> |
| ${project.collaborators.slice(0, 3).map((collab, index) => |
| `<img src="${collab.avatar}" class="w-8 h-8 rounded-full border-2 border-white" alt="${collab.name}" title="${collab.name}">` |
| ).join('')} |
| ${project.collaborators.length > 3 ? |
| `<div class="w-8 h-8 rounded-full border-2 border-white bg-gray-200 flex items-center justify-center text-xs">+${project.collaborators.length - 3}</div>` : ''} |
| </div> |
| <div class="text-indigo-600 text-sm font-medium">View Project</div> |
| </div> |
| </div> |
| `; |
| |
| container.appendChild(projectCard); |
| }); |
| |
| |
| const newProjectCard = document.createElement('div'); |
| newProjectCard.className = 'bg-white rounded-xl shadow-md overflow-hidden transition duration-300 card-hover cursor-pointer border-2 border-dashed border-gray-300 flex items-center justify-center'; |
| newProjectCard.onclick = () => showModal('newProject'); |
| |
| newProjectCard.innerHTML = ` |
| <div class="text-center p-6"> |
| <div class="bg-indigo-100 text-indigo-600 p-4 rounded-full inline-block mb-3"> |
| <i class="fas fa-plus text-xl"></i> |
| </div> |
| <h3 class="font-bold text-lg text-gray-700">Add New Project</h3> |
| <p class="text-sm text-gray-500 mt-1">Start a new coding adventure</p> |
| </div> |
| `; |
| |
| container.appendChild(newProjectCard); |
| } |
| |
| function renderSnippets() { |
| const container = document.querySelector('#snippets-content .grid'); |
| container.innerHTML = ''; |
| |
| state.snippets.forEach(snippet => { |
| const snippetCard = document.createElement('div'); |
| snippetCard.className = 'bg-white rounded-xl shadow-md overflow-hidden'; |
| |
| snippetCard.innerHTML = ` |
| <div class="p-4 border-b border-gray-200"> |
| <div class="flex justify-between items-center"> |
| <h3 class="font-bold text-lg">${snippet.title}</h3> |
| <div class="flex space-x-2"> |
| <button class="text-gray-400 hover:text-indigo-600" onclick="copySnippet('${snippet.id}')"> |
| <i class="fas fa-copy"></i> |
| </button> |
| <button class="text-gray-400 hover:text-red-600" onclick="deleteSnippetPrompt('${snippet.id}')"> |
| <i class="fas fa-trash"></i> |
| </button> |
| </div> |
| </div> |
| <p class="text-sm text-gray-500 mt-1">${snippet.description}</p> |
| </div> |
| <div class="p-4 snippet-code"> |
| <pre class="text-sm overflow-x-auto"><code>${snippet.code}</code></pre> |
| </div> |
| <div class="p-4 border-t border-gray-200 text-sm text-gray-500"> |
| <div class="flex justify-between items-center"> |
| <span>Created: ${formatDate(snippet.createdAt)}</span> |
| <span class="bg-indigo-100 text-indigo-800 px-2 py-1 rounded-full text-xs">${snippet.language}</span> |
| </div> |
| </div> |
| `; |
| |
| container.appendChild(snippetCard); |
| }); |
| |
| |
| const newSnippetCard = document.createElement('div'); |
| newSnippetCard.className = 'bg-white rounded-xl shadow-md overflow-hidden transition duration-300 card-hover cursor-pointer border-2 border-dashed border-gray-300 flex items-center justify-center'; |
| newSnippetCard.onclick = () => showModal('newSnippet'); |
| |
| newSnippetCard.innerHTML = ` |
| <div class="text-center p-6"> |
| <div class="bg-indigo-100 text-indigo-600 p-4 rounded-full inline-block mb-3"> |
| <i class="fas fa-plus text-xl"></i> |
| </div> |
| <h3 class="font-bold text-lg text-gray-700">Add New Snippet</h3> |
| <p class="text-sm text-gray-500 mt-1">Save your useful code pieces</p> |
| </div> |
| `; |
| |
| container.appendChild(newSnippetCard); |
| } |
| |
| function renderCommunity() { |
| const mainContainer = document.querySelector('#community-content .lg\\:col-span-2'); |
| const sidebarContainer = document.querySelector('#community-content .lg\\:col-span-1'); |
| |
| |
| mainContainer.querySelector('.space-y-4').innerHTML = ''; |
| sidebarContainer.innerHTML = ''; |
| |
| |
| state.communityPosts.forEach(post => { |
| const postElement = document.createElement('div'); |
| postElement.className = 'bg-white rounded-xl shadow-md p-6 community-post cursor-pointer'; |
| postElement.onclick = () => navigate('post', { id: post.id }); |
| |
| postElement.innerHTML = ` |
| <div class="flex items-start space-x-4"> |
| <img src="${post.author.avatar}" alt="User" class="w-12 h-12 rounded-full"> |
| <div class="flex-1"> |
| <div class="flex justify-between items-start"> |
| <div> |
| <h3 class="font-bold text-lg">${post.title}</h3> |
| <p class="text-sm text-gray-500">Posted by ${post.author.name} • ${formatDate(post.createdAt)}</p> |
| </div> |
| <span class="bg-indigo-100 text-indigo-800 px-2 py-1 rounded-full text-xs">${post.tags[0]}</span> |
| </div> |
| <p class="mt-2 text-gray-700">${post.content}</p> |
| <div class="mt-4 flex items-center space-x-6 text-sm text-gray-500"> |
| <span><i class="far fa-comment mr-1"></i> ${post.comments} comments</span> |
| <span><i class="far fa-heart mr-1"></i> ${post.likes} likes</span> |
| <span><i class="fas fa-share mr-1"></i> Share</span> |
| </div> |
| </div> |
| </div> |
| `; |
| |
| mainContainer.querySelector('.space-y-4').appendChild(postElement); |
| }); |
| |
| |
| sidebarContainer.innerHTML = ` |
| <!-- Popular Topics --> |
| <div class="bg-white rounded-xl shadow-md p-6"> |
| <h3 class="font-bold text-lg mb-4">Popular Topics</h3> |
| <div class="space-y-3"> |
| <a href="#" class="flex items-center justify-between p-2 hover:bg-gray-50 rounded-lg transition"> |
| <div class="flex items-center space-x-3"> |
| <div class="bg-indigo-100 text-indigo-600 p-2 rounded-lg"> |
| <i class="fab fa-react"></i> |
| </div> |
| <span>React</span> |
| </div> |
| <span class="bg-gray-100 text-gray-800 px-2 py-1 rounded-full text-xs">142 posts</span> |
| </a> |
| <a href="#" class="flex items-center justify-between p-2 hover:bg-gray-50 rounded-lg transition"> |
| <div class="flex items-center space-x-3"> |
| <div class="bg-blue-100 text-blue-600 p-2 rounded-lg"> |
| <i class="fab fa-js"></i> |
| </div> |
| <span>JavaScript</span> |
| </div> |
| <span class="bg-gray-100 text-gray-800 px-2 py-1 rounded-full text-xs">98 posts</span> |
| </a> |
| <a href="#" class="flex items-center justify-between p-2 hover:bg-gray-50 rounded-lg transition"> |
| <div class="flex items-center space-x-3"> |
| <div class="bg-green-100 text-green-600 p-2 rounded-lg"> |
| <i class="fab fa-css3-alt"></i> |
| </div> |
| <span>CSS</span> |
| </div> |
| <span class="bg-gray-100 text-gray-800 px-2 py-1 rounded-full text-xs">76 posts</span> |
| </a> |
| <a href="#" class="flex items-center justify-between p-2 hover:bg-gray-50 rounded-lg transition"> |
| <div class="flex items-center space-x-3"> |
| <div class="bg-purple-100 text-purple-600 p-2 rounded-lg"> |
| <i class="fab fa-node-js"></i> |
| </div> |
| <span>Node.js</span> |
| </div> |
| <span class="bg-gray-100 text-gray-800 px-2 py-1 rounded-full text-xs">64 posts</span> |
| </a> |
| <a href="#" class="flex items-center justify-between p-2 hover:bg-gray-50 rounded-lg transition"> |
| <div class="flex items-center space-x-3"> |
| <div class="bg-yellow-100 text-yellow-600 p-2 rounded-lg"> |
| <i class="fas fa-database"></i> |
| </div> |
| <span>Database</span> |
| </div> |
| <span class="bg-gray-100 text-gray-800 px-2 py-1 rounded-full text-xs">52 posts</span> |
| </a> |
| </div> |
| </div> |
| |
| <!-- Top Contributors --> |
| <div class="bg-white rounded-xl shadow-md p-6 mt-6"> |
| <h3 class="font-bold text-lg mb-4">Top Contributors</h3> |
| <div class="space-y-4"> |
| <div class="flex items-center space-x-3"> |
| <img src="https://randomuser.me/api/portraits/women/44.jpg" alt="User" class="w-10 h-10 rounded-full"> |
| <div class="flex-1"> |
| <h4 class="font-medium">Sarah Johnson</h4> |
| <p class="text-sm text-gray-500">React Expert</p> |
| </div> |
| < |
| </html> |