MoiMoi-01 commited on
Commit
8ecdc7b
·
verified ·
1 Parent(s): ab3ac32

Add 2 files

Browse files
Files changed (2) hide show
  1. index.html +334 -215
  2. prompts.txt +2 -0
index.html CHANGED
@@ -3,35 +3,42 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Project Manager - Card View</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
10
- .card-hover {
11
  transition: all 0.3s ease;
 
12
  }
13
- .card-hover:hover {
14
  transform: translateY(-5px);
15
- box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
16
- }
17
- .status-badge {
18
- position: absolute;
19
- top: -10px;
20
- right: -10px;
21
- border-radius: 9999px;
22
- padding: 0.25rem 0.5rem;
23
- font-size: 0.75rem;
24
- font-weight: 600;
25
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
26
  }
27
- .tag-pill {
28
  transition: all 0.2s ease;
29
  }
30
- .tag-pill:hover {
31
  transform: scale(1.05);
32
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  .fade-in {
34
- animation: fadeIn 0.3s ease-in-out;
35
  }
36
  @keyframes fadeIn {
37
  from { opacity: 0; transform: translateY(10px); }
@@ -44,51 +51,70 @@
44
  .form-input:focus {
45
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2);
46
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  </style>
48
  </head>
49
  <body class="bg-gray-50 min-h-screen">
50
- <div class="container mx-auto px-4 py-8">
51
  <!-- Header -->
52
- <header class="flex flex-col md:flex-row justify-between items-center mb-8">
53
- <div>
54
- <h1 class="text-3xl font-bold text-gray-800">Project Manager</h1>
55
- <p class="text-gray-600">Track and manage your projects</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  </div>
57
- <button id="addProjectBtn" class="mt-4 md:mt-0 bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-lg flex items-center transition-colors">
58
- <i class="fas fa-plus mr-2"></i> Add Project
59
- </button>
60
- </header>
61
 
62
- <!-- Filter Controls -->
63
- <div class="mb-8 bg-white p-4 rounded-lg shadow-sm">
64
- <div class="flex flex-wrap items-center gap-4">
65
- <div class="flex-1 min-w-[200px]">
66
- <label for="statusFilter" class="block text-sm font-medium text-gray-700 mb-1">Status</label>
67
- <select id="statusFilter" class="w-full border border-gray-300 rounded-md py-2 px-3 focus:outline-none focus:ring-2 focus:ring-blue-500">
68
- <option value="all">All Statuses</option>
69
- <option value="Not Started">Not Started</option>
70
- <option value="In Progress">In Progress</option>
71
- <option value="Completed">Completed</option>
72
- <option value="On Hold">On Hold</option>
73
- </select>
74
- </div>
75
- <div class="flex-1 min-w-[200px]">
76
- <label for="tagFilter" class="block text-sm font-medium text-gray-700 mb-1">Tags</label>
77
- <select id="tagFilter" class="w-full border border-gray-300 rounded-md py-2 px-3 focus:outline-none focus:ring-2 focus:ring-blue-500">
78
- <option value="all">All Tags</option>
79
- <!-- Tags will be populated dynamically -->
80
- </select>
81
- </div>
82
- <div class="flex items-end">
83
- <button id="resetFilters" class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded-md transition-colors">
84
- Reset Filters
85
- </button>
86
- </div>
87
  </div>
88
  </div>
89
 
90
  <!-- Projects Grid -->
91
- <div id="projectsContainer" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
92
  <!-- Project cards will be inserted here dynamically -->
93
  </div>
94
 
@@ -98,18 +124,25 @@
98
  <i class="fas fa-folder-open text-5xl text-gray-300 mb-4"></i>
99
  <h3 class="text-xl font-medium text-gray-700 mb-2">No projects found</h3>
100
  <p class="text-gray-500 mb-4">Add a new project or adjust your filters</p>
101
- <button id="addProjectBtnEmpty" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-lg inline-flex items-center transition-colors">
102
  <i class="fas fa-plus mr-2"></i> Add Project
103
  </button>
104
  </div>
105
  </div>
 
 
 
 
 
 
 
106
  </div>
107
 
108
  <!-- Add/Edit Project Modal -->
109
  <div id="projectModal" class="fixed inset-0 z-50 hidden">
110
  <div class="modal-overlay absolute inset-0"></div>
111
  <div class="flex items-center justify-center min-h-screen">
112
- <div class="bg-white rounded-lg shadow-xl w-full max-w-2xl max-h-[90vh] overflow-y-auto m-4">
113
  <div class="p-6">
114
  <div class="flex justify-between items-center mb-4">
115
  <h3 id="modalTitle" class="text-xl font-bold text-gray-800">Add New Project</h3>
@@ -124,74 +157,74 @@
124
  <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
125
  <div>
126
  <label for="projectName" class="block text-sm font-medium text-gray-700 mb-1">Project Name *</label>
127
- <input type="text" id="projectName" required class="w-full border border-gray-300 rounded-md py-2 px-3 form-input focus:outline-none focus:border-blue-500">
128
  </div>
129
 
130
  <div>
131
  <label for="projectStatus" class="block text-sm font-medium text-gray-700 mb-1">Status *</label>
132
- <select id="projectStatus" required class="w-full border border-gray-300 rounded-md py-2 px-3 focus:outline-none focus:border-blue-500">
133
- <option value="Not Started">Not Started</option>
134
- <option value="In Progress">In Progress</option>
135
- <option value="Completed">Completed</option>
136
- <option value="On Hold">On Hold</option>
137
  </select>
138
  </div>
139
  </div>
140
 
141
  <div>
142
  <label for="projectImage" class="block text-sm font-medium text-gray-700 mb-1">Image URL</label>
143
- <input type="url" id="projectImage" class="w-full border border-gray-300 rounded-md py-2 px-3 form-input focus:outline-none focus:border-blue-500">
144
  </div>
145
 
146
  <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
147
  <div>
148
  <label for="projectDateRange" class="block text-sm font-medium text-gray-700 mb-1">Date Range</label>
149
- <input type="text" id="projectDateRange" placeholder="e.g. Jan 2023 - Mar 2023" class="w-full border border-gray-300 rounded-md py-2 px-3 form-input focus:outline-none focus:border-blue-500">
150
  </div>
151
 
152
  <div>
153
- <label for="projectTechnologies" class="block text-sm font-medium text-gray-700 mb-1">Technologies (comma separated)</label>
154
- <input type="text" id="projectTechnologies" placeholder="e.g. React, Node.js, MongoDB" class="w-full border border-gray-300 rounded-md py-2 px-3 form-input focus:outline-none focus:border-blue-500">
155
  </div>
156
  </div>
157
 
158
  <div>
159
- <label for="projectDescription" class="block text-sm font-medium text-gray-700 mb-1">Description</label>
160
- <textarea id="projectDescription" rows="3" class="w-full border border-gray-300 rounded-md py-2 px-3 form-input focus:outline-none focus:border-blue-500"></textarea>
161
  </div>
162
 
163
  <div>
164
  <label for="projectTags" class="block text-sm font-medium text-gray-700 mb-1">Tags (comma separated)</label>
165
- <input type="text" id="projectTags" placeholder="e.g. web, mobile, api" class="w-full border border-gray-300 rounded-md py-2 px-3 form-input focus:outline-none focus:border-blue-500">
166
  </div>
167
 
168
  <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
169
  <div>
170
  <label for="projectGithub" class="block text-sm font-medium text-gray-700 mb-1">GitHub Link</label>
171
- <input type="url" id="projectGithub" class="w-full border border-gray-300 rounded-md py-2 px-3 form-input focus:outline-none focus:border-blue-500">
172
  </div>
173
 
174
  <div>
175
  <label for="projectDemo" class="block text-sm font-medium text-gray-700 mb-1">Demo Link</label>
176
- <input type="url" id="projectDemo" class="w-full border border-gray-300 rounded-md py-2 px-3 form-input focus:outline-none focus:border-blue-500">
177
  </div>
178
 
179
  <div>
180
  <label for="projectReadme" class="block text-sm font-medium text-gray-700 mb-1">README Link</label>
181
- <input type="url" id="projectReadme" class="w-full border border-gray-300 rounded-md py-2 px-3 form-input focus:outline-none focus:border-blue-500">
182
  </div>
183
  </div>
184
 
185
  <div>
186
  <label for="projectNotes" class="block text-sm font-medium text-gray-700 mb-1">Notes</label>
187
- <textarea id="projectNotes" rows="3" class="w-full border border-gray-300 rounded-md py-2 px-3 form-input focus:outline-none focus:border-blue-500"></textarea>
188
  </div>
189
 
190
  <div class="flex justify-end space-x-3 pt-4">
191
- <button type="button" id="cancelModalBtn" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors">
192
  Cancel
193
  </button>
194
- <button type="submit" id="saveProjectBtn" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors">
195
  Save Project
196
  </button>
197
  </div>
@@ -205,7 +238,7 @@
205
  <div id="detailsModal" class="fixed inset-0 z-50 hidden">
206
  <div class="modal-overlay absolute inset-0"></div>
207
  <div class="flex items-center justify-center min-h-screen">
208
- <div class="bg-white rounded-lg shadow-xl w-full max-w-2xl max-h-[90vh] overflow-y-auto m-4">
209
  <div class="p-6">
210
  <div class="flex justify-between items-center mb-4">
211
  <h3 id="detailsTitle" class="text-xl font-bold text-gray-800">Project Details</h3>
@@ -219,7 +252,10 @@
219
  </div>
220
 
221
  <div class="flex justify-end space-x-3 pt-6">
222
- <button id="editDetailsBtn" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors">
 
 
 
223
  Edit Project
224
  </button>
225
  </div>
@@ -232,7 +268,7 @@
232
  <div id="deleteModal" class="fixed inset-0 z-50 hidden">
233
  <div class="modal-overlay absolute inset-0"></div>
234
  <div class="flex items-center justify-center min-h-screen">
235
- <div class="bg-white rounded-lg shadow-xl w-full max-w-md m-4">
236
  <div class="p-6">
237
  <div class="flex justify-between items-center mb-4">
238
  <h3 class="text-xl font-bold text-gray-800">Confirm Deletion</h3>
@@ -244,10 +280,10 @@
244
  <p id="deleteMessage" class="text-gray-700 mb-6">Are you sure you want to delete this project?</p>
245
 
246
  <div class="flex justify-end space-x-3">
247
- <button id="cancelDeleteBtn" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors">
248
  Cancel
249
  </button>
250
- <button id="confirmDeleteBtn" class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 transition-colors">
251
  Delete
252
  </button>
253
  </div>
@@ -262,14 +298,14 @@
262
  {
263
  id: "1",
264
  name: "E-commerce Website",
265
- image_link: "https://images.unsplash.com/photo-1555529669-e69e7aa0ba9a?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=500&q=80",
266
  date_range: "Mar 2023 - Jun 2023",
267
  description: "A full-featured e-commerce platform with product listings, cart functionality, and payment processing.",
268
  tags: ["web", "ecommerce", "react"],
269
  github_link: "https://github.com/example/ecommerce",
270
  demo_link: "https://ecommerce.example.com",
271
  readme_link: "https://github.com/example/ecommerce/blob/main/README.md",
272
- status: "Completed",
273
  technologies: ["React", "Node.js", "MongoDB", "Stripe"],
274
  notes: "The project was completed on time and under budget. Customer satisfaction was high.",
275
  created_at: "2023-03-15T10:00:00Z",
@@ -278,14 +314,14 @@
278
  {
279
  id: "2",
280
  name: "Mobile Task Manager",
281
- image_link: "https://images.unsplash.com/photo-1512941937669-90a1b58e7e9c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=500&q=80",
282
  date_range: "Jul 2023 - Present",
283
  description: "A cross-platform mobile application for task management with sync across devices.",
284
  tags: ["mobile", "productivity", "react-native"],
285
  github_link: "https://github.com/example/task-manager",
286
  demo_link: "",
287
  readme_link: "https://github.com/example/task-manager/blob/main/README.md",
288
- status: "In Progress",
289
  technologies: ["React Native", "Firebase", "Redux"],
290
  notes: "Currently working on the offline sync functionality. Expected completion in Q4 2023.",
291
  created_at: "2023-07-01T09:15:00Z",
@@ -294,29 +330,75 @@
294
  {
295
  id: "3",
296
  name: "API Service",
297
- image_link: "https://images.unsplash.com/photo-1558494949-ef010cbdcc31?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=500&q=80",
298
  date_range: "",
299
  description: "Backend API service for data processing and integration with third-party services.",
300
  tags: ["api", "backend", "node"],
301
  github_link: "https://github.com/example/api-service",
302
  demo_link: "",
303
  readme_link: "",
304
- status: "On Hold",
305
  technologies: ["Node.js", "Express", "PostgreSQL"],
306
  notes: "Project put on hold due to shifting priorities. Will revisit in Q1 2024.",
307
  created_at: "2023-05-10T14:20:00Z",
308
  updated_at: "2023-08-01T11:10:00Z"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
309
  }
310
  ];
311
 
312
  // DOM Elements
313
  const projectsContainer = document.getElementById('projectsContainer');
314
  const emptyState = document.getElementById('emptyState');
315
- const addProjectBtn = document.getElementById('addProjectBtn');
316
  const addProjectBtnEmpty = document.getElementById('addProjectBtnEmpty');
317
- const statusFilter = document.getElementById('statusFilter');
318
- const tagFilter = document.getElementById('tagFilter');
319
- const resetFilters = document.getElementById('resetFilters');
320
 
321
  // Modal Elements
322
  const projectModal = document.getElementById('projectModal');
@@ -344,6 +426,7 @@
344
  const detailsContent = document.getElementById('detailsContent');
345
  const closeDetailsBtn = document.getElementById('closeDetailsBtn');
346
  const editDetailsBtn = document.getElementById('editDetailsBtn');
 
347
 
348
  // Delete Modal Elements
349
  const deleteModal = document.getElementById('deleteModal');
@@ -354,44 +437,29 @@
354
 
355
  // State
356
  let currentProjectId = null;
357
- let allTags = [];
 
 
358
 
359
  // Initialize the app
360
  function init() {
361
- renderProjects();
362
  setupEventListeners();
363
- updateTagFilterOptions();
364
  }
365
 
366
  // Render all projects
367
- function renderProjects() {
368
  projectsContainer.innerHTML = '';
369
 
370
- const statusFilterValue = statusFilter.value;
371
- const tagFilterValue = tagFilter.value;
372
-
373
- let filteredProjects = projects;
374
-
375
- // Apply status filter
376
- if (statusFilterValue !== 'all') {
377
- filteredProjects = filteredProjects.filter(project => project.status === statusFilterValue);
378
- }
379
-
380
- // Apply tag filter
381
- if (tagFilterValue !== 'all') {
382
- filteredProjects = filteredProjects.filter(project =>
383
- project.tags && project.tags.includes(tagFilterValue)
384
- );
385
- }
386
-
387
- if (filteredProjects.length === 0) {
388
  emptyState.classList.remove('hidden');
389
  projectsContainer.classList.add('hidden');
390
  } else {
391
  emptyState.classList.add('hidden');
392
  projectsContainer.classList.remove('hidden');
393
 
394
- filteredProjects.forEach(project => {
395
  const projectCard = createProjectCard(project);
396
  projectsContainer.appendChild(projectCard);
397
  });
@@ -401,104 +469,169 @@
401
  // Create a project card element
402
  function createProjectCard(project) {
403
  const card = document.createElement('div');
404
- card.className = 'bg-white rounded-lg shadow-md overflow-hidden card-hover fade-in relative';
405
  card.dataset.id = project.id;
406
-
407
- // Status badge with color coding
408
- let statusColor = 'bg-gray-500'; // Default for unknown status
409
- if (project.status === 'Not Started') statusColor = 'bg-gray-500';
410
- else if (project.status === 'In Progress') statusColor = 'bg-yellow-500';
411
- else if (project.status === 'Completed') statusColor = 'bg-green-500';
412
- else if (project.status === 'On Hold') statusColor = 'bg-red-500';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
413
 
414
  // Card content
415
  card.innerHTML = `
416
- <div class="relative">
417
  ${project.image_link ?
418
- `<img src="${project.image_link}" alt="${project.name}" class="w-full h-48 object-cover">` :
419
- `<div class="w-full h-48 bg-gray-200 flex items-center justify-center">
420
  <i class="fas fa-image text-4xl text-gray-400"></i>
421
  </div>`
422
  }
423
- <span class="status-badge ${statusColor} text-white">${project.status}</span>
424
  </div>
425
-
426
- <div class="p-4">
427
- <h3 class="text-lg font-semibold text-gray-800 mb-1 truncate">${project.name}</h3>
 
 
 
 
 
428
 
429
- ${project.date_range ?
430
- `<p class="text-sm text-gray-500 mb-2 flex items-center">
431
- <i class="fas fa-calendar-alt mr-2"></i>${project.date_range}
432
- </p>` : ''
 
 
 
 
433
  }
434
 
435
- <p class="text-gray-600 text-sm mb-3 line-clamp-2">${project.description || 'No description available'}</p>
436
-
437
  ${project.tags && project.tags.length > 0 ?
438
  `<div class="flex flex-wrap gap-2 mb-4">
439
  ${project.tags.map(tag => `
440
- <span class="text-xs bg-blue-100 text-blue-800 px-2 py-1 rounded-full tag-pill">${tag}</span>
 
 
441
  `).join('')}
442
  </div>` : ''
443
  }
444
 
445
- <div class="flex justify-between items-center border-t pt-3">
 
446
  <div class="flex space-x-2">
447
  ${project.github_link ? `
448
- <a href="${project.github_link}" target="_blank" class="text-gray-500 hover:text-gray-700 transition-colors" title="GitHub">
449
  <i class="fab fa-github"></i>
450
  </a>
451
  ` : ''}
452
 
453
  ${project.demo_link ? `
454
- <a href="${project.demo_link}" target="_blank" class="text-gray-500 hover:text-gray-700 transition-colors" title="Live Demo">
455
  <i class="fas fa-external-link-alt"></i>
456
  </a>
457
  ` : ''}
458
 
459
  ${project.readme_link ? `
460
- <a href="${project.readme_link}" target="_blank" class="text-gray-500 hover:text-gray-700 transition-colors" title="README">
461
  <i class="fas fa-book"></i>
462
  </a>
463
  ` : ''}
464
  </div>
465
-
466
- <div class="flex space-x-2">
467
- <button class="text-gray-500 hover:text-blue-500 transition-colors edit-btn" title="Edit">
468
- <i class="fas fa-edit"></i>
469
- </button>
470
- <button class="text-gray-500 hover:text-red-500 transition-colors delete-btn" title="Delete">
471
- <i class="fas fa-trash"></i>
472
- </button>
473
- </div>
474
  </div>
475
  </div>
476
  `;
477
 
478
  // Add click event for viewing details
479
  card.addEventListener('click', (e) => {
480
- // Don't open details if clicking on edit/delete buttons or links
481
- if (e.target.closest('.edit-btn, .delete-btn, a')) {
482
  return;
483
  }
484
  openDetailsModal(project.id);
485
  });
486
 
487
- // Add edit and delete button events
488
- const editBtn = card.querySelector('.edit-btn');
489
- const deleteBtn = card.querySelector('.delete-btn');
490
-
491
- editBtn.addEventListener('click', (e) => {
492
- e.stopPropagation();
493
- openEditModal(project.id);
 
 
 
 
 
 
 
494
  });
495
 
496
- deleteBtn.addEventListener('click', (e) => {
497
- e.stopPropagation();
498
- openDeleteModal(project.id);
499
- });
 
 
 
 
 
 
 
 
 
500
 
501
- return card;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
502
  }
503
 
504
  // Open the add project modal
@@ -526,7 +659,7 @@
526
  projectGithub.value = project.github_link || '';
527
  projectDemo.value = project.demo_link || '';
528
  projectReadme.value = project.readme_link || '';
529
- projectStatus.value = project.status || 'Not Started';
530
  projectTechnologies.value = project.technologies ? project.technologies.join(', ') : '';
531
  projectNotes.value = project.notes || '';
532
 
@@ -547,6 +680,16 @@
547
  const createdDate = project.created_at ? new Date(project.created_at).toLocaleDateString() : 'Unknown';
548
  const updatedDate = project.updated_at ? new Date(project.updated_at).toLocaleDateString() : 'Unknown';
549
 
 
 
 
 
 
 
 
 
 
 
550
  // Create details content
551
  detailsContent.innerHTML = `
552
  <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
@@ -560,12 +703,10 @@
560
  <div class="bg-gray-50 p-4 rounded-lg">
561
  <h4 class="font-medium text-gray-800 mb-2">Quick Info</h4>
562
  <div class="space-y-2">
563
- ${project.status ? `
564
- <div class="flex items-center">
565
- <span class="inline-block w-3 h-3 rounded-full mr-2 ${getStatusColorClass(project.status)}"></span>
566
- <span class="text-sm text-gray-700">Status: ${project.status}</span>
567
- </div>
568
- ` : ''}
569
 
570
  ${project.date_range ? `
571
  <div class="flex items-center text-sm text-gray-700">
@@ -630,19 +771,19 @@
630
  <h4 class="font-medium text-gray-800 mb-2">Links</h4>
631
  <div class="flex flex-wrap gap-4">
632
  ${project.github_link ? `
633
- <a href="${project.github_link}" target="_blank" class="flex items-center text-blue-600 hover:text-blue-800 transition-colors">
634
  <i class="fab fa-github mr-2"></i> GitHub Repository
635
  </a>
636
  ` : ''}
637
 
638
  ${project.demo_link ? `
639
- <a href="${project.demo_link}" target="_blank" class="flex items-center text-blue-600 hover:text-blue-800 transition-colors">
640
  <i class="fas fa-external-link-alt mr-2"></i> Live Demo
641
  </a>
642
  ` : ''}
643
 
644
  ${project.readme_link ? `
645
- <a href="${project.readme_link}" target="_blank" class="flex items-center text-blue-600 hover:text-blue-800 transition-colors">
646
  <i class="fas fa-book mr-2"></i> README
647
  </a>
648
  ` : ''}
@@ -689,6 +830,16 @@
689
  return;
690
  }
691
 
 
 
 
 
 
 
 
 
 
 
692
  // Get form values
693
  const id = projectId.value || generateId();
694
  const now = new Date().toISOString();
@@ -734,17 +885,19 @@
734
  projects.push(projectData);
735
  }
736
 
737
- // Update UI
738
- renderProjects();
739
- updateTagFilterOptions();
740
  closeAllModals();
741
  }
742
 
743
  // Delete project
744
  function deleteProject() {
745
  projects = projects.filter(p => p.id !== currentProjectId);
746
- renderProjects();
747
- updateTagFilterOptions();
 
 
748
  closeAllModals();
749
  }
750
 
@@ -753,50 +906,11 @@
753
  return Date.now().toString(36) + Math.random().toString(36).substr(2);
754
  }
755
 
756
- // Get status color class
757
- function getStatusColorClass(status) {
758
- switch (status) {
759
- case 'Not Started': return 'bg-gray-500';
760
- case 'In Progress': return 'bg-yellow-500';
761
- case 'Completed': return 'bg-green-500';
762
- case 'On Hold': return 'bg-red-500';
763
- default: return 'bg-gray-500';
764
- }
765
- }
766
-
767
- // Update tag filter options
768
- function updateTagFilterOptions() {
769
- // Collect all unique tags from projects
770
- const tagsSet = new Set();
771
- projects.forEach(project => {
772
- if (project.tags) {
773
- project.tags.forEach(tag => tagsSet.add(tag));
774
- }
775
- });
776
-
777
- allTags = Array.from(tagsSet).sort();
778
-
779
- // Update tag filter dropdown
780
- tagFilter.innerHTML = `
781
- <option value="all">All Tags</option>
782
- ${allTags.map(tag => `<option value="${tag}">${tag}</option>`).join('')}
783
- `;
784
- }
785
-
786
  // Set up event listeners
787
  function setupEventListeners() {
788
  // Add project buttons
789
- addProjectBtn.addEventListener('click', openAddModal);
790
  addProjectBtnEmpty.addEventListener('click', openAddModal);
791
-
792
- // Filter controls
793
- statusFilter.addEventListener('change', renderProjects);
794
- tagFilter.addEventListener('change', renderProjects);
795
- resetFilters.addEventListener('click', () => {
796
- statusFilter.value = 'all';
797
- tagFilter.value = 'all';
798
- renderProjects();
799
- });
800
 
801
  // Modal buttons
802
  closeModalBtn.addEventListener('click', closeAllModals);
@@ -809,6 +923,10 @@
809
  closeAllModals();
810
  openEditModal(currentProjectId);
811
  });
 
 
 
 
