Spaces:
Running
Running
Add 2 files
Browse files- index.html +334 -215
- 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
|
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
|
11 |
transition: all 0.3s ease;
|
|
|
12 |
}
|
13 |
-
.card
|
14 |
transform: translateY(-5px);
|
15 |
-
box-shadow: 0
|
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
|
28 |
transition: all 0.2s ease;
|
29 |
}
|
30 |
-
.tag
|
31 |
transform: scale(1.05);
|
32 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
.fade-in {
|
34 |
-
animation: fadeIn 0.
|
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-
|
51 |
<!-- Header -->
|
52 |
-
<
|
53 |
-
<
|
54 |
-
|
55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
63 |
-
|
64 |
-
|
65 |
-
<
|
66 |
-
<
|
67 |
-
|
68 |
-
|
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-
|
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-
|
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-
|
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-
|
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-
|
133 |
-
<option value="
|
134 |
-
<option value="
|
135 |
-
<option value="
|
136 |
-
<option value="
|
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-
|
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-
|
150 |
</div>
|
151 |
|
152 |
<div>
|
153 |
-
<label for="projectTechnologies" class="block text-sm font-medium text-gray-700 mb-1">Technologies (comma separated)
|
154 |
-
<input type="text" id="projectTechnologies" placeholder="e.g. React, Node.js, MongoDB" class="w-full border border-gray-300 rounded-
|
155 |
</div>
|
156 |
</div>
|
157 |
|
158 |
<div>
|
159 |
-
<label for="projectDescription" class="block text-sm font-medium text-gray-700 mb-1">Description
|
160 |
-
<textarea id="projectDescription" rows="3" class="w-full border border-gray-300 rounded-
|
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-
|
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-
|
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-
|
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-
|
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-
|
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-
|
192 |
Cancel
|
193 |
</button>
|
194 |
-
<button type="submit" id="saveProjectBtn" class="px-4 py-2 bg-
|
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-
|
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="
|
|
|
|
|
|
|
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-
|
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-
|
248 |
Cancel
|
249 |
</button>
|
250 |
-
<button id="confirmDeleteBtn" class="px-4 py-2 bg-red-600 text-white rounded-
|
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=
|
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: "
|
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=
|
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: "
|
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=
|
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: "
|
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
|
318 |
-
const
|
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
|
|
|
|
|
358 |
|
359 |
// Initialize the app
|
360 |
function init() {
|
361 |
-
renderProjects();
|
362 |
setupEventListeners();
|
363 |
-
|
364 |
}
|
365 |
|
366 |
// Render all projects
|
367 |
-
function renderProjects() {
|
368 |
projectsContainer.innerHTML = '';
|
369 |
|
370 |
-
|
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 |
-
|
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-
|
405 |
card.dataset.id = project.id;
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
413 |
|
414 |
// Card content
|
415 |
card.innerHTML = `
|
416 |
-
<div class="
|
417 |
${project.image_link ?
|
418 |
-
`<img src="${project.image_link}" alt="${project.name}" class="w-full h-
|
419 |
-
`<div class="w-full h-
|
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 |
-
|
427 |
-
|
|
|
|
|
|
|
|
|
|
|
428 |
|
429 |
-
${project.
|
430 |
-
`<
|
431 |
-
|
432 |
-
|
|
|
|
|
|
|
|
|
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-
|
|
|
|
|
441 |
`).join('')}
|
442 |
</div>` : ''
|
443 |
}
|
444 |
|
445 |
-
<div class="flex justify-between items-center
|
|
|
446 |
<div class="flex space-x-2">
|
447 |
${project.github_link ? `
|
448 |
-
<a href="${project.github_link}" target="_blank" class="text-gray-
|
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-
|
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-
|
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
|
481 |
-
if (e.target.closest('
|
482 |
return;
|
483 |
}
|
484 |
openDetailsModal(project.id);
|
485 |
});
|
486 |
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
494 |
});
|
495 |
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
500 |
|
501 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 || '
|
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 |
-
|
564 |
-
<
|
565 |
-
|
566 |
-
|
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
|
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
|
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
|
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 |
-
|
739 |
-
|
740 |
closeAllModals();
|
741 |
}
|
742 |
|
743 |
// Delete project
|
744 |
function deleteProject() {
|
745 |
projects = projects.filter(p => p.id !== currentProjectId);
|
746 |
-
|
747 |
-
|
|
|
|
|
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. ---
|