|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Vibe Coding | HTML5 User Environment</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> |
|
|
.kanban-column { |
|
|
min-height: 500px; |
|
|
background-color: rgba(243, 244, 246, 0.5); |
|
|
} |
|
|
.card { |
|
|
transition: all 0.2s ease; |
|
|
} |
|
|
.card:hover { |
|
|
transform: translateY(-2px); |
|
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); |
|
|
} |
|
|
.annotation-marker { |
|
|
position: absolute; |
|
|
width: 16px; |
|
|
height: 16px; |
|
|
background-color: #3B82F6; |
|
|
border-radius: 50%; |
|
|
border: 2px solid white; |
|
|
cursor: pointer; |
|
|
transform: translate(-50%, -50%); |
|
|
} |
|
|
.annotation-marker:hover { |
|
|
background-color: #2563EB; |
|
|
} |
|
|
.annotation-tooltip { |
|
|
position: absolute; |
|
|
background-color: white; |
|
|
padding: 8px; |
|
|
border-radius: 4px; |
|
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); |
|
|
z-index: 10; |
|
|
max-width: 200px; |
|
|
} |
|
|
.feedback-canvas { |
|
|
position: relative; |
|
|
border: 1px dashed #ccc; |
|
|
margin: 0 auto; |
|
|
} |
|
|
.priority-indicator { |
|
|
width: 12px; |
|
|
height: 12px; |
|
|
border-radius: 50%; |
|
|
display: inline-block; |
|
|
margin-right: 4px; |
|
|
} |
|
|
.priority-high { |
|
|
background-color: #EF4444; |
|
|
} |
|
|
.priority-medium { |
|
|
background-color: #F59E0B; |
|
|
} |
|
|
.priority-low { |
|
|
background-color: #10B981; |
|
|
} |
|
|
.skeleton-loader { |
|
|
animation: pulse 2s infinite; |
|
|
} |
|
|
@keyframes pulse { |
|
|
0%, 100% { |
|
|
opacity: 0.6; |
|
|
} |
|
|
50% { |
|
|
opacity: 0.3; |
|
|
} |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body class="bg-gray-50 font-sans"> |
|
|
|
|
|
<header class="bg-indigo-700 text-white shadow-md"> |
|
|
<div class="container mx-auto px-4 py-3 flex justify-between items-center"> |
|
|
<div class="flex items-center space-x-2"> |
|
|
<i class="fas fa-code text-2xl"></i> |
|
|
<h1 class="text-xl font-bold">Vibe Coding</h1> |
|
|
<span class="text-sm bg-indigo-600 px-2 py-1 rounded ml-2">v1.0</span> |
|
|
</div> |
|
|
<div class="flex items-center space-x-4"> |
|
|
<div class="relative"> |
|
|
<button id="user-menu-btn" class="flex items-center space-x-2 focus:outline-none"> |
|
|
<span class="font-medium">John Doe</span> |
|
|
<i class="fas fa-chevron-down text-xs"></i> |
|
|
</button> |
|
|
<div id="user-menu" class="hidden absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg py-1 z-10"> |
|
|
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Profile</a> |
|
|
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Settings</a> |
|
|
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Sign out</a> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</header> |
|
|
|
|
|
|
|
|
<main class="container mx-auto px-4 py-6"> |
|
|
|
|
|
<div class="flex justify-between items-center mb-6"> |
|
|
<div> |
|
|
<h2 class="text-2xl font-bold text-gray-800">Product Backlog</h2> |
|
|
<p class="text-gray-600">Last updated: <span id="last-updated">Just now</span></p> |
|
|
</div> |
|
|
<div class="flex space-x-3"> |
|
|
<button id="refresh-btn" class="flex items-center px-4 py-2 bg-white border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 hover:bg-gray-50"> |
|
|
<i class="fas fa-sync-alt mr-2"></i> Refresh |
|
|
</button> |
|
|
<button id="new-feedback-btn" class="flex items-center px-4 py-2 bg-indigo-600 border border-transparent rounded-md shadow-sm text-sm font-medium text-white hover:bg-indigo-700"> |
|
|
<i class="fas fa-plus mr-2"></i> New Feedback |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="bg-white p-4 rounded-lg shadow-sm mb-6"> |
|
|
<div class="flex flex-col md:flex-row md:items-center md:space-x-4 space-y-3 md:space-y-0"> |
|
|
<div class="flex-1"> |
|
|
<label for="search" class="sr-only">Search</label> |
|
|
<div class="relative"> |
|
|
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> |
|
|
<i class="fas fa-search text-gray-400"></i> |
|
|
</div> |
|
|
<input id="search" name="search" type="text" class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md leading-5 bg-white placeholder-gray-500 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" placeholder="Search backlog items..."> |
|
|
</div> |
|
|
</div> |
|
|
<div class="flex space-x-3"> |
|
|
<div> |
|
|
<label for="status-filter" class="sr-only">Status</label> |
|
|
<select id="status-filter" name="status-filter" class="block w-full pl-3 pr-10 py-2 text-base border border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md"> |
|
|
<option value="all">All Statuses</option> |
|
|
<option value="todo">To Do</option> |
|
|
<option value="in-progress">In Progress</option> |
|
|
<option value="done">Done</option> |
|
|
</select> |
|
|
</div> |
|
|
<div> |
|
|
<label for="priority-filter" class="sr-only">Priority</label> |
|
|
<select id="priority-filter" name="priority-filter" class="block w-full pl-3 pr-10 py-2 text-base border border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md"> |
|
|
<option value="all">All Priorities</option> |
|
|
<option value="high">High</option> |
|
|
<option value="medium">Medium</option> |
|
|
<option value="low">Low</option> |
|
|
</select> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="kanban-board" class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6"> |
|
|
|
|
|
<div class="kanban-column rounded-lg p-4 shadow-sm"> |
|
|
<div class="flex justify-between items-center mb-4"> |
|
|
<h3 class="font-semibold text-lg text-gray-800">To Do</h3> |
|
|
<span class="bg-gray-200 text-gray-700 text-xs font-semibold px-2 py-1 rounded-full">24 items</span> |
|
|
</div> |
|
|
<div id="todo-cards" class="space-y-3"> |
|
|
|
|
|
<div class="card bg-white p-4 rounded-lg shadow cursor-pointer hover:shadow-md transition" onclick="showCardDetails('card-1')"> |
|
|
<div class="flex justify-between items-start mb-2"> |
|
|
<h4 class="font-medium text-gray-800">Implement user authentication</h4> |
|
|
<span class="priority-indicator priority-high"></span> |
|
|
</div> |
|
|
<p class="text-sm text-gray-600 mb-3">Add secure login and registration functionality with JWT tokens</p> |
|
|
<div class="flex justify-between items-center text-xs"> |
|
|
<span class="bg-blue-100 text-blue-800 px-2 py-1 rounded">US-101</span> |
|
|
<div class="flex items-center space-x-2"> |
|
|
<span class="text-gray-500"><i class="fas fa-comment mr-1"></i> 5</span> |
|
|
<span class="text-gray-500"><i class="fas fa-code-branch mr-1"></i> 3</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="card bg-white p-4 rounded-lg shadow cursor-pointer hover:shadow-md transition" onclick="showCardDetails('card-2')"> |
|
|
<div class="flex justify-between items-start mb-2"> |
|
|
<h4 class="font-medium text-gray-800">Create dashboard layout</h4> |
|
|
<span class="priority-indicator priority-medium"></span> |
|
|
</div> |
|
|
<p class="text-sm text-gray-600 mb-3">Design and implement the main dashboard UI components</p> |
|
|
<div class="flex justify-between items-center text-xs"> |
|
|
<span class="bg-blue-100 text-blue-800 px-2 py-1 rounded">US-102</span> |
|
|
<div class="flex items-center space-x-2"> |
|
|
<span class="text-gray-500"><i class="fas fa-comment mr-1"></i> 2</span> |
|
|
<span class="text-gray-500"><i class="fas fa-code-branch mr-1"></i> 1</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="card bg-gray-100 p-4 rounded-lg shadow"> |
|
|
<div class="animate-pulse"> |
|
|
<div class="h-5 bg-gray-200 rounded w-3/4 mb-3"></div> |
|
|
<div class="h-3 bg-gray-200 rounded w-full mb-4"></div> |
|
|
<div class="flex justify-between"> |
|
|
<div class="h-6 bg-gray-200 rounded w-16"></div> |
|
|
<div class="flex space-x-2"> |
|
|
<div class="h-6 bg-gray-200 rounded w-6"></div> |
|
|
<div class="h-6 bg-gray-200 rounded w-6"></div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="kanban-column rounded-lg p-4 shadow-sm"> |
|
|
<div class="flex justify-between items-center mb-4"> |
|
|
<h3 class="font-semibold text-lg text-gray-800">In Progress</h3> |
|
|
<span class="bg-blue-100 text-blue-800 text-xs font-semibold px-2 py-1 rounded-full">8 items</span> |
|
|
</div> |
|
|
<div id="in-progress-cards" class="space-y-3"> |
|
|
|
|
|
<div class="card bg-white p-4 rounded-lg shadow cursor-pointer hover:shadow-md transition" onclick="showCardDetails('card-4')"> |
|
|
<div class="flex justify-between items-start mb-2"> |
|
|
<h4 class="font-medium text-gray-800">API endpoint for user data</h4> |
|
|
<span class="priority-indicator priority-high"></span> |
|
|
</div> |
|
|
<p class="text-sm text-gray-600 mb-3">Create RESTful endpoints for user profile management</p> |
|
|
<div class="flex justify-between items-center text-xs"> |
|
|
<span class="bg-blue-100 text-blue-800 px-2 py-1 rounded">US-103</span> |
|
|
<div class="flex items-center space-x-2"> |
|
|
<span class="text-gray-500"><i class="fas fa-comment mr-1"></i> 3</span> |
|
|
<span class="text-gray-500"><i class="fas fa-code-branch mr-1"></i> 2</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="card bg-white p-4 rounded-lg shadow cursor-pointer hover:shadow-md transition" onclick="showCardDetails('card-5')"> |
|
|
<div class="flex justify-between items-start mb-2"> |
|
|
<h4 class="font-medium text-gray-800">Mobile responsive design</h4> |
|
|
<span class="priority-indicator priority-medium"></span> |
|
|
</div> |
|
|
<p class="text-sm text-gray-600 mb-3">Ensure all components adapt to different screen sizes</p> |
|
|
<div class="flex justify-between items-center text-xs"> |
|
|
<span class="bg-blue-100 text-blue-800 px-2 py-1 rounded">US-104</span> |
|
|
<div class="flex items-center space-x-2"> |
|
|
<span class="text-gray-500"><i class="fas fa-comment mr-1"></i> 7</span> |
|
|
<span class="text-gray-500"><i class="fas fa-code-branch mr-1"></i> 4</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="kanban-column rounded-lg p-4 shadow-sm"> |
|
|
<div class="flex justify-between items-center mb-4"> |
|
|
<h3 class="font-semibold text-lg text-gray-800">Done</h3> |
|
|
<span class="bg-green-100 text-green-800 text-xs font-semibold px-2 py-1 rounded-full">12 items</span> |
|
|
</div> |
|
|
<div id="done-cards" class="space-y-3"> |
|
|
|
|
|
<div class="card bg-white p-4 rounded-lg shadow cursor-pointer hover:shadow-md transition" onclick="showCardDetails('card-6')"> |
|
|
<div class="flex justify-between items-start mb-2"> |
|
|
<h4 class="font-medium text-gray-800">Project setup and config</h4> |
|
|
<span class="priority-indicator priority-low"></span> |
|
|
</div> |
|
|
<p class="text-sm text-gray-600 mb-3">Initialize project with required dependencies and tooling</p> |
|
|
<div class="flex justify-between items-center text-xs"> |
|
|
<span class="bg-blue-100 text-blue-800 px-2 py-1 rounded">US-105</span> |
|
|
<div class="flex items-center space-x-2"> |
|
|
<span class="text-gray-500"><i class="fas fa-comment mr-1"></i> 0</span> |
|
|
<span class="text-gray-500"><i class="fas fa-code-branch mr-1"></i> 1</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="card bg-white p-4 rounded-lg shadow cursor-pointer hover:shadow-md transition" onclick="showCardDetails('card-7')"> |
|
|
<div class="flex justify-between items-start mb-2"> |
|
|
<h4 class="font-medium text-gray-800">Database schema design</h4> |
|
|
<span class="priority-indicator priority-medium"></span> |
|
|
</div> |
|
|
<p class="text-sm text-gray-600 mb-3">Create initial database models and relationships</p> |
|
|
<div class="flex justify-between items-center text-xs"> |
|
|
<span class="bg-blue-100 text-blue-800 px-2 py-1 rounded">US-106</span> |
|
|
<div class="flex items-center space-x-2"> |
|
|
<span class="text-gray-500"><i class="fas fa-comment mr-1"></i> 4</span> |
|
|
<span class="text-gray-500"><i class="fas fa-code-branch mr-1"></i> 2</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="card-modal" class="hidden fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50"> |
|
|
<div class="relative top-20 mx-auto p-5 border w-11/12 md:w-3/4 lg:w-2/3 shadow-lg rounded-md bg-white"> |
|
|
<div class="flex justify-between items-start mb-4"> |
|
|
<div> |
|
|
<h3 id="card-title" class="text-xl font-bold text-gray-800">Card Title</h3> |
|
|
<div class="flex items-center mt-1 space-x-3"> |
|
|
<span id="card-id" class="bg-blue-100 text-blue-800 px-2 py-1 rounded text-xs">US-000</span> |
|
|
<span id="card-priority" class="text-xs font-medium flex items-center"> |
|
|
<span class="priority-indicator priority-high mr-1"></span> |
|
|
<span>High Priority</span> |
|
|
</span> |
|
|
<span id="card-status" class="bg-blue-100 text-blue-800 px-2 py-1 rounded text-xs">To Do</span> |
|
|
</div> |
|
|
</div> |
|
|
<button onclick="closeCardDetails()" class="text-gray-400 hover:text-gray-500"> |
|
|
<i class="fas fa-times"></i> |
|
|
</button> |
|
|
</div> |
|
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6"> |
|
|
<div class="lg:col-span-2"> |
|
|
<div class="mb-6"> |
|
|
<h4 class="font-semibold text-gray-700 mb-2">Description</h4> |
|
|
<p id="card-description" class="text-gray-600">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p> |
|
|
</div> |
|
|
|
|
|
<div class="mb-6"> |
|
|
<h4 class="font-semibold text-gray-700 mb-2">Acceptance Criteria</h4> |
|
|
<ul id="card-criteria" class="list-disc pl-5 space-y-1 text-gray-600"> |
|
|
<li>First acceptance criterion</li> |
|
|
<li>Second acceptance criterion</li> |
|
|
<li>Third acceptance criterion</li> |
|
|
</ul> |
|
|
</div> |
|
|
|
|
|
<div class="mb-6"> |
|
|
<h4 class="font-semibold text-gray-700 mb-2">Dependencies</h4> |
|
|
<div id="card-dependencies" class="flex flex-wrap gap-2"> |
|
|
<span class="bg-gray-100 text-gray-800 px-2 py-1 rounded text-xs">US-105</span> |
|
|
<span class="bg-gray-100 text-gray-800 px-2 py-1 rounded text-xs">US-107</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div> |
|
|
<div class="mb-6"> |
|
|
<div class="flex justify-between items-center mb-2"> |
|
|
<h4 class="font-semibold text-gray-700">Feedback (3)</h4> |
|
|
<button onclick="startFeedbackSession()" class="text-sm text-indigo-600 hover:text-indigo-800 flex items-center"> |
|
|
<i class="fas fa-plus mr-1"></i> Add Feedback |
|
|
</button> |
|
|
</div> |
|
|
<div id="card-feedback" class="space-y-3"> |
|
|
<div class="bg-gray-50 p-3 rounded"> |
|
|
<div class="flex justify-between items-start mb-1"> |
|
|
<span class="text-sm font-medium">Jane Smith</span> |
|
|
<span class="text-xs text-gray-500">2 days ago</span> |
|
|
</div> |
|
|
<p class="text-sm text-gray-600">The login button color doesn't match our brand guidelines. Please use #3B82F6 instead.</p> |
|
|
</div> |
|
|
<div class="bg-gray-50 p-3 rounded"> |
|
|
<div class="flex justify-between items-start mb-1"> |
|
|
<span class="text-sm font-medium">Mike Johnson</span> |
|
|
<span class="text-xs text-gray-500">1 week ago</span> |
|
|
</div> |
|
|
<p class="text-sm text-gray-600">We should add a "Forgot Password" link below the login form.</p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div> |
|
|
<h4 class="font-semibold text-gray-700 mb-2">Development Links</h4> |
|
|
<div id="card-dev-links" class="space-y-2"> |
|
|
<a href="#" class="flex items-center text-sm text-indigo-600 hover:text-indigo-800"> |
|
|
<i class="fas fa-file-code mr-2"></i> user-auth.controller.js |
|
|
</a> |
|
|
<a href="#" class="flex items-center text-sm text-indigo-600 hover:text-indigo-800"> |
|
|
<i class="fas fa-folder mr-2"></i> /src/routes/auth |
|
|
</a> |
|
|
<a href="#" class="flex items-center text-sm text-indigo-600 hover:text-indigo-800"> |
|
|
<i class="fas fa-database mr-2"></i> users table schema |
|
|
</a> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="feedback-modal" class="hidden fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50"> |
|
|
<div class="relative top-10 mx-auto p-5 border w-11/12 md:w-4/5 lg:w-3/4 shadow-lg rounded-md bg-white"> |
|
|
<div class="flex justify-between items-start mb-4"> |
|
|
<div> |
|
|
<h3 class="text-xl font-bold text-gray-800">Add Feedback</h3> |
|
|
<p class="text-sm text-gray-600">Attach visual feedback to: <span id="feedback-card-title" class="font-medium">Implement user authentication</span></p> |
|
|
</div> |
|
|
<button onclick="closeFeedbackModal()" class="text-gray-400 hover:text-gray-500"> |
|
|
<i class="fas fa-times"></i> |
|
|
</button> |
|
|
</div> |
|
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6"> |
|
|
<div class="lg:col-span-2"> |
|
|
<div class="mb-4"> |
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Feedback Context</label> |
|
|
<div class="flex space-x-3"> |
|
|
<button id="upload-image-btn" class="flex-1 flex items-center justify-center px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 hover:bg-gray-50"> |
|
|
<i class="fas fa-image mr-2"></i> Upload Image |
|
|
</button> |
|
|
<button id="paste-url-btn" class="flex-1 flex items-center justify-center px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 hover:bg-gray-50"> |
|
|
<i class="fas fa-link mr-2"></i> Paste URL |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div id="feedback-upload-area" class="hidden"> |
|
|
<div class="border-2 border-dashed border-gray-300 rounded-md p-4 text-center"> |
|
|
<i class="fas fa-cloud-upload-alt text-4xl text-gray-400 mb-2"></i> |
|
|
<p class="text-sm text-gray-600 mb-2">Drag and drop an image file here, or click to select</p> |
|
|
<input type="file" id="image-upload" class="hidden" accept="image/*"> |
|
|
<button onclick="document.getElementById('image-upload').click()" class="px-4 py-2 bg-indigo-600 text-white text-sm font-medium rounded-md hover:bg-indigo-700"> |
|
|
Select Image |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div id="feedback-url-area" class="hidden"> |
|
|
<div class="mb-4"> |
|
|
<label for="url-input" class="block text-sm font-medium text-gray-700 mb-1">URL to Prototype/Screenshot</label> |
|
|
<input type="url" id="url-input" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" placeholder="https://example.com/prototype"> |
|
|
</div> |
|
|
<button id="load-url-btn" class="px-4 py-2 bg-indigo-600 text-white text-sm font-medium rounded-md hover:bg-indigo-700"> |
|
|
Load URL |
|
|
</button> |
|
|
</div> |
|
|
|
|
|
<div id="feedback-canvas-container" class="hidden mt-4"> |
|
|
<div class="flex justify-between items-center mb-2"> |
|
|
<h4 class="font-medium text-gray-700">Click on the image to add annotations</h4> |
|
|
<button id="clear-annotations-btn" class="text-sm text-red-600 hover:text-red-800"> |
|
|
<i class="fas fa-trash-alt mr-1"></i> Clear All |
|
|
</button> |
|
|
</div> |
|
|
<div id="feedback-canvas" class="feedback-canvas bg-gray-100 relative"> |
|
|
|
|
|
<img id="feedback-image" src="" alt="Feedback context" class="max-w-full h-auto"> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div> |
|
|
<div id="annotation-form" class="hidden"> |
|
|
<div class="mb-4"> |
|
|
<label for="annotation-comment" class="block text-sm font-medium text-gray-700 mb-1">Your Comment</label> |
|
|
<textarea id="annotation-comment" rows="4" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" placeholder="Add details about this specific area..."></textarea> |
|
|
</div> |
|
|
<div class="flex justify-end space-x-3"> |
|
|
<button id="cancel-annotation-btn" class="px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 hover:bg-gray-50"> |
|
|
Cancel |
|
|
</button> |
|
|
<button id="submit-annotation-btn" class="px-4 py-2 bg-indigo-600 text-white text-sm font-medium rounded-md hover:bg-indigo-700"> |
|
|
Submit Annotation |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div id="existing-annotations" class="hidden"> |
|
|
<h4 class="font-medium text-gray-700 mb-2">Existing Annotations</h4> |
|
|
<div id="annotations-list" class="space-y-3"> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div id="feedback-instructions" class="bg-blue-50 p-4 rounded-md"> |
|
|
<h4 class="font-medium text-blue-800 mb-2">How to provide feedback</h4> |
|
|
<ol class="list-decimal pl-5 space-y-1 text-sm text-blue-700"> |
|
|
<li>Upload an image or paste a URL to load the visual context</li> |
|
|
<li>Click on specific areas to add annotation markers</li> |
|
|
<li>Add detailed comments for each annotation</li> |
|
|
<li>Submit your feedback to attach it to this backlog item</li> |
|
|
</ol> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</main> |
|
|
|
|
|
<script> |
|
|
|
|
|
const cards = { |
|
|
'card-1': { |
|
|
id: 'US-101', |
|
|
title: 'Implement user authentication', |
|
|
priority: 'high', |
|
|
status: 'todo', |
|
|
description: 'Add secure login and registration functionality with JWT tokens. This includes creating the necessary API endpoints, frontend components, and validation logic.', |
|
|
criteria: [ |
|
|
'User can register with email and password', |
|
|
'User can login with valid credentials', |
|
|
'Invalid login attempts are handled securely', |
|
|
'JWT tokens are issued and validated properly' |
|
|
], |
|
|
dependencies: ['US-105', 'US-107'], |
|
|
feedback: [ |
|
|
{ author: 'Jane Smith', date: '2 days ago', comment: 'The login button color doesn\'t match our brand guidelines. Please use #3B82F6 instead.' }, |
|
|
{ author: 'Mike Johnson', date: '1 week ago', comment: 'We should add a "Forgot Password" link below the login form.' } |
|
|
], |
|
|
devLinks: [ |
|
|
{ type: 'file', name: 'user-auth.controller.js' }, |
|
|
{ type: 'folder', name: '/src/routes/auth' }, |
|
|
{ type: 'db', name: 'users table schema' } |
|
|
] |
|
|
}, |
|
|
'card-2': { |
|
|
id: 'US-102', |
|
|
title: 'Create dashboard layout', |
|
|
priority: 'medium', |
|
|
status: 'todo', |
|
|
description: 'Design and implement the main dashboard UI components including navigation, summary cards, and the main content area.', |
|
|
criteria: [ |
|
|
'Dashboard adapts to different screen sizes', |
|
|
'Navigation is accessible and intuitive', |
|
|
'Summary cards display key metrics', |
|
|
'Main content area is flexible for different widgets' |
|
|
], |
|
|
dependencies: ['US-105'], |
|
|
feedback: [ |
|
|
{ author: 'Sarah Williams', date: '3 days ago', comment: 'The navigation should be collapsible on smaller screens.' } |
|
|
], |
|
|
devLinks: [ |
|
|
{ type: 'file', name: 'Dashboard.jsx' }, |
|
|
{ type: 'folder', name: '/src/components/layout' } |
|
|
] |
|
|
}, |
|
|
'card-4': { |
|
|
id: 'US-103', |
|
|
title: 'API endpoint for user data', |
|
|
priority: 'high', |
|
|
status: 'in-progress', |
|
|
description: 'Create RESTful endpoints for user profile management including CRUD operations and data validation.', |
|
|
criteria: [ |
|
|
'GET /api/users returns user list', |
|
|
'GET /api/users/:id returns specific user', |
|
|
'PUT /api/users/:id updates user data', |
|
|
'DELETE /api/users/:id deactivates user' |
|
|
], |
|
|
dependencies: ['US-101', 'US-106'], |
|
|
feedback: [], |
|
|
devLinks: [ |
|
|
{ type: 'file', name: 'users.routes.js' }, |
|
|
{ type: 'folder', name: '/src/controllers' } |
|
|
] |
|
|
}, |
|
|
'card-5': { |
|
|
id: 'US-104', |
|
|
title: 'Mobile responsive design', |
|
|
priority: 'medium', |
|
|
status: 'in-progress', |
|
|
description: 'Ensure all components adapt to different screen sizes with appropriate breakpoints and responsive behavior.', |
|
|
criteria: [ |
|
|
'Layout adjusts at 768px and 480px breakpoints', |
|
|
'Navigation converts to hamburger menu on mobile', |
|
|
'Forms remain usable on small screens', |
|
|
'Images scale appropriately' |
|
|
], |
|
|
dependencies: ['US-102'], |
|
|
feedback: [ |
|
|
{ author: 'Alex Chen', date: '5 days ago', comment: 'The form fields need more padding on mobile devices.' }, |
|
|
{ author: 'Taylor Swift', date: '1 week ago', comment: 'Consider adding swipe gestures for the image carousel on mobile.' } |
|
|
], |
|
|
devLinks: [ |
|
|
{ type: 'file', name: 'responsive.scss' }, |
|
|
{ type: 'folder', name: '/src/styles' } |
|
|
] |
|
|
}, |
|
|
'card-6': { |
|
|
id: 'US-105', |
|
|
title: 'Project setup and config', |
|
|
priority: 'low', |
|
|
status: 'done', |
|
|
description: 'Initialize project with required dependencies and tooling including linters, testing frameworks, and CI/CD pipeline.', |
|
|
criteria: [ |
|
|
'Project can be installed with npm install', |
|
|
'ESLint and Prettier configured', |
|
|
'Jest testing framework installed', |
|
|
'GitHub Actions workflow for CI' |
|
|
], |
|
|
dependencies: [], |
|
|
feedback: [], |
|
|
devLinks: [ |
|
|
{ type: 'file', name: 'package.json' }, |
|
|
{ type: 'folder', name: '/.github/workflows' } |
|
|
] |
|
|
}, |
|
|
'card-7': { |
|
|
id: 'US-106', |
|
|
title: 'Database schema design', |
|
|
priority: 'medium', |
|
|
status: 'done', |
|
|
description: 'Create initial database models and relationships including users, products, and orders tables with appropriate indexes.', |
|
|
criteria: [ |
|
|
'Users table with required fields', |
|
|
'Products table with categories', |
|
|
'Orders table with relationships', |
|
|
'Appropriate indexes for common queries' |
|
|
], |
|
|
dependencies: ['US-105'], |
|
|
feedback: [ |
|
|
{ author: 'David Miller', date: '2 weeks ago', comment: 'Consider adding a created_at timestamp to all tables.' } |
|
|
], |
|
|
devLinks: [ |
|
|
{ type: 'file', name: 'schema.sql' }, |
|
|
{ type: 'folder', name: '/database/migrations' } |
|
|
] |
|
|
} |
|
|
}; |
|
|
|
|
|
|
|
|
const userMenuBtn = document.getElementById('user-menu-btn'); |
|
|
const userMenu = document.getElementById('user-menu'); |
|
|
const refreshBtn = document.getElementById('refresh-btn'); |
|
|
const newFeedbackBtn = document.getElementById('new-feedback-btn'); |
|
|
const searchInput = document.getElementById('search'); |
|
|
const statusFilter = document.getElementById('status-filter'); |
|
|
const priorityFilter = document.getElementById('priority-filter'); |
|
|
const cardModal = document.getElementById('card-modal'); |
|
|
const feedbackModal = document.getElementById('feedback-modal'); |
|
|
const uploadImageBtn = document.getElementById('upload-image-btn'); |
|
|
const pasteUrlBtn = document.getElementById('paste-url-btn'); |
|
|
const feedbackUploadArea = document.getElementById('feedback-upload-area'); |
|
|
const feedbackUrlArea = document.getElementById('feedback-url-area'); |
|
|
const feedbackCanvasContainer = document.getElementById('feedback-canvas-container'); |
|
|
const annotationForm = document.getElementById('annotation-form'); |
|
|
const existingAnnotations = document.getElementById('existing-annotations'); |
|
|
const feedbackInstructions = document.getElementById('feedback-instructions'); |
|
|
const feedbackImage = document.getElementById('feedback-image'); |
|
|
const feedbackCanvas = document.getElementById('feedback-canvas'); |
|
|
const clearAnnotationsBtn = document.getElementById('clear-annotations-btn'); |
|
|
const cancelAnnotationBtn = document.getElementById('cancel-annotation-btn'); |
|
|
const submitAnnotationBtn = document.getElementById('submit-annotation-btn'); |
|
|
const annotationComment = document.getElementById('annotation-comment'); |
|
|
const annotationsList = document.getElementById('annotations-list'); |
|
|
|
|
|
|
|
|
let currentCardId = null; |
|
|
let annotations = []; |
|
|
let currentAnnotation = null; |
|
|
|
|
|
|
|
|
userMenuBtn.addEventListener('click', toggleUserMenu); |
|
|
refreshBtn.addEventListener('click', refreshBacklog); |
|
|
newFeedbackBtn.addEventListener('click', startFeedbackSession); |
|
|
searchInput.addEventListener('input', filterCards); |
|
|
statusFilter.addEventListener('change', filterCards); |
|
|
priorityFilter.addEventListener('change', filterCards); |
|
|
uploadImageBtn.addEventListener('click', showUploadArea); |
|
|
pasteUrlBtn.addEventListener('click', showUrlArea); |
|
|
clearAnnotationsBtn.addEventListener('click', clearAnnotations); |
|
|
cancelAnnotationBtn.addEventListener('click', cancelAnnotation); |
|
|
submitAnnotationBtn.addEventListener('click', submitAnnotation); |
|
|
document.getElementById('image-upload').addEventListener('change', handleImageUpload); |
|
|
document.getElementById('load-url-btn').addEventListener('click', loadUrl); |
|
|
|
|
|
|
|
|
function init() { |
|
|
|
|
|
setTimeout(() => { |
|
|
document.querySelectorAll('.skeleton-loader').forEach(el => { |
|
|
el.classList.remove('animate-pulse'); |
|
|
el.innerHTML = ` |
|
|
<div class="flex justify-between items-start mb-2"> |
|
|
<h4 class="font-medium text-gray-800">Data validation middleware</h4> |
|
|
<span class="priority-indicator priority-medium"></span> |
|
|
</div> |
|
|
<p class="text-sm text-gray-600 mb-3">Create reusable validation middleware for API requests</p> |
|
|
<div class="flex justify-between items-center text-xs"> |
|
|
<span class="bg-blue-100 text-blue-800 px-2 py-1 rounded">US-108</span> |
|
|
<div class="flex items-center space-x-2"> |
|
|
<span class="text-gray-500"><i class="fas fa-comment mr-1"></i> 0</span> |
|
|
<span class="text-gray-500"><i class="fas fa-code-branch mr-1"></i> 0</span> |
|
|
</div> |
|
|
</div> |
|
|
`; |
|
|
}); |
|
|
}, 1500); |
|
|
} |
|
|
|
|
|
|
|
|
function toggleUserMenu() { |
|
|
userMenu.classList.toggle('hidden'); |
|
|
} |
|
|
|
|
|
|
|
|
document.addEventListener('click', (e) => { |
|
|
if (!userMenu.contains(e.target) && e.target !== userMenuBtn) { |
|
|
userMenu.classList.add('hidden'); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
function refreshBacklog() { |
|
|
refreshBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> Refreshing'; |
|
|
setTimeout(() => { |
|
|
refreshBtn.innerHTML = '<i class="fas fa-sync-alt mr-2"></i> Refresh'; |
|
|
document.getElementById('last-updated').textContent = new Date().toLocaleString(); |
|
|
|
|
|
}, 1000); |
|
|
} |
|
|
|
|
|
|
|
|
function showCardDetails(cardId) { |
|
|
currentCardId = cardId; |
|
|
const card = cards[cardId]; |
|
|
|
|
|
|
|
|
document.getElementById('card-title').textContent = card.title; |
|
|
document.getElementById('card-id').textContent = card.id; |
|
|
document.getElementById('card-description').textContent = card.description; |
|
|
document.getElementById('card-status').textContent = card.status === 'todo' ? 'To Do' : |
|
|
card.status === 'in-progress' ? 'In Progress' : 'Done'; |
|
|
|
|
|
|
|
|
const priorityIndicator = document.getElementById('card-priority'); |
|
|
priorityIndicator.querySelector('.priority-indicator').className = `priority-indicator priority-${card.priority}`; |
|
|
priorityIndicator.querySelector('span:last-child').textContent = `${card.priority.charAt(0).toUpperCase() + card.priority.slice(1)} Priority`; |
|
|
|
|
|
|
|
|
const criteriaList = document.getElementById('card-criteria'); |
|
|
criteriaList.innerHTML = ''; |
|
|
card.criteria.forEach(criterion => { |
|
|
const li = document.createElement('li'); |
|
|
li.textContent = criterion; |
|
|
criteriaList.appendChild(li); |
|
|
}); |
|
|
|
|
|
|
|
|
const dependenciesContainer = document.getElementById('card-dependencies'); |
|
|
dependenciesContainer.innerHTML = ''; |
|
|
card.dependencies.forEach(dep => { |
|
|
const span = document.createElement('span'); |
|
|
span.className = 'bg-gray-100 text-gray-800 px-2 py-1 rounded text-xs'; |
|
|
span.textContent = dep; |
|
|
dependenciesContainer.appendChild(span); |
|
|
}); |
|
|
|
|
|
|
|
|
const feedbackContainer = document.getElementById('card-feedback'); |
|
|
feedbackContainer.innerHTML = ''; |
|
|
card.feedback.forEach(fb => { |
|
|
const div = document.createElement('div'); |
|
|
div.className = 'bg-gray-50 p-3 rounded'; |
|
|
div.innerHTML = ` |
|
|
<div class="flex justify-between items-start mb-1"> |
|
|
<span class="text-sm font-medium">${fb.author}</span> |
|
|
<span class="text-xs text-gray-500">${fb.date}</span> |
|
|
</div> |
|
|
<p class="text-sm text-gray-600">${fb.comment}</p> |
|
|
`; |
|
|
feedbackContainer.appendChild(div); |
|
|
}); |
|
|
|
|
|
|
|
|
const devLinksContainer = document.getElementById('card-dev-links'); |
|
|
devLinksContainer.innerHTML = ''; |
|
|
card.devLinks.forEach(link => { |
|
|
const a = document.createElement('a'); |
|
|
a.href = '#'; |
|
|
a.className = 'flex items-center text-sm text-indigo-600 hover:text-indigo-800'; |
|
|
a.innerHTML = ` |
|
|
<i class="fas ${link.type === 'file' ? 'fa-file-code' : link.type === 'folder' ? 'fa-folder' : 'fa-database'} mr-2"></i> |
|
|
${link.name} |
|
|
`; |
|
|
devLinksContainer.appendChild(a); |
|
|
}); |
|
|
|
|
|
|
|
|
document.getElementById('feedback-card-title').textContent = card.title; |
|
|
cardModal.classList.remove('hidden'); |
|
|
} |
|
|
|
|
|
|
|
|
function closeCardDetails() { |
|
|
cardModal.classList.add('hidden'); |
|
|
} |
|
|
|
|
|
|
|
|
function startFeedbackSession() { |
|
|
if (!currentCardId) return; |
|
|
|
|
|
|
|
|
feedbackUploadArea.classList.add('hidden'); |
|
|
feedbackUrlArea.classList.add('hidden'); |
|
|
feedbackCanvasContainer.classList.add('hidden'); |
|
|
annotationForm.classList.add('hidden'); |
|
|
existingAnnotations.classList.add('hidden'); |
|
|
feedbackInstructions.classList.remove('hidden'); |
|
|
|
|
|
|
|
|
feedbackModal.classList.remove('hidden'); |
|
|
} |
|
|
|
|
|
|
|
|
function closeFeedbackModal() { |
|
|
feedbackModal.classList.add('hidden'); |
|
|
} |
|
|
|
|
|
|
|
|
function showUploadArea() { |
|
|
feedbackUploadArea.classList.remove('hidden'); |
|
|
feedbackUrlArea.classList.add('hidden'); |
|
|
feedbackInstructions.classList.add('hidden'); |
|
|
} |
|
|
|
|
|
|
|
|
function showUrlArea() { |
|
|
feedbackUrlArea.classList.remove('hidden'); |
|
|
feedbackUploadArea.classList.add('hidden'); |
|
|
feedbackInstructions.classList.add('hidden'); |
|
|
} |
|
|
|
|
|
|
|
|
function handleImageUpload(e) { |
|
|
const file = e.target.files[0]; |
|
|
if (!file) return; |
|
|
|
|
|
const reader = new FileReader(); |
|
|
reader.onload = function(event) { |
|
|
feedbackImage.src = event.target.result; |
|
|
feedbackCanvasContainer.classList.remove('hidden'); |
|
|
feedbackUploadArea.classList.add('hidden'); |
|
|
|
|
|
|
|
|
setupAnnotationCanvas(); |
|
|
}; |
|
|
reader.readAsDataURL(file); |
|
|
} |
|
|
|
|
|
|
|
|
function loadUrl() { |
|
|
const url = document.getElementById('url-input').value; |
|
|
if (!url) return; |
|
|
|
|
|
|
|
|
|
|
|
feedbackImage.src = 'https://via.placeholder.com/800x500?text=Prototype+Preview'; |
|
|
feedbackCanvasContainer.classList.remove('hidden'); |
|
|
feedbackUrlArea.classList.add('hidden'); |
|
|
|
|
|
|
|
|
setupAnnotationCanvas(); |
|
|
} |
|
|
|
|
|
|
|
|
function setupAnnotationCanvas() { |
|
|
|
|
|
clearAnnotations(); |
|
|
|
|
|
|
|
|
feedbackCanvas.addEventListener('click', handleCanvasClick); |
|
|
} |
|
|
|
|
|
|
|
|
function handleCanvasClick(e) { |
|
|
|
|
|
const rect = feedbackCanvas.getBoundingClientRect(); |
|
|
const x = e.clientX - rect.left; |
|
|
const y = e.clientY - rect.top; |
|
|
|
|
|
|
|
|
currentAnnotation = { x, y, comment: '' }; |
|
|
|
|
|
|
|
|
annotationForm.classList.remove('hidden'); |
|
|
existingAnnotations.classList.add('hidden'); |
|
|
|
|
|
|
|
|
annotationForm.style.top = `${y + 20}px`; |
|
|
annotationForm.style.left = `${x + 20}px`; |
|
|
} |
|
|
|
|
|
|
|
|
function clearAnnotations() { |
|
|
annotations = []; |
|
|
currentAnnotation = null; |
|
|
renderAnnotations(); |
|
|
} |
|
|
|
|
|
|
|
|
function cancelAnnotation() { |
|
|
currentAnnotation = null; |
|
|
annotationForm.classList.add('hidden'); |
|
|
} |
|
|
|
|
|
|
|
|
function submitAnnotation() { |
|
|
if (!currentAnnotation) return; |
|
|
|
|
|
const comment = annotationComment.value.trim(); |
|
|
if (!comment) return; |
|
|
|
|
|
currentAnnotation.comment = comment; |
|
|
currentAnnotation.date = new Date().toLocaleDateString(); |
|
|
currentAnnotation.author = 'You'; |
|
|
|
|
|
annotations.push(currentAnnotation); |
|
|
currentAnnotation = null; |
|
|
annotationComment.value = ''; |
|
|
annotationForm.classList.add('hidden'); |
|
|
|
|
|
renderAnnotations(); |
|
|
} |
|
|
|
|
|
|
|
|
function renderAnnotations() { |
|
|
|
|
|
document.querySelectorAll('.annotation-marker').forEach(marker => marker.remove()); |
|
|
document.querySelectorAll('.annotation-tooltip').forEach(tooltip => tooltip.remove()); |
|
|
|
|
|
|
|
|
annotations.forEach((annotation, index) => { |
|
|
|
|
|
const marker = document.createElement('div'); |
|
|
marker.className = 'annotation-marker'; |
|
|
marker.style.top = `${annotation.y}px`; |
|
|
marker.style.left = `${annotation.x}px`; |
|
|
marker.dataset.index = index; |
|
|
|
|
|
|
|
|
marker.addEventListener('click', (e) => { |
|
|
e.stopPropagation(); |
|
|
showAnnotationTooltip(annotation, marker); |
|
|
}); |
|
|
|
|
|
feedbackCanvas.appendChild(marker); |
|
|
}); |
|
|
|
|
|
|
|
|
annotationsList.innerHTML = ''; |
|
|
annotations.forEach((annotation, index) => { |
|
|
const div = document.createElement('div'); |
|
|
div.className = 'bg-gray-50 p-3 rounded cursor-pointer hover:bg-gray-100'; |
|
|
div.innerHTML = ` |
|
|
<div class="flex justify-between items-start mb-1"> |
|
|
<span class="text-sm font-medium">${annotation.author}</span> |
|
|
<span class="text-xs text-gray-500">${annotation.date}</span> |
|
|
</div> |
|
|
<p class="text-sm text-gray-600">${annotation.comment}</p> |
|
|
`; |
|
|
div.addEventListener('click', () => { |
|
|
const marker = feedbackCanvas.querySelector(`.annotation-marker[data-index="${index}"]`); |
|
|
if (marker) { |
|
|
showAnnotationTooltip(annotation, marker); |
|
|
} |
|
|
}); |
|
|
annotationsList.appendChild(div); |
|
|
}); |
|
|
|
|
|
|
|
|
if (annotations.length > 0) { |
|
|
existingAnnotations.classList.remove('hidden'); |
|
|
} else { |
|
|
existingAnnotations.classList.add('hidden'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function showAnnotationTooltip(annotation, marker) { |
|
|
|
|
|
document.querySelectorAll('.annotation-tooltip').forEach(tooltip => tooltip.remove()); |
|
|
|
|
|
|
|
|
const tooltip = document.createElement('div'); |
|
|
tooltip.className = 'annotation-tooltip'; |
|
|
tooltip.style.top = `${parseInt(marker.style.top) - 10}px`; |
|
|
tooltip.style.left = `${parseInt(marker.style.left) + 20}px`; |
|
|
tooltip.innerHTML = ` |
|
|
<div class="text-sm font-medium">${annotation.author}</div> |
|
|
<div class="text-xs text-gray-500 mb-1">${annotation.date}</div> |
|
|
<div class="text-sm">${annotation.comment}</div> |
|
|
`; |
|
|
|
|
|
feedbackCanvas.appendChild(tooltip); |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
const closeTooltip = (e) => { |
|
|
if (!tooltip.contains(e.target) && e.target !== marker) { |
|
|
tooltip.remove(); |
|
|
document.removeEventListener('click', closeTooltip); |
|
|
} |
|
|
}; |
|
|
document.addEventListener('click', closeTooltip); |
|
|
}, 10); |
|
|
} |
|
|
|
|
|
|
|
|
function filterCards() { |
|
|
const searchTerm = searchInput.value.toLowerCase(); |
|
|
const statusValue = statusFilter.value; |
|
|
const priorityValue = priorityFilter.value; |
|
|
|
|
|
document.querySelectorAll('.card').forEach(card => { |
|
|
const title = card.querySelector('h4').textContent.toLowerCase(); |
|
|
const status = card.closest('.kanban-column').querySelector('h3').textContent.toLowerCase(); |
|
|
const priority = card.querySelector('.priority-indicator').className.includes('high') ? 'high' : |
|
|
card.querySelector('.priority-indicator').className.includes('medium') ? 'medium' : 'low'; |
|
|
|
|
|
const matchesSearch = title.includes(searchTerm); |
|
|
const matchesStatus = statusValue === 'all' || |
|
|
(statusValue === 'todo' && status.includes('to do')) || |
|
|
(statusValue === 'in-progress' && status.includes('in progress')) || |
|
|
(statusValue === 'done' && status.includes('done')); |
|
|
const matchesPriority = priorityValue === 'all' || priority === priorityValue; |
|
|
|
|
|
if (matchesSearch && matchesStatus && matchesPriority) { |
|
|
card.style.display = 'block'; |
|
|
} else { |
|
|
card.style.display = 'none'; |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
init(); |
|
|
</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=LukasBe/vibe-coding-backlog-driven" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
|
|
</html> |