812
 
813
  // Delete modal buttons
814
  closeDeleteBtn.addEventListener('click', closeAllModals);
@@ -819,5 +937,6 @@
819
  // Initialize the app when DOM is loaded
820
  document.addEventListener('DOMContentLoaded', init);
821
  </script>
 
822
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=MoiMoi-01/project-manager" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
823
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Project Dashboard</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
10
+ .project-card {
11
  transition: all 0.3s ease;
12
+ transform: translateY(0);
13
  }
14
+ .project-card:hover {
15
  transform: translateY(-5px);
16
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
 
 
 
 
 
 
 
 
 
 
17
  }
18
+ .tag {
19
  transition: all 0.2s ease;
20
  }
21
+ .tag:hover {
22
  transform: scale(1.05);
23
  }
24
+ .status-badge.completed {
25
+ background-color: rgba(16, 185, 129, 0.2);
26
+ color: rgb(16, 185, 129);
27
+ }
28
+ .status-badge.in-progress {
29
+ background-color: rgba(245, 158, 11, 0.2);
30
+ color: rgb(245, 158, 11);
31
+ }
32
+ .status-badge.planned {
33
+ background-color: rgba(59, 130, 246, 0.2);
34
+ color: rgb(59, 130, 246);
35
+ }
36
+ .status-badge.on-hold {
37
+ background-color: rgba(239, 68, 68, 0.2);
38
+ color: rgb(239, 68, 68);
39
+ }
40
  .fade-in {
41
+ animation: fadeIn 0.5s ease-in-out;
42
  }
43
  @keyframes fadeIn {
44
  from { opacity: 0; transform: translateY(10px); }
 
51
  .form-input:focus {
52
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2);
53
  }
54
+ .card-expand {
55
+ transition: all 0.3s ease;
56
+ }
57
+ .card-expand:hover {
58
+ transform: scale(1.02);
59
+ }
60
+ .filter-tag {
61
+ transition: all 0.2s ease;
62
+ }
63
+ .filter-tag:hover {
64
+ transform: scale(1.05);
65
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
66
+ }
67
+ .filter-tag.active {
68
+ background-color: #6366f1;
69
+ color: white;
70
+ }
71
+ .slide-in {
72
+ animation: slideIn 0.3s ease-out forwards;
73
+ }
74
+ @keyframes slideIn {
75
+ from { transform: translateY(20px); opacity: 0; }
76
+ to { transform: translateY(0); opacity: 1; }
77
+ }
78
  </style>
79
  </head>
80
  <body class="bg-gray-50 min-h-screen">
81
+ <div class="container mx-auto px-4 py-12">
82
  <!-- Header -->
83
+ <div class="text-center mb-12">
84
+ <h1 class="text-4xl font-bold text-gray-800 mb-2">Project Dashboard</h1>
85
+ <p class="text-lg text-gray-600 max-w-2xl mx-auto">Track and manage all your projects in one place</p>
86
+
87
+ <!-- Filter Controls -->
88
+ <div class="flex flex-wrap justify-center gap-3 mt-6">
89
+ <button onclick="filterProjects('all')" class="filter-tag px-4 py-2 bg-indigo-600 text-white rounded-full hover:bg-indigo-700 transition active">
90
+ All Projects
91
+ </button>
92
+ <button onclick="filterProjects('completed')" class="filter-tag px-4 py-2 border border-gray-300 rounded-full hover:bg-gray-100 transition">
93
+ Completed
94
+ </button>
95
+ <button onclick="filterProjects('in-progress')" class="filter-tag px-4 py-2 border border-gray-300 rounded-full hover:bg-gray-100 transition">
96
+ In Progress
97
+ </button>
98
+ <button onclick="filterProjects('planned')" class="filter-tag px-4 py-2 border border-gray-300 rounded-full hover:bg-gray-100 transition">
99
+ Planned
100
+ </button>
101
+ <button onclick="filterProjects('on-hold')" class="filter-tag px-4 py-2 border border-gray-300 rounded-full hover:bg-gray-100 transition">
102
+ On Hold
103
+ </button>
104
  </div>
 
 
 
 
105
 
106
+ <!-- Technology Filter -->
107
+ <div class="mt-6">
108
+ <label for="technologyFilter" class="block text-sm font-medium text-gray-700 mb-2">Filter by Technology:</label>
109
+ <select id="technologyFilter" onchange="filterByTechnology()" class="border border-gray-300 rounded-lg py-2 px-3 focus:outline-none focus:border-indigo-500">
110
+ <option value="all">All Technologies</option>
111
+ <!-- Options will be populated dynamically -->
112
+ </select>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  </div>
114
  </div>
115
 
116
  <!-- Projects Grid -->
117
+ <div id="projectsContainer" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
118
  <!-- Project cards will be inserted here dynamically -->
119
  </div>
120
 
 
124
  <i class="fas fa-folder-open text-5xl text-gray-300 mb-4"></i>
125
  <h3 class="text-xl font-medium text-gray-700 mb-2">No projects found</h3>
126
  <p class="text-gray-500 mb-4">Add a new project or adjust your filters</p>
127
+ <button id="addProjectBtnEmpty" class="bg-indigo-600 hover:bg-indigo-700 text-white px-6 py-2 rounded-full inline-flex items-center transition">
128
  <i class="fas fa-plus mr-2"></i> Add Project
129
  </button>
130
  </div>
131
  </div>
132
+
133
+ <!-- Add Project Button -->
134
+ <div class="fixed bottom-8 right-8">
135
+ <button id="addProjectBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white w-14 h-14 rounded-full flex items-center justify-center shadow-lg transition transform hover:scale-110">
136
+ <i class="fas fa-plus text-xl"></i>
137
+ </button>
138
+ </div>
139
  </div>
140
 
141
  <!-- Add/Edit Project Modal -->
142
  <div id="projectModal" class="fixed inset-0 z-50 hidden">
143
  <div class="modal-overlay absolute inset-0"></div>
144
  <div class="flex items-center justify-center min-h-screen">
145
+ <div class="bg-white rounded-xl shadow-xl w-full max-w-2xl max-h-[90vh] overflow-y-auto m-4 card-expand slide-in">
146
  <div class="p-6">
147
  <div class="flex justify-between items-center mb-4">
148
  <h3 id="modalTitle" class="text-xl font-bold text-gray-800">Add New Project</h3>
 
157
  <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
158
  <div>
159
  <label for="projectName" class="block text-sm font-medium text-gray-700 mb-1">Project Name *</label>
160
+ <input type="text" id="projectName" required class="w-full border border-gray-300 rounded-lg py-2 px-3 form-input focus:outline-none focus:border-indigo-500">
161
  </div>
162
 
163
  <div>
164
  <label for="projectStatus" class="block text-sm font-medium text-gray-700 mb-1">Status *</label>
165
+ <select id="projectStatus" required class="w-full border border-gray-300 rounded-lg py-2 px-3 focus:outline-none focus:border-indigo-500">
166
+ <option value="planned">Planned</option>
167
+ <option value="in-progress">In Progress</option>
168
+ <option value="completed">Completed</option>
169
+ <option value="on-hold">On Hold</option>
170
  </select>
171
  </div>
172
  </div>
173
 
174
  <div>
175
  <label for="projectImage" class="block text-sm font-medium text-gray-700 mb-1">Image URL</label>
176
+ <input type="url" id="projectImage" class="w-full border border-gray-300 rounded-lg py-2 px-3 form-input focus:outline-none focus:border-indigo-500">
177
  </div>
178
 
179
  <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
180
  <div>
181
  <label for="projectDateRange" class="block text-sm font-medium text-gray-700 mb-1">Date Range</label>
182
+ <input type="text" id="projectDateRange" placeholder="e.g. Jan 2023 - Mar 2023" class="w-full border border-gray-300 rounded-lg py-2 px-3 form-input focus:outline-none focus:border-indigo-500">
183
  </div>
184
 
185
  <div>
186
+ <label for="projectTechnologies" class="block text-sm font-medium text-gray-700 mb-1">Technologies (comma separated) *</label>
187
+ <input type="text" id="projectTechnologies" required placeholder="e.g. React, Node.js, MongoDB" class="w-full border border-gray-300 rounded-lg py-2 px-3 form-input focus:outline-none focus:border-indigo-500">
188
  </div>
189
  </div>
190
 
191
  <div>
192
+ <label for="projectDescription" class="block text-sm font-medium text-gray-700 mb-1">Description *</label>
193
+ <textarea id="projectDescription" rows="3" required class="w-full border border-gray-300 rounded-lg py-2 px-3 form-input focus:outline-none focus:border-indigo-500"></textarea>
194
  </div>
195
 
196
  <div>
197
  <label for="projectTags" class="block text-sm font-medium text-gray-700 mb-1">Tags (comma separated)</label>
198
+ <input type="text" id="projectTags" placeholder="e.g. web, mobile, api" class="w-full border border-gray-300 rounded-lg py-2 px-3 form-input focus:outline-none focus:border-indigo-500">
199
  </div>
200
 
201
  <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
202
  <div>
203
  <label for="projectGithub" class="block text-sm font-medium text-gray-700 mb-1">GitHub Link</label>
204
+ <input type="url" id="projectGithub" class="w-full border border-gray-300 rounded-lg py-2 px-3 form-input focus:outline-none focus:border-indigo-500">
205
  </div>
206
 
207
  <div>
208
  <label for="projectDemo" class="block text-sm font-medium text-gray-700 mb-1">Demo Link</label>
209
+ <input type="url" id="projectDemo" class="w-full border border-gray-300 rounded-lg py-2 px-3 form-input focus:outline-none focus:border-indigo-500">
210
  </div>
211
 
212
  <div>
213
  <label for="projectReadme" class="block text-sm font-medium text-gray-700 mb-1">README Link</label>
214
+ <input type="url" id="projectReadme" class="w-full border border-gray-300 rounded-lg py-2 px-3 form-input focus:outline-none focus:border-indigo-500">
215
  </div>
216
  </div>
217
 
218
  <div>
219
  <label for="projectNotes" class="block text-sm font-medium text-gray-700 mb-1">Notes</label>
220
+ <textarea id="projectNotes" rows="3" class="w-full border border-gray-300 rounded-lg py-2 px-3 form-input focus:outline-none focus:border-indigo-500"></textarea>
221
  </div>
222
 
223
  <div class="flex justify-end space-x-3 pt-4">
224
+ <button type="button" id="cancelModalBtn" class="px-4 py-2 border border-gray-300 rounded-full text-gray-700 hover:bg-gray-50 transition">
225
  Cancel
226
  </button>
227
+ <button type="submit" id="saveProjectBtn" class="px-4 py-2 bg-indigo-600 text-white rounded-full hover:bg-indigo-700 transition">
228
  Save Project
229
  </button>
230
  </div>
 
238
  <div id="detailsModal" class="fixed inset-0 z-50 hidden">
239
  <div class="modal-overlay absolute inset-0"></div>
240
  <div class="flex items-center justify-center min-h-screen">
241
+ <div class="bg-white rounded-xl shadow-xl w-full max-w-2xl max-h-[90vh] overflow-y-auto m-4 card-expand slide-in">
242
  <div class="p-6">
243
  <div class="flex justify-between items-center mb-4">
244
  <h3 id="detailsTitle" class="text-xl font-bold text-gray-800">Project Details</h3>
 
252
  </div>
253
 
254
  <div class="flex justify-end space-x-3 pt-6">
255
+ <button id="deleteDetailsBtn" class="px-4 py-2 bg-red-600 text-white rounded-full hover:bg-red-700 transition">
256
+ Delete Project
257
+ </button>
258
+ <button id="editDetailsBtn" class="px-4 py-2 bg-indigo-600 text-white rounded-full hover:bg-indigo-700 transition">
259
  Edit Project
260
  </button>
261
  </div>
 
268
  <div id="deleteModal" class="fixed inset-0 z-50 hidden">
269
  <div class="modal-overlay absolute inset-0"></div>
270
  <div class="flex items-center justify-center min-h-screen">
271
+ <div class="bg-white rounded-xl shadow-xl w-full max-w-md m-4 card-expand slide-in">
272
  <div class="p-6">
273
  <div class="flex justify-between items-center mb-4">
274
  <h3 class="text-xl font-bold text-gray-800">Confirm Deletion</h3>
 
280
  <p id="deleteMessage" class="text-gray-700 mb-6">Are you sure you want to delete this project?</p>
281
 
282
  <div class="flex justify-end space-x-3">
283
+ <button id="cancelDeleteBtn" class="px-4 py-2 border border-gray-300 rounded-full text-gray-700 hover:bg-gray-50 transition">
284
  Cancel
285
  </button>
286
+ <button id="confirmDeleteBtn" class="px-4 py-2 bg-red-600 text-white rounded-full hover:bg-red-700 transition">
287
  Delete
288
  </button>
289
  </div>
 
298
  {
299
  id: "1",
300
  name: "E-commerce Website",
301
+ image_link: "https://images.unsplash.com/photo-1555529669-e69e7aa0ba9a?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80",
302
  date_range: "Mar 2023 - Jun 2023",
303
  description: "A full-featured e-commerce platform with product listings, cart functionality, and payment processing.",
304
  tags: ["web", "ecommerce", "react"],
305
  github_link: "https://github.com/example/ecommerce",
306
  demo_link: "https://ecommerce.example.com",
307
  readme_link: "https://github.com/example/ecommerce/blob/main/README.md",
308
+ status: "completed",
309
  technologies: ["React", "Node.js", "MongoDB", "Stripe"],
310
  notes: "The project was completed on time and under budget. Customer satisfaction was high.",
311
  created_at: "2023-03-15T10:00:00Z",
 
314
  {
315
  id: "2",
316
  name: "Mobile Task Manager",
317
+ image_link: "https://images.unsplash.com/photo-1512941937669-90a1b58e7e9c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80",
318
  date_range: "Jul 2023 - Present",
319
  description: "A cross-platform mobile application for task management with sync across devices.",
320
  tags: ["mobile", "productivity", "react-native"],
321
  github_link: "https://github.com/example/task-manager",
322
  demo_link: "",
323
  readme_link: "https://github.com/example/task-manager/blob/main/README.md",
324
+ status: "in-progress",
325
  technologies: ["React Native", "Firebase", "Redux"],
326
  notes: "Currently working on the offline sync functionality. Expected completion in Q4 2023.",
327
  created_at: "2023-07-01T09:15:00Z",
 
330
  {
331
  id: "3",
332
  name: "API Service",
333
+ image_link: "https://images.unsplash.com/photo-1558494949-ef010cbdcc31?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80",
334
  date_range: "",
335
  description: "Backend API service for data processing and integration with third-party services.",
336
  tags: ["api", "backend", "node"],
337
  github_link: "https://github.com/example/api-service",
338
  demo_link: "",
339
  readme_link: "",
340
+ status: "on-hold",
341
  technologies: ["Node.js", "Express", "PostgreSQL"],
342
  notes: "Project put on hold due to shifting priorities. Will revisit in Q1 2024.",
343
  created_at: "2023-05-10T14:20:00Z",
344
  updated_at: "2023-08-01T11:10:00Z"
345
+ },
346
+ {
347
+ id: "4",
348
+ name: "Portfolio Website",
349
+ image_link: "https://images.unsplash.com/photo-1633356122544-f134324a6cee?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80",
350
+ date_range: "Apr 2023",
351
+ description: "Personal portfolio website showcasing projects, skills, and contact information.",
352
+ tags: ["web", "portfolio", "tailwind"],
353
+ github_link: "https://github.com/example/portfolio",
354
+ demo_link: "https://portfolio.example.com",
355
+ readme_link: "https://github.com/example/portfolio/blob/main/README.md",
356
+ status: "completed",
357
+ technologies: ["HTML", "CSS", "JavaScript", "Tailwind CSS"],
358
+ notes: "Simple and clean design that highlights my work effectively.",
359
+ created_at: "2023-04-01T08:00:00Z",
360
+ updated_at: "2023-04-15T12:30:00Z"
361
+ },
362
+ {
363
+ id: "5",
364
+ name: "Weather Dashboard",
365
+ image_link: "https://images.unsplash.com/photo-1601134467661-3d775b999c8b?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80",
366
+ date_range: "Jul 2023 - Present",
367
+ description: "Interactive weather application showing current conditions and forecasts.",
368
+ tags: ["web", "weather", "api"],
369
+ github_link: "https://github.com/example/weather-app",
370
+ demo_link: "https://weather.example.com",
371
+ readme_link: "https://github.com/example/weather-app/blob/main/README.md",
372
+ status: "in-progress",
373
+ technologies: ["React", "OpenWeather API", "Chart.js"],
374
+ notes: "Currently adding historical data visualization features.",
375
+ created_at: "2023-07-10T09:30:00Z",
376
+ updated_at: "2023-08-05T15:20:00Z"
377
+ },
378
+ {
379
+ id: "6",
380
+ name: "Recipe Finder",
381
+ image_link: "https://images.unsplash.com/photo-1546069901-ba9599a7e63c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80",
382
+ date_range: "Coming Soon",
383
+ description: "Discover recipes based on ingredients you have with nutritional information.",
384
+ tags: ["mobile", "food", "api"],
385
+ github_link: "",
386
+ demo_link: "",
387
+ readme_link: "",
388
+ status: "planned",
389
+ technologies: ["React Native", "Spoonacular API"],
390
+ notes: "Planning phase - gathering requirements and designing UI.",
391
+ created_at: "2023-08-01T10:00:00Z",
392
+ updated_at: "2023-08-01T10:00:00Z"
393
  }
394
  ];
395
 
396
  // DOM Elements
397
  const projectsContainer = document.getElementById('projectsContainer');
398
  const emptyState = document.getElementById('emptyState');
 
399
  const addProjectBtnEmpty = document.getElementById('addProjectBtnEmpty');
400
+ const addProjectBtn = document.getElementById('addProjectBtn');
401
+ const technologyFilter = document.getElementById('technologyFilter');
 
402
 
403
  // Modal Elements
404
  const projectModal = document.getElementById('projectModal');
 
426
  const detailsContent = document.getElementById('detailsContent');
427
  const closeDetailsBtn = document.getElementById('closeDetailsBtn');
428
  const editDetailsBtn = document.getElementById('editDetailsBtn');
429
+ const deleteDetailsBtn = document.getElementById('deleteDetailsBtn');
430
 
431
  // Delete Modal Elements
432
  const deleteModal = document.getElementById('deleteModal');
 
437
 
438
  // State
439
  let currentProjectId = null;
440
+ let currentFilter = 'all';
441
+ let currentTechnologyFilter = 'all';
442
+ let allTechnologies = [];
443
 
444
  // Initialize the app
445
  function init() {
446
+ renderProjects(projects);
447
  setupEventListeners();
448
+ updateTechnologyFilter();
449
  }
450
 
451
  // Render all projects
452
+ function renderProjects(projectsToRender) {
453
  projectsContainer.innerHTML = '';
454
 
455
+ if (projectsToRender.length === 0) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
456
  emptyState.classList.remove('hidden');
457
  projectsContainer.classList.add('hidden');
458
  } else {
459
  emptyState.classList.add('hidden');
460
  projectsContainer.classList.remove('hidden');
461
 
462
+ projectsToRender.forEach(project => {
463
  const projectCard = createProjectCard(project);
464
  projectsContainer.appendChild(projectCard);
465
  });
 
469
  // Create a project card element
470
  function createProjectCard(project) {
471
  const card = document.createElement('div');
472
+ card.className = 'project-card bg-white rounded-xl overflow-hidden shadow-md hover:shadow-lg fade-in';
473
  card.dataset.id = project.id;
474
+ card.dataset.status = project.status;
475
+ card.dataset.technologies = project.technologies ? project.technologies.join(',') : '';
476
+
477
+ // Determine status text and styling
478
+ let statusText, statusClass;
479
+ switch(project.status) {
480
+ case 'completed':
481
+ statusText = 'Completed';
482
+ statusClass = 'completed';
483
+ break;
484
+ case 'in-progress':
485
+ statusText = 'In Progress';
486
+ statusClass = 'in-progress';
487
+ break;
488
+ case 'planned':
489
+ statusText = 'Planned';
490
+ statusClass = 'planned';
491
+ break;
492
+ case 'on-hold':
493
+ statusText = 'On Hold';
494
+ statusClass = 'on-hold';
495
+ break;
496
+ }
497
 
498
  // Card content
499
  card.innerHTML = `
500
+ <div class="h-48 overflow-hidden">
501
  ${project.image_link ?
502
+ `<img src="${project.image_link}" alt="${project.name}" class="w-full h-full object-cover">` :
503
+ `<div class="w-full h-full bg-gray-200 flex items-center justify-center">
504
  <i class="fas fa-image text-4xl text-gray-400"></i>
505
  </div>`
506
  }
 
507
  </div>
508
+ <div class="p-6">
509
+ <div class="flex justify-between items-start mb-2">
510
+ <h3 class="text-xl font-semibold text-gray-800">${project.name}</h3>
511
+ <span class="status-badge ${statusClass} text-xs font-medium px-2.5 py-0.5 rounded-full">
512
+ ${statusText}
513
+ </span>
514
+ </div>
515
+ <p class="text-gray-600 text-sm mb-4">${project.description || 'No description available'}</p>
516
 
517
+ ${project.technologies && project.technologies.length > 0 ?
518
+ `<div class="flex flex-wrap gap-2 mb-2">
519
+ ${project.technologies.map(tech => `
520
+ <span class="tag text-xs bg-purple-100 text-purple-800 px-2 py-1 rounded-full">
521
+ ${tech}
522
+ </span>
523
+ `).join('')}
524
+ </div>` : ''
525
  }
526
 
 
 
527
  ${project.tags && project.tags.length > 0 ?
528
  `<div class="flex flex-wrap gap-2 mb-4">
529
  ${project.tags.map(tag => `
530
+ <span class="tag text-xs bg-gray-100 text-gray-800 px-2 py-1 rounded-full">
531
+ ${tag}
532
+ </span>
533
  `).join('')}
534
  </div>` : ''
535
  }
536
 
537
+ <div class="flex justify-between items-center text-sm text-gray-500">
538
+ <span>${project.date_range || 'No date specified'}</span>
539
  <div class="flex space-x-2">
540
  ${project.github_link ? `
541
+ <a href="${project.github_link}" target="_blank" class="text-gray-700 hover:text-gray-900 transition" title="GitHub">
542
  <i class="fab fa-github"></i>
543
  </a>
544
  ` : ''}
545
 
546
  ${project.demo_link ? `
547
+ <a href="${project.demo_link}" target="_blank" class="text-gray-700 hover:text-gray-900 transition" title="Live Demo">
548
  <i class="fas fa-external-link-alt"></i>
549
  </a>
550
  ` : ''}
551
 
552
  ${project.readme_link ? `
553
+ <a href="${project.readme_link}" target="_blank" class="text-gray-700 hover:text-gray-900 transition" title="README">
554
  <i class="fas fa-book"></i>
555
  </a>
556
  ` : ''}
557
  </div>
 
 
 
 
 
 
 
 
 
558
  </div>
559
  </div>
560
  `;
561
 
562
  // Add click event for viewing details
563
  card.addEventListener('click', (e) => {
564
+ // Don't open details if clicking on links
565
+ if (e.target.closest('a')) {
566
  return;
567
  }
568
  openDetailsModal(project.id);
569
  });
570
 
571
+ return card;
572
+ }
573
+
574
+ // Filter projects by status
575
+ function filterProjects(status) {
576
+ currentFilter = status;
577
+
578
+ // Update active filter button
579
+ document.querySelectorAll('.filter-tag').forEach(btn => {
580
+ btn.classList.remove('active', 'bg-indigo-600', 'text-white');
581
+ if ((status === 'all' && btn.textContent.trim() === 'All Projects') ||
582
+ (status !== 'all' && btn.textContent.trim() === status.charAt(0).toUpperCase() + status.slice(1))) {
583
+ btn.classList.add('active', 'bg-indigo-600', 'text-white');
584
+ }
585
  });
586
 
587
+ // Apply both status and technology filters
588
+ applyFilters();
589
+ }
590
+
591
+ // Filter projects by technology
592
+ function filterByTechnology() {
593
+ currentTechnologyFilter = technologyFilter.value;
594
+ applyFilters();
595
+ }
596
+
597
+ // Apply both status and technology filters
598
+ function applyFilters() {
599
+ let filteredProjects = projects;
600
 
601
+ // Apply status filter
602
+ if (currentFilter !== 'all') {
603
+ filteredProjects = filteredProjects.filter(project => project.status === currentFilter);
604
+ }
605
+
606
+ // Apply technology filter
607
+ if (currentTechnologyFilter !== 'all') {
608
+ filteredProjects = filteredProjects.filter(project =>
609
+ project.technologies && project.technologies.includes(currentTechnologyFilter)
610
+ );
611
+ }
612
+
613
+ renderProjects(filteredProjects);
614
+ }
615
+
616
+ // Update technology filter dropdown with unique technologies
617
+ function updateTechnologyFilter() {
618
+ // Get all unique technologies from projects
619
+ allTechnologies = [...new Set(
620
+ projects.flatMap(project => project.technologies || [])
621
+ )].sort();
622
+
623
+ // Clear existing options except "All Technologies"
624
+ while (technologyFilter.options.length > 1) {
625
+ technologyFilter.remove(1);
626
+ }
627
+
628
+ // Add technology options
629
+ allTechnologies.forEach(tech => {
630
+ const option = document.createElement('option');
631
+ option.value = tech;
632
+ option.textContent = tech;
633
+ technologyFilter.appendChild(option);
634
+ });
635
  }
636
 
637
  // Open the add project modal
 
659
  projectGithub.value = project.github_link || '';
660
  projectDemo.value = project.demo_link || '';
661
  projectReadme.value = project.readme_link || '';
662
+ projectStatus.value = project.status || 'planned';
663
  projectTechnologies.value = project.technologies ? project.technologies.join(', ') : '';
664
  projectNotes.value = project.notes || '';
665
 
 
680
  const createdDate = project.created_at ? new Date(project.created_at).toLocaleDateString() : 'Unknown';
681
  const updatedDate = project.updated_at ? new Date(project.updated_at).toLocaleDateString() : 'Unknown';
682
 
683
+ // Determine status styling
684
+ let statusClass;
685
+ switch(project.status) {
686
+ case 'completed': statusClass = 'completed'; break;
687
+ case 'in-progress': statusClass = 'in-progress'; break;
688
+ case 'planned': statusClass = 'planned'; break;
689
+ case 'on-hold': statusClass = 'on-hold'; break;
690
+ default: statusClass = '';
691
+ }
692
+
693
  // Create details content
694
  detailsContent.innerHTML = `
695
  <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
 
703
  <div class="bg-gray-50 p-4 rounded-lg">
704
  <h4 class="font-medium text-gray-800 mb-2">Quick Info</h4>
705
  <div class="space-y-2">
706
+ <div class="flex items-center">
707
+ <span class="inline-block w-3 h-3 rounded-full mr-2 ${statusClass}"></span>
708
+ <span class="text-sm text-gray-700">Status: ${project.status}</span>
709
+ </div>
 
 
710
 
711
  ${project.date_range ? `
712
  <div class="flex items-center text-sm text-gray-700">
 
771
  <h4 class="font-medium text-gray-800 mb-2">Links</h4>
772
  <div class="flex flex-wrap gap-4">
773
  ${project.github_link ? `
774
+ <a href="${project.github_link}" target="_blank" class="flex items-center text-blue-600 hover:text-blue-800 transition">
775
  <i class="fab fa-github mr-2"></i> GitHub Repository
776
  </a>
777
  ` : ''}
778
 
779
  ${project.demo_link ? `
780
+ <a href="${project.demo_link}" target="_blank" class="flex items-center text-blue-600 hover:text-blue-800 transition">
781
  <i class="fas fa-external-link-alt mr-2"></i> Live Demo
782
  </a>
783
  ` : ''}
784
 
785
  ${project.readme_link ? `
786
+ <a href="${project.readme_link}" target="_blank" class="flex items-center text-blue-600 hover:text-blue-800 transition">
787
  <i class="fas fa-book mr-2"></i> README
788
  </a>
789
  ` : ''}
 
830
  return;
831
  }
832
 
833
+ if (!projectDescription.value.trim()) {
834
+ alert('Project description is required');
835
+ return;
836
+ }
837
+
838
+ if (!projectTechnologies.value.trim()) {
839
+ alert('At least one technology is required');
840
+ return;
841
+ }
842
+
843
  // Get form values
844
  const id = projectId.value || generateId();
845
  const now = new Date().toISOString();
 
885
  projects.push(projectData);
886
  }
887
 
888
+ // Update UI and filters
889
+ updateTechnologyFilter();
890
+ applyFilters();
891
  closeAllModals();
892
  }
893
 
894
  // Delete project
895
  function deleteProject() {
896
  projects = projects.filter(p => p.id !== currentProjectId);
897
+
898
+ // Update UI and filters
899
+ updateTechnologyFilter();
900
+ applyFilters();
901
  closeAllModals();
902
  }
903
 
 
906
  return Date.now().toString(36) + Math.random().toString(36).substr(2);
907
  }
908
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
909
  // Set up event listeners
910
  function setupEventListeners() {
911
  // Add project buttons
 
912
  addProjectBtnEmpty.addEventListener('click', openAddModal);
913
+ addProjectBtn.addEventListener('click', openAddModal);
 
 
 
 
 
 
 
 
914
 
915
  // Modal buttons
916
  closeModalBtn.addEventListener('click', closeAllModals);
 
923
  closeAllModals();
924
  openEditModal(currentProjectId);
925
  });
926
+ deleteDetailsBtn.addEventListener('click', () => {
927
+ closeAllModals();
928
+ openDeleteModal(currentProjectId);
929
+ });
930
 
931
  // Delete modal buttons
932
  closeDeleteBtn.addEventListener('click', closeAllModals);
 
937
  // Initialize the app when DOM is loaded
938
  document.addEventListener('DOMContentLoaded', init);
939
  </script>
940
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=JamesToth/project-manager-app" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p>
941
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=MoiMoi-01/project-manager" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
942
  </html>
prompts.txt CHANGED
@@ -0,0 +1,2 @@
 
 
 
1
+ Make it look like this visually and add animations : <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Project 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> .project-card { transition: all 0.3s ease; transform: translateY(0); } .project-card: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); } .tag { transition: all 0.2s ease; } .tag:hover { transform: scale(1.05); } .status-badge.completed { background-color: #10b98120; color: #10b981; } .status-badge.in-progress { background-color: #f59e0b20; color: #f59e0b; } .status-badge.planned { background-color: #3b82f620; color: #3b82f6; } </style> </head> <body class="bg-gray-50 min-h-screen"> <div class="container mx-auto px-4 py-12"> <!-- Header --> <div class="text-center mb-12"> <h1 class="text-4xl font-bold text-gray-800 mb-2">My Projects</h1> <p class="text-lg text-gray-600 max-w-2xl mx-auto">A collection of my recent work, experiments, and contributions</p> <!-- Filter Controls --> <div class="flex flex-wrap justify-center gap-3 mt-6"> <button onclick="filterProjects('all')" class="px-4 py-2 bg-indigo-600 text-white rounded-full hover:bg-indigo-700 transition">All Projects</button> <button onclick="filterProjects('completed')" class="px-4 py-2 border border-gray-300 rounded-full hover:bg-gray-100 transition">Completed</button> <button onclick="filterProjects('in-progress')" class="px-4 py-2 border border-gray-300 rounded-full hover:bg-gray-100 transition">In Progress</button> <button onclick="filterProjects('planned')" class="px-4 py-2 border border-gray-300 rounded-full hover:bg-gray-100 transition">Planned</button> </div> </div> <!-- Projects Grid --> <div id="projects-container" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"> <!-- Projects will be dynamically inserted here --> </div> </div> <script> // Sample project data const projects = [ { id: 1, title: "E-commerce Platform", description: "A full-stack e-commerce solution with payment integration, inventory management, and analytics dashboard.", image: "https://images.unsplash.com/photo-1555529669-e69e7aa0ba9a?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80", status: "completed", tags: ["React", "Node.js", "MongoDB", "Stripe"], github: "https://github.com", demo: "https://example.com", date: "Jun 2023" }, { id: 2, title: "Task Management App", description: "Collaborative task management application with real-time updates, team assignments, and progress tracking.", image: "https://images.unsplash.com/photo-1541462608143-67571c6738dd?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80", status: "in-progress", tags: ["Vue.js", "Firebase", "Tailwind CSS"], github: "https://github.com", demo: null, date: "Aug 2023 - Present" }, { id: 3, title: "Health & Fitness Tracker", description: "Mobile application for tracking workouts, nutrition, and health metrics with personalized recommendations.", image: "https://images.unsplash.com/photo-1571019613454-1cb2f99b2d8b?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80", status: "planned", tags: ["React Native", "GraphQL", "PostgreSQL"], github: null, demo: null, date: "Coming Soon" }, { id: 4, title: "Portfolio Website", description: "Personal portfolio website showcasing projects, skills, and contact information with a clean, modern design.", image: "https://images.unsplash.com/photo-1633356122544-f134324a6cee?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80", status: "completed", tags: ["HTML", "CSS", "JavaScript"], github: "https://github.com", demo: "https://example.com", date: "Apr 2023" }, { id: 5, title: "Weather Dashboard", description: "Interactive weather application showing current conditions, forecasts, and historical data visualization.", image: "https://images.unsplash.com/photo-1601134467661-3d775b999c8b?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80", status: "in-progress", tags: ["React", "OpenWeather API", "Chart.js"], github: "https://github.com", demo: "https://example.com", date: "Jul 2023 - Present" }, { id: 6, title: "Recipe Finder", description: "Discover recipes based on ingredients you have, with nutritional information and step-by-step instructions.", image: "https://images.unsplash.com/photo-1546069901-ba9599a7e63c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80", status: "planned", tags: ["Angular", "Spoonacular API", "Bootstrap"], github: null, demo: null, date: "Coming Soon" } ]; // Render all projects initially document.addEventListener('DOMContentLoaded', () => { renderProjects(projects); }); // Function to render projects function renderProjects(projectsToRender) { const container = document.getElementById('projects-container'); container.innerHTML = ''; projectsToRender.forEach(project => { const projectCard = document.createElement('div'); projectCard.className = 'project-card bg-white rounded-xl overflow-hidden shadow-md hover:shadow-lg'; // Determine status text and styling let statusText, statusClass; switch(project.status) { case 'completed': statusText = 'Completed'; statusClass = 'completed'; break; case 'in-progress': statusText = 'In Progress'; statusClass = 'in-progress'; break; case 'planned': statusText = 'Planned'; statusClass = 'planned'; break; } projectCard.innerHTML = ` <div class="h-48 overflow-hidden"> <img src="${project.image}" alt="${project.title}" class="w-full h-full object-cover"> </div> <div class="p-6"> <div class="flex justify-between items-start mb-2"> <h3 class="text-xl font-semibold text-gray-800">${project.title}</h3> <span class="status-badge ${statusClass} text-xs font-medium px-2.5 py-0.5 rounded-full"> ${statusText} </span> </div> <p class="text-gray-600 text-sm mb-4">${project.description}</p> <div class="flex flex-wrap gap-2 mb-4"> ${project.tags.map(tag => ` <span class="tag text-xs bg-gray-100 text-gray-800 px-3 py-1 rounded-full"> ${tag} </span> `).join('')} </div> <div class="flex justify-between items-center text-sm text-gray-500"> <span>${project.date}</span> <div class="flex space-x-2"> ${project.github ? ` <a href="${project.github}" target="_blank" class="text-gray-700 hover:text-gray-900 transition"> <i class="fab fa-github"></i> </a> ` : ''} ${project.demo ? ` <a href="${project.demo}" target="_blank" class="text-gray-700 hover:text-gray-900 transition"> <i class="fas fa-external-link-alt"></i> </a> ` : ''} </div> </div> </div> `; container.appendChild(projectCard); }); } // Filter projects by status function filterProjects(status) { if (status === 'all') { renderProjects(projects); } else { const filteredProjects = projects.filter(project => project.status === status); renderProjects(filteredProjects); } } </script> <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=JamesToth/project-manager-app" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> </html>
2
+ check and add these features : Okay, I will update the PRD to reflect the exact list of project information fields you specified for the JSON structure, plus include the additional relevant fields from our previous iteration. Here is the revised PRD: --- ## Product Requirements Document: Simple Project Manager App (Card View) **Version:** 1.2 **Date:** May 19, 2025 **Prepared By:** [Your Name/Team Name] --- ### 1. Introduction #### 1.1 Purpose The purpose of this document is to define the requirements for a simple Project Manager App that visualizes projects as interactive cards. The application will utilize HTML, CSS (specifically Tailwind CSS for styling), and JavaScript to provide core functionalities to add, view, edit, and delete project entries. Project data will be stored and managed in a JSON format, capturing specific details including project ID, name, image link, date range, description, tags, GitHub link, demo link, README link, and other relevant metadata. #### 1.2 Goals * Provide a visually appealing dashboard displaying projects as distinct cards, populated with data from a JSON source. * Enable users to easily record and view a specific set of key details for each project on its card or in a detail view. * Allow users to update project information using an editing mechanism that modifies the JSON data. * Provide the ability to remove project entries from the JSON data structure. * Leverage modern web technologies (HTML, Tailwind CSS, JavaScript) for a responsive and dynamic user interface. * Manage project data using a structured JSON format with defined fields. #### 1.3 Target Audience Individuals or small teams who need a simple, personal, web-based tool to track multiple projects, preferring a visual card-based overview and a lightweight technical implementation using standard web technologies and a defined JSON data structure. ### 2. Features #### 2.1 Core Features ##### 2.1.1 Data Structure & Storage (JSON) * **Description:** The application will manage all project data using a consistent JSON structure, where each project is an object with specific keys (fields). * **Functionality:** The application will define and adhere to the following JSON structure for each project object: * `id`: Unique identifier (string or number) * `name`: Project name (string) * `image_link`: URL to a project image/thumbnail (string) * `date_range`: String representing the duration of the project (e.g., "Jan 2023 - Mar 2023", "2 Weeks") (string) * `description`: Short project description (string) * `tags`: Array of strings representing keywords or technologies (array of strings) * `github_link`: URL to the GitHub repository (string) * `demo_link`: URL to a live demo or deployment (string) * `readme_link`: URL to the project's README file (string) * `status`: Current status (e.g., "Not Started", "In Progress", "Completed", "On Hold") (string) * `technologies`: Array of strings representing the technology stack used (array of strings) * `notes`: Additional notes or details (string) * `created_at`: Timestamp of when the project was added (string/timestamp format) * `updated_at`: Timestamp of when the project was last updated (string/timestamp format) * **Data Source:** Project data shall be loaded from a designated JSON source (e.g., a local file served statically, or a simple API endpoint) upon application load. ##### 2.1.2 View Projects as Cards (Dynamic Rendering) * **Description:** Projects fetched from the JSON data will be dynamically rendered as visually distinct cards on a dashboard based on their fields. * **Functionality:** * JavaScript will read the project data from the loaded JSON array of objects. * For each project object, JavaScript will generate the necessary HTML structure for a project card, populating elements with data from the corresponding JSON fields. * These generated project cards will be injected into a container element in the HTML. * **Card Design:** Each card shall display the following details pulled from the JSON data: * Project Image (using `image_link`) * Project Title (`name`) * Status Badge (`status` - color-coded, e.g., Green for Completed, Yellow for In Progress) * Short Description (`description` - potentially truncated) * List of Tags (`tags` - styled as pills/badges) * Links (Icons/Buttons) for GitHub (`github_link`), Live Demo (`demo_link`), and README (`readme_link`), if available. * **Layout:** Cards will be arranged in a responsive grid using Tailwind CSS classes: * 1 column on small screens (mobile) * 2 columns on medium screens (tablets) * 3 or more columns on large screens (desktops) ##### 2.1.3 Add Project * **Description:** Users shall be able to add a new project entry which will be appended to the JSON data structure. * **Functionality:** * A user interface (e.g., a form or modal) will be provided to input details for a new project, covering all fields defined in the JSON structure (though some may be optional). * Upon submission, JavaScript will create a new project object based on the input, automatically generating a unique `id` and setting `created_at` and `updated_at` timestamps. * The new project object will be added to the in-memory project data array. * The UI will refresh to display the newly added project card. * A mechanism is required to save the updated JSON data back to the source (see Scope). ##### 2.1.4 Edit Project * **Description:** Users shall be able to modify the details of an existing project, updating the corresponding object in the JSON data structure. * **Functionality:** * Each project card will have an option (e.g., an edit button or clicking the card) to open an editing interface (form or modal). * The editing interface will be pre-populated with the current details of the selected project, pulled from its JSON object. * Users can modify any of the editable project fields. * Upon saving, JavaScript will update the specific project object in the in-memory data array based on its unique `id`, and update the `updated_at` timestamp. * The specific project card or the entire UI will refresh to show the updated details. * A mechanism is required to save the updated JSON data back to the source (see Scope). ##### 2.1.5 Delete Project * **Description:** Users shall be able to remove a project entry, deleting the corresponding object from the JSON data structure. * **Functionality:** * Each project card will have an option (e.g., a delete button). * Clicking delete will prompt a confirmation dialog (`FR12`). * Upon confirmation, JavaScript will remove the specific project object (identified by its `id`) from the in-memory data array. * The specific project card will be removed from the UI. * A mechanism is required to save the updated JSON data back to the source (see Scope). #### 2.2 Optional Interactivity Features * **Filtering:** Add controls (buttons, dropdowns) to filter the displayed cards based on criteria like `tags`, `technologies`, or `status`. * **Detail View:** Clicking a card could open a modal or navigate to a separate view to display full details, potentially including fields not shown on the collapsed card view and offering the Edit/Delete options there. ### 3. User Stories * As a user, I want to see all my projects displayed as clear, visual cards populated with specific details like name, image, description, and status, so I can quickly get an overview. * As a user, I want the project cards to show relevant links like GitHub, Demo, and README directly so I can access them easily. * As a user, I want to add a new project by filling out a form that includes fields for name, image link, date range, description, tags, and all the links (GitHub, demo, readme), so it's stored with all its details. * As a user, I want to update any detail of an existing project, such as changing the status, description, or links, using an edit function on the card. * As a user, I want to delete a project card and its associated data from my list when it's no longer needed, after confirming my action. * As a user, I want the project cards to arrange themselves in a responsive grid layout that looks good on my phone, tablet, and desktop. * As a user, I want the project status to be clearly visible and potentially color-coded on the card. * (Optional) As a user, I want to be able to filter the projects displayed based on the tags or technologies used. * (Optional) As a user, when I click a card, I want to see all the project details, including notes and dates, in a popup or separate screen. ### 4. Requirements #### 4.1 Functional Requirements * FR1: The application shall load project data from a JSON source following the specified structure upon initialization. * FR2: The application shall store project data in a JavaScript array containing objects that conform to the specified JSON structure. * FR3: The application shall dynamically generate and display HTML project cards based on the data in the JavaScript array using the specified JSON fields. * FR4: Each project card shall display the `name`, `image_link`, `status` (visually indicated), `description` (potentially truncated), `tags`, `github_link` (if available), `demo_link` (if available), and `readme_link` (if available). * FR5: The application shall provide an interface (form/modal) to input details for a new project, including fields: `name`, `image_link`, `date_range`, `description`, `tags`, `github_link`, `demo_link`, `readme_link`, `status`, `technologies`, `notes`. * FR6: Adding a new project shall create a new object in the in-memory JavaScript array conforming to the specified structure. * FR7: A unique `id` shall be automatically generated for each new project. * FR8: `created_at` and `updated_at` timestamps shall be automatically recorded upon project creation. * FR9: The application shall provide an interface (form/modal) to edit the details of an existing project, pre-populating fields from the selected project object. * FR10: Editing a project shall update the corresponding object in the in-memory JavaScript array based on its `id`. * FR11: The `updated_at` timestamp shall be updated when a project is edited. * FR12: Deleting a project shall remove the corresponding object from the in-memory JavaScript array based on its `id`. * FR13: The application shall update the UI (add/edit/remove cards) to reflect changes in the in-memory data array without a full page reload. * FR14: The application shall prompt the user for confirmation before deleting a project. * FR15: The `id` and `name` fields shall be considered mandatory upon project creation via the Add interface. * FR16: (Optional) The application shall provide controls to filter the displayed project cards based on specified criteria (`tags`, `status`, `technologies`). * FR17: (Optional) Clicking a project card shall display additional details (`date_range`, `technologies`, `notes`, `created_at`, `updated_at`) in a modal or separate view, and potentially include the edit/delete options there. #### 4.2 Non-Functional Requirements * NFR1: **Usability:** The card-based dashboard and editing/adding interfaces should be intuitive and easy for users to understand and operate. * NFR2: **Performance:** The application should load and render project cards efficiently, ideally showing a quick initial load and smooth updates for a moderate number of projects. * NFR3: **Responsiveness:** The application layout, particularly the project card grid, shall adapt gracefully to different screen sizes (mobile, tablet, desktop) using Tailwind CSS. * NFR4: **Maintainability:** The code structure (HTML, CSS, JavaScript) should be organized and well-commented to allow for easy maintenance and future enhancements. Tailwind CSS class usage should be consistent. * NFR5: **Data Integrity:** While the persistence mechanism is scoped separately, the in-memory management of the JSON array must ensure data is correctly added, updated, and deleted within the application session according to the defined structure. * NFR6: **Aesthetics:** The visual design, leveraging Tailwind CSS, should be clean, modern, and visually appealing, including consistent spacing, typography, shadows, and hover effects on cards. Status badges should be clearly distinguishable. * NFR7: **Data Structure Adherence:** The application's logic for reading, writing, and manipulating data must strictly adhere to the defined JSON field names and expected data types. ### 5. Scope #### 5.1 In Scope * Defining and using the specified JSON structure for project data (`id`, `name`, `image_link`, `date_range`, `description`, `tags`, `github_link`, `demo_link`, `readme_link`, `status`, `technologies`, `notes`, `created_at`, `updated_at`). * Loading project data from a JSON source at application startup into a JavaScript array. * Dynamically rendering project data as responsive cards using HTML, Tailwind CSS, and JavaScript, displaying the relevant fields on the cards. * Implementing the responsive grid layout for project cards using Tailwind CSS. * Functionality to Add, Edit, and Delete project objects within the *in-memory* JavaScript data array, updating the specified fields. * Generating unique `id` and timestamps (`created_at`, `updated_at`) for new projects and updating `updated_at` on edits. * Basic validation for mandatory fields (`id`, `name`). * (Optional) Implementation of filtering controls based on specified criteria and/or a detailed view modal displaying all fields. * Utilizing Tailwind CSS for all styling requirements. #### 5.2 Out of Scope * **Persistence Mechanism:** The specific implementation of *saving* the modified JSON data from the in-memory array back to a persistent source (e.g., writing to a local file, integrating with a backend API). This PRD defines the *in-memory* manipulation and the data structure, but the saving/loading process outside of the initial load needs to be designed and implemented separately based on the deployment environment. * User authentication or multi-user support. * Advanced querying, sorting (beyond basic display order from JSON), or reporting features. * Real-time collaboration or data synchronization across multiple users/devices. * Integrated task management within projects. * Complex data validation or robust error handling (e.g., handling network errors on fetch, malformed JSON). * Unit or integration testing. ### 6. Success Metrics * **JSON Structure Compliance:** The application successfully loads and processes JSON data conforming to the specified structure. * **Dynamic Rendering Accuracy:** Project cards are correctly generated and populated with data from the JSON fields. * **Responsiveness:** The grid layout correctly adapts across target device screen sizes. * **Core Feature Functionality:** Add, Edit, and Delete operations successfully manipulate the project objects in the in-memory JSON array and update the UI accordingly. * **Data Field Adherence:** All specified JSON fields are correctly handled during data loading, display, adding, and editing. * (If Persistence Added): Successful saving and loading of changes to/from the persistent JSON source across application sessions. ### 7. Future Considerations (Potential Future Features) * Implementation of a persistence layer (e.g., using Local Storage for simple local apps, or integrating with a backend API) to save changes permanently. * Advanced filtering, sorting, and search functionality across all specified fields. * Expanding the detail view or modal to allow inline editing. * Options for different visual layouts (e.g., list view). * Implementing pagination or infinite scrolling for large project lists. * Basic data export (e.g., download modified JSON). * More robust input validation and user feedback during Add/Edit operations. ---