frucht commited on
Commit
a53e528
·
verified ·
1 Parent(s): 6ff3302

Add 3 files

Browse files
Files changed (3) hide show
  1. README.md +7 -5
  2. index.html +1469 -19
  3. prompts.txt +1 -0
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Vid Project
3
- emoji: 😻
4
- colorFrom: gray
5
- colorTo: indigo
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: vid-project
3
+ emoji: 🐳
4
+ colorFrom: purple
5
+ colorTo: green
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,1469 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Workout Video Archiver | Trainer's Toolkit</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
+ /* Custom styles that can't be done with Tailwind */
11
+ .video-upload-area {
12
+ border: 2px dashed #cbd5e0;
13
+ transition: all 0.3s ease;
14
+ }
15
+ .video-upload-area:hover {
16
+ border-color: #4f46e5;
17
+ background-color: #f8fafc;
18
+ }
19
+ .video-upload-area.dragover {
20
+ border-color: #4f46e5;
21
+ background-color: #e0e7ff;
22
+ }
23
+ .video-thumbnail {
24
+ transition: transform 0.2s ease;
25
+ }
26
+ .video-thumbnail:hover {
27
+ transform: scale(1.03);
28
+ }
29
+ .tag-cloud {
30
+ display: flex;
31
+ flex-wrap: wrap;
32
+ gap: 8px;
33
+ }
34
+ .tag-item {
35
+ cursor: pointer;
36
+ transition: all 0.2s ease;
37
+ }
38
+ .tag-item:hover {
39
+ transform: translateY(-2px);
40
+ }
41
+ .sidebar {
42
+ transition: all 0.3s ease;
43
+ }
44
+ @media (max-width: 768px) {
45
+ .sidebar {
46
+ transform: translateX(-100%);
47
+ position: fixed;
48
+ z-index: 50;
49
+ height: 100vh;
50
+ top: 0;
51
+ left: 0;
52
+ }
53
+ .sidebar.open {
54
+ transform: translateX(0);
55
+ }
56
+ }
57
+ .video-player-container {
58
+ aspect-ratio: 16/9;
59
+ }
60
+ </style>
61
+ </head>
62
+ <body class="bg-gray-50 font-sans">
63
+ <div class="flex h-screen overflow-hidden">
64
+ <!-- Sidebar -->
65
+ <div class="sidebar bg-indigo-700 text-white w-64 flex-shrink-0 p-4 md:block">
66
+ <div class="flex items-center justify-between mb-8">
67
+ <h1 class="text-2xl font-bold">Trainer's Toolkit</h1>
68
+ <button id="closeSidebar" class="md:hidden text-white">
69
+ <i class="fas fa-times"></i>
70
+ </button>
71
+ </div>
72
+
73
+ <nav>
74
+ <div class="mb-6">
75
+ <h2 class="text-sm uppercase font-semibold text-indigo-200 mb-2">Navigation</h2>
76
+ <ul class="space-y-1">
77
+ <li>
78
+ <button id="dashboardBtn" class="w-full text-left px-3 py-2 rounded-md bg-indigo-800 flex items-center">
79
+ <i class="fas fa-home mr-2"></i> Dashboard
80
+ </button>
81
+ </li>
82
+ <li>
83
+ <button id="uploadBtn" class="w-full text-left px-3 py-2 rounded-md hover:bg-indigo-600 flex items-center">
84
+ <i class="fas fa-upload mr-2"></i> Upload Videos
85
+ </button>
86
+ </li>
87
+ <li>
88
+ <button id="libraryBtn" class="w-full text-left px-3 py-2 rounded-md hover:bg-indigo-600 flex items-center">
89
+ <i class="fas fa-video mr-2"></i> Video Library
90
+ </button>
91
+ </li>
92
+ <li>
93
+ <button id="tagsBtn" class="w-full text-left px-3 py-2 rounded-md hover:bg-indigo-600 flex items-center">
94
+ <i class="fas fa-tags mr-2"></i> Manage Tags
95
+ </button>
96
+ </li>
97
+ </ul>
98
+ </div>
99
+
100
+ <div class="mb-6">
101
+ <h2 class="text-sm uppercase font-semibold text-indigo-200 mb-2">Quick Filters</h2>
102
+ <ul class="space-y-1">
103
+ <li>
104
+ <button data-filter="recent" class="w-full text-left px-3 py-2 rounded-md hover:bg-indigo-600 flex items-center">
105
+ <i class="fas fa-clock mr-2"></i> Recent Videos
106
+ </button>
107
+ </li>
108
+ <li>
109
+ <button data-filter="week" class="w-full text-left px-3 py-2 rounded-md hover:bg-indigo-600 flex items-center">
110
+ <i class="fas fa-calendar-week mr-2"></i> This Week
111
+ </button>
112
+ </li>
113
+ <li>
114
+ <button data-filter="month" class="w-full text-left px-3 py-2 rounded-md hover:bg-indigo-600 flex items-center">
115
+ <i class="fas fa-calendar-alt mr-2"></i> This Month
116
+ </button>
117
+ </li>
118
+ </ul>
119
+ </div>
120
+
121
+ <div>
122
+ <h2 class="text-sm uppercase font-semibold text-indigo-200 mb-2">Popular Tags</h2>
123
+ <div class="tag-cloud" id="popularTags">
124
+ <!-- Tags will be dynamically inserted here -->
125
+ </div>
126
+ </div>
127
+ </nav>
128
+ </div>
129
+
130
+ <!-- Main Content -->
131
+ <div class="flex-1 flex flex-col overflow-hidden">
132
+ <!-- Top Navigation -->
133
+ <header class="bg-white shadow-sm z-10">
134
+ <div class="flex items-center justify-between px-6 py-4">
135
+ <div class="flex items-center">
136
+ <button id="menuBtn" class="mr-4 text-gray-600 md:hidden">
137
+ <i class="fas fa-bars"></i>
138
+ </button>
139
+ <h2 id="pageTitle" class="text-xl font-semibold text-gray-800">Dashboard</h2>
140
+ </div>
141
+ <div class="flex items-center space-x-4">
142
+ <div class="relative">
143
+ <input type="text" placeholder="Search videos..." class="pl-10 pr-4 py-2 border rounded-full text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
144
+ <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
145
+ </div>
146
+ <div class="w-10 h-10 rounded-full bg-indigo-100 flex items-center justify-center text-indigo-700 font-semibold">
147
+ T
148
+ </div>
149
+ </div>
150
+ </div>
151
+ </header>
152
+
153
+ <!-- Page Content -->
154
+ <main class="flex-1 overflow-y-auto p-6 bg-gray-50" id="mainContent">
155
+ <!-- Dashboard Content -->
156
+ <div id="dashboardContent">
157
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
158
+ <div class="bg-white p-6 rounded-lg shadow">
159
+ <div class="flex items-center justify-between">
160
+ <div>
161
+ <p class="text-gray-500">Total Videos</p>
162
+ <h3 class="text-2xl font-bold" id="totalVideos">0</h3>
163
+ </div>
164
+ <div class="p-3 rounded-full bg-indigo-100 text-indigo-600">
165
+ <i class="fas fa-video"></i>
166
+ </div>
167
+ </div>
168
+ </div>
169
+ <div class="bg-white p-6 rounded-lg shadow">
170
+ <div class="flex items-center justify-between">
171
+ <div>
172
+ <p class="text-gray-500">Total Tags</p>
173
+ <h3 class="text-2xl font-bold" id="totalTags">0</h3>
174
+ </div>
175
+ <div class="p-3 rounded-full bg-green-100 text-green-600">
176
+ <i class="fas fa-tags"></i>
177
+ </div>
178
+ </div>
179
+ </div>
180
+ <div class="bg-white p-6 rounded-lg shadow">
181
+ <div class="flex items-center justify-between">
182
+ <div>
183
+ <p class="text-gray-500">Storage Used</p>
184
+ <h3 class="text-2xl font-bold" id="storageUsed">0 MB</h3>
185
+ </div>
186
+ <div class="p-3 rounded-full bg-blue-100 text-blue-600">
187
+ <i class="fas fa-database"></i>
188
+ </div>
189
+ </div>
190
+ </div>
191
+ </div>
192
+
193
+ <div class="bg-white p-6 rounded-lg shadow mb-6">
194
+ <div class="flex justify-between items-center mb-4">
195
+ <h3 class="text-lg font-semibold">Recent Videos</h3>
196
+ <button id="viewAllVideos" class="text-indigo-600 hover:text-indigo-800 text-sm font-medium">View All</button>
197
+ </div>
198
+ <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4" id="recentVideos">
199
+ <!-- Recent videos will be inserted here -->
200
+ </div>
201
+ </div>
202
+
203
+ <div class="bg-white p-6 rounded-lg shadow">
204
+ <h3 class="text-lg font-semibold mb-4">Quick Actions</h3>
205
+ <div class="grid grid-cols-2 md:grid-cols-4 gap-4">
206
+ <button id="quickUploadBtn" class="flex flex-col items-center justify-center p-4 border rounded-lg hover:bg-gray-50 transition-colors">
207
+ <div class="w-10 h-10 rounded-full bg-indigo-100 flex items-center justify-center text-indigo-600 mb-2">
208
+ <i class="fas fa-upload"></i>
209
+ </div>
210
+ <span class="text-sm font-medium">Upload Video</span>
211
+ </button>
212
+ <button id="quickTagBtn" class="flex flex-col items-center justify-center p-4 border rounded-lg hover:bg-gray-50 transition-colors">
213
+ <div class="w-10 h-10 rounded-full bg-green-100 flex items-center justify-center text-green-600 mb-2">
214
+ <i class="fas fa-tags"></i>
215
+ </div>
216
+ <span class="text-sm font-medium">Manage Tags</span>
217
+ </button>
218
+ <button id="quickShareBtn" class="flex flex-col items-center justify-center p-4 border rounded-lg hover:bg-gray-50 transition-colors">
219
+ <div class="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center text-blue-600 mb-2">
220
+ <i class="fas fa-share-alt"></i>
221
+ </div>
222
+ <span class="text-sm font-medium">Share Videos</span>
223
+ </button>
224
+ <button id="quickStatsBtn" class="flex flex-col items-center justify-center p-4 border rounded-lg hover:bg-gray-50 transition-colors">
225
+ <div class="w-10 h-10 rounded-full bg-purple-100 flex items-center justify-center text-purple-600 mb-2">
226
+ <i class="fas fa-chart-line"></i>
227
+ </div>
228
+ <span class="text-sm font-medium">View Stats</span>
229
+ </button>
230
+ </div>
231
+ </div>
232
+ </div>
233
+
234
+ <!-- Upload Content -->
235
+ <div id="uploadContent" class="hidden">
236
+ <div class="bg-white p-6 rounded-lg shadow mb-6">
237
+ <h2 class="text-xl font-semibold mb-4">Upload Workout Videos</h2>
238
+
239
+ <div class="video-upload-area rounded-lg p-8 text-center mb-6" id="dropArea">
240
+ <i class="fas fa-cloud-upload-alt text-4xl text-indigo-500 mb-3"></i>
241
+ <h3 class="text-lg font-medium mb-1">Drag & Drop your workout videos here</h3>
242
+ <p class="text-gray-500 mb-4">or</p>
243
+ <label for="videoUpload" class="inline-flex items-center px-4 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 cursor-pointer">
244
+ <i class="fas fa-folder-open mr-2"></i> Browse Files
245
+ <input type="file" id="videoUpload" class="hidden" accept="video/*" multiple>
246
+ </label>
247
+ </div>
248
+
249
+ <div class="mb-6">
250
+ <h3 class="text-lg font-medium mb-3">Upload Queue</h3>
251
+ <div class="border rounded-lg overflow-hidden">
252
+ <table class="min-w-full divide-y divide-gray-200">
253
+ <thead class="bg-gray-50">
254
+ <tr>
255
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">File Name</th>
256
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Size</th>
257
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Progress</th>
258
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Action</th>
259
+ </tr>
260
+ </thead>
261
+ <tbody class="bg-white divide-y divide-gray-200" id="uploadQueue">
262
+ <!-- Upload queue will be inserted here -->
263
+ </tbody>
264
+ </table>
265
+ </div>
266
+ </div>
267
+
268
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
269
+ <div>
270
+ <label for="workoutName" class="block text-sm font-medium text-gray-700 mb-1">Workout Name</label>
271
+ <input type="text" id="workoutName" class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="e.g. Upper Body Strength">
272
+ </div>
273
+ <div>
274
+ <label for="trainingName" class="block text-sm font-medium text-gray-700 mb-1">Training Name</label>
275
+ <input type="text" id="trainingName" class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="e.g. Shoulder Press Technique">
276
+ </div>
277
+ </div>
278
+
279
+ <div class="mt-6">
280
+ <label for="videoTags" class="block text-sm font-medium text-gray-700 mb-1">Tags (comma separated)</label>
281
+ <input type="text" id="videoTags" class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="e.g. strength, shoulders, technique">
282
+ </div>
283
+
284
+ <div class="mt-6">
285
+ <label for="videoDescription" class="block text-sm font-medium text-gray-700 mb-1">Description</label>
286
+ <textarea id="videoDescription" rows="3" class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="Add a description for this workout video..."></textarea>
287
+ </div>
288
+
289
+ <div class="mt-6 flex justify-end">
290
+ <button id="cancelUpload" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 mr-3">Cancel</button>
291
+ <button id="startUpload" class="px-4 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700">Start Upload</button>
292
+ </div>
293
+ </div>
294
+ </div>
295
+
296
+ <!-- Video Library Content -->
297
+ <div id="libraryContent" class="hidden">
298
+ <div class="bg-white p-6 rounded-lg shadow mb-6">
299
+ <div class="flex flex-col md:flex-row md:items-center md:justify-between mb-6">
300
+ <h2 class="text-xl font-semibold mb-4 md:mb-0">Video Library</h2>
301
+
302
+ <div class="flex flex-col sm:flex-row gap-3">
303
+ <div class="relative">
304
+ <select id="sortBy" class="appearance-none pl-3 pr-8 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 bg-white">
305
+ <option value="date-desc">Sort by: Newest First</option>
306
+ <option value="date-asc">Sort by: Oldest First</option>
307
+ <option value="name-asc">Sort by: Name (A-Z)</option>
308
+ <option value="name-desc">Sort by: Name (Z-A)</option>
309
+ </select>
310
+ <i class="fas fa-chevron-down absolute right-3 top-3 text-gray-400 pointer-events-none"></i>
311
+ </div>
312
+
313
+ <div class="relative">
314
+ <select id="filterBy" class="appearance-none pl-3 pr-8 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 bg-white">
315
+ <option value="all">Filter by: All Videos</option>
316
+ <option value="week">This Week</option>
317
+ <option value="month">This Month</option>
318
+ <option value="year">This Year</option>
319
+ </select>
320
+ <i class="fas fa-chevron-down absolute right-3 top-3 text-gray-400 pointer-events-none"></i>
321
+ </div>
322
+ </div>
323
+ </div>
324
+
325
+ <div class="mb-4">
326
+ <div class="tag-cloud" id="activeFilters">
327
+ <!-- Active filters will be shown here -->
328
+ </div>
329
+ </div>
330
+
331
+ <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6" id="videoGrid">
332
+ <!-- Videos will be inserted here -->
333
+ </div>
334
+
335
+ <div class="mt-6 flex justify-center" id="loadMoreContainer">
336
+ <button id="loadMoreVideos" class="px-4 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700">Load More Videos</button>
337
+ </div>
338
+ </div>
339
+ </div>
340
+
341
+ <!-- Tags Management Content -->
342
+ <div id="tagsContent" class="hidden">
343
+ <div class="bg-white p-6 rounded-lg shadow mb-6">
344
+ <div class="flex justify-between items-center mb-6">
345
+ <h2 class="text-xl font-semibold">Manage Tags</h2>
346
+ <button id="addNewTag" class="px-4 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 flex items-center">
347
+ <i class="fas fa-plus mr-2"></i> New Tag
348
+ </button>
349
+ </div>
350
+
351
+ <div class="mb-6">
352
+ <div class="relative">
353
+ <input type="text" id="tagSearch" class="w-full pl-10 pr-4 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="Search tags...">
354
+ <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
355
+ </div>
356
+ </div>
357
+
358
+ <div class="border rounded-lg overflow-hidden">
359
+ <table class="min-w-full divide-y divide-gray-200">
360
+ <thead class="bg-gray-50">
361
+ <tr>
362
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tag Name</th>
363
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Color</th>
364
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Videos Count</th>
365
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
366
+ </tr>
367
+ </thead>
368
+ <tbody class="bg-white divide-y divide-gray-200" id="tagsTable">
369
+ <!-- Tags will be inserted here -->
370
+ </tbody>
371
+ </table>
372
+ </div>
373
+ </div>
374
+ </div>
375
+
376
+ <!-- Video Detail Modal -->
377
+ <div id="videoModal" class="fixed inset-0 z-50 hidden overflow-y-auto">
378
+ <div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
379
+ <div class="fixed inset-0 transition-opacity" aria-hidden="true">
380
+ <div class="absolute inset-0 bg-gray-500 opacity-75"></div>
381
+ </div>
382
+
383
+ <span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
384
+
385
+ <div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-4xl sm:w-full">
386
+ <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
387
+ <div class="flex justify-between items-start">
388
+ <h3 class="text-lg font-medium text-gray-900" id="modalVideoTitle">Video Title</h3>
389
+ <button id="closeModal" class="text-gray-400 hover:text-gray-500">
390
+ <i class="fas fa-times"></i>
391
+ </button>
392
+ </div>
393
+
394
+ <div class="mt-4 video-player-container bg-black rounded-lg overflow-hidden">
395
+ <video controls class="w-full h-full" id="modalVideoPlayer">
396
+ Your browser does not support the video tag.
397
+ </video>
398
+ </div>
399
+
400
+ <div class="mt-4 grid grid-cols-1 md:grid-cols-3 gap-4">
401
+ <div class="md:col-span-2">
402
+ <div class="flex items-center mb-2">
403
+ <i class="fas fa-calendar-alt text-gray-500 mr-2"></i>
404
+ <span class="text-sm text-gray-600" id="modalVideoDate">Uploaded on: </span>
405
+ </div>
406
+ <div class="flex items-center mb-2">
407
+ <i class="fas fa-tag text-gray-500 mr-2"></i>
408
+ <div class="tag-cloud" id="modalVideoTags">
409
+ <!-- Tags will be inserted here -->
410
+ </div>
411
+ </div>
412
+ <div class="flex items-center mb-2">
413
+ <i class="fas fa-dumbbell text-gray-500 mr-2"></i>
414
+ <span class="text-sm text-gray-600" id="modalVideoWorkout">Workout: </span>
415
+ </div>
416
+ <div class="flex items-center mb-2">
417
+ <i class="fas fa-running text-gray-500 mr-2"></i>
418
+ <span class="text-sm text-gray-600" id="modalVideoTraining">Training: </span>
419
+ </div>
420
+ <div class="mt-3">
421
+ <p class="text-sm text-gray-700" id="modalVideoDescription">No description provided.</p>
422
+ </div>
423
+ </div>
424
+
425
+ <div class="bg-gray-50 p-4 rounded-lg">
426
+ <h4 class="font-medium mb-3">Share Options</h4>
427
+ <div class="space-y-3">
428
+ <button class="w-full flex items-center justify-center px-4 py-2 border border-gray-300 rounded-md bg-white text-gray-700 hover:bg-gray-50">
429
+ <i class="fab fa-whatsapp text-green-500 mr-2"></i> Share via WhatsApp
430
+ </button>
431
+ <button class="w-full flex items-center justify-center px-4 py-2 border border-gray-300 rounded-md bg-white text-gray-700 hover:bg-gray-50">
432
+ <i class="fas fa-envelope text-blue-500 mr-2"></i> Share via Email
433
+ </button>
434
+ <div class="mt-2">
435
+ <label class="block text-sm font-medium text-gray-700 mb-1">Direct Link</label>
436
+ <div class="flex">
437
+ <input type="text" id="videoLink" class="flex-1 px-3 py-2 border rounded-l-md focus:outline-none focus:ring-2 focus:ring-indigo-500" readonly>
438
+ <button id="copyLink" class="px-3 py-2 bg-indigo-600 text-white rounded-r-md hover:bg-indigo-700">
439
+ <i class="fas fa-copy"></i>
440
+ </button>
441
+ </div>
442
+ </div>
443
+ </div>
444
+
445
+ <div class="mt-4 pt-4 border-t border-gray-200">
446
+ <h4 class="font-medium mb-3">Video Actions</h4>
447
+ <div class="space-y-2">
448
+ <button id="editVideoBtn" class="w-full flex items-center justify-start px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-md">
449
+ <i class="fas fa-edit text-indigo-500 mr-2"></i> Edit Details
450
+ </button>
451
+ <button id="downloadVideoBtn" class="w-full flex items-center justify-start px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-md">
452
+ <i class="fas fa-download text-green-500 mr-2"></i> Download Video
453
+ </button>
454
+ <button id="deleteVideoBtn" class="w-full flex items-center justify-start px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-md">
455
+ <i class="fas fa-trash-alt text-red-500 mr-2"></i> Delete Video
456
+ </button>
457
+ </div>
458
+ </div>
459
+ </div>
460
+ </div>
461
+ </div>
462
+ </div>
463
+ </div>
464
+ </div>
465
+
466
+ <!-- Edit Video Modal -->
467
+ <div id="editVideoModal" class="fixed inset-0 z-50 hidden overflow-y-auto">
468
+ <div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
469
+ <div class="fixed inset-0 transition-opacity" aria-hidden="true">
470
+ <div class="absolute inset-0 bg-gray-500 opacity-75"></div>
471
+ </div>
472
+
473
+ <span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
474
+
475
+ <div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-2xl sm:w-full">
476
+ <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
477
+ <div class="flex justify-between items-start">
478
+ <h3 class="text-lg font-medium text-gray-900">Edit Video Details</h3>
479
+ <button id="closeEditModal" class="text-gray-400 hover:text-gray-500">
480
+ <i class="fas fa-times"></i>
481
+ </button>
482
+ </div>
483
+
484
+ <div class="mt-4">
485
+ <input type="hidden" id="editVideoId">
486
+
487
+ <div class="mb-4">
488
+ <label for="editVideoTitle" class="block text-sm font-medium text-gray-700 mb-1">Video Title</label>
489
+ <input type="text" id="editVideoTitle" class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
490
+ </div>
491
+
492
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
493
+ <div>
494
+ <label for="editWorkoutName" class="block text-sm font-medium text-gray-700 mb-1">Workout Name</label>
495
+ <input type="text" id="editWorkoutName" class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
496
+ </div>
497
+ <div>
498
+ <label for="editTrainingName" class="block text-sm font-medium text-gray-700 mb-1">Training Name</label>
499
+ <input type="text" id="editTrainingName" class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
500
+ </div>
501
+ </div>
502
+
503
+ <div class="mb-4">
504
+ <label for="editVideoTags" class="block text-sm font-medium text-gray-700 mb-1">Tags (comma separated)</label>
505
+ <input type="text" id="editVideoTags" class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
506
+ </div>
507
+
508
+ <div>
509
+ <label for="editVideoDescription" class="block text-sm font-medium text-gray-700 mb-1">Description</label>
510
+ <textarea id="editVideoDescription" rows="3" class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500"></textarea>
511
+ </div>
512
+ </div>
513
+ </div>
514
+
515
+ <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
516
+ <button id="saveVideoChanges" class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-indigo-600 text-base font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:ml-3 sm:w-auto sm:text-sm">
517
+ Save Changes
518
+ </button>
519
+ <button id="cancelVideoEdit" class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm">
520
+ Cancel
521
+ </button>
522
+ </div>
523
+ </div>
524
+ </div>
525
+ </div>
526
+
527
+ <!-- Add Tag Modal -->
528
+ <div id="addTagModal" class="fixed inset-0 z-50 hidden overflow-y-auto">
529
+ <div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
530
+ <div class="fixed inset-0 transition-opacity" aria-hidden="true">
531
+ <div class="absolute inset-0 bg-gray-500 opacity-75"></div>
532
+ </div>
533
+
534
+ <span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
535
+
536
+ <div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-md sm:w-full">
537
+ <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
538
+ <div class="flex justify-between items-start">
539
+ <h3 class="text-lg font-medium text-gray-900">Add New Tag</h3>
540
+ <button id="closeTagModal" class="text-gray-400 hover:text-gray-500">
541
+ <i class="fas fa-times"></i>
542
+ </button>
543
+ </div>
544
+
545
+ <div class="mt-4">
546
+ <div class="mb-4">
547
+ <label for="newTagName" class="block text-sm font-medium text-gray-700 mb-1">Tag Name</label>
548
+ <input type="text" id="newTagName" class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
549
+ </div>
550
+
551
+ <div class="mb-4">
552
+ <label class="block text-sm font-medium text-gray-700 mb-1">Tag Color</label>
553
+ <div class="flex flex-wrap gap-2">
554
+ <div class="w-8 h-8 rounded-full bg-red-500 cursor-pointer border-2 border-transparent hover:border-gray-300" data-color="red"></div>
555
+ <div class="w-8 h-8 rounded-full bg-blue-500 cursor-pointer border-2 border-transparent hover:border-gray-300" data-color="blue"></div>
556
+ <div class="w-8 h-8 rounded-full bg-green-500 cursor-pointer border-2 border-transparent hover:border-gray-300" data-color="green"></div>
557
+ <div class="w-8 h-8 rounded-full bg-yellow-500 cursor-pointer border-2 border-transparent hover:border-gray-300" data-color="yellow"></div>
558
+ <div class="w-8 h-8 rounded-full bg-indigo-500 cursor-pointer border-2 border-transparent hover:border-gray-300" data-color="indigo"></div>
559
+ <div class="w-8 h-8 rounded-full bg-purple-500 cursor-pointer border-2 border-transparent hover:border-gray-300" data-color="purple"></div>
560
+ <div class="w-8 h-8 rounded-full bg-pink-500 cursor-pointer border-2 border-transparent hover:border-gray-300" data-color="pink"></div>
561
+ <div class="w-8 h-8 rounded-full bg-gray-500 cursor-pointer border-2 border-transparent hover:border-gray-300" data-color="gray"></div>
562
+ </div>
563
+ <input type="hidden" id="selectedTagColor" value="indigo">
564
+ </div>
565
+ </div>
566
+ </div>
567
+
568
+ <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
569
+ <button id="saveNewTag" class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-indigo-600 text-base font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:ml-3 sm:w-auto sm:text-sm">
570
+ Add Tag
571
+ </button>
572
+ <button id="cancelNewTag" class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm">
573
+ Cancel
574
+ </button>
575
+ </div>
576
+ </div>
577
+ </div>
578
+ </div>
579
+
580
+ <!-- Confirmation Modal -->
581
+ <div id="confirmModal" class="fixed inset-0 z-50 hidden overflow-y-auto">
582
+ <div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
583
+ <div class="fixed inset-0 transition-opacity" aria-hidden="true">
584
+ <div class="absolute inset-0 bg-gray-500 opacity-75"></div>
585
+ </div>
586
+
587
+ <span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
588
+
589
+ <div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
590
+ <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
591
+ <div class="sm:flex sm:items-start">
592
+ <div class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10">
593
+ <i class="fas fa-exclamation-triangle text-red-600"></i>
594
+ </div>
595
+ <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
596
+ <h3 class="text-lg leading-6 font-medium text-gray-900" id="confirmModalTitle">Confirm Action</h3>
597
+ <div class="mt-2">
598
+ <p class="text-sm text-gray-500" id="confirmModalMessage">Are you sure you want to perform this action?</p>
599
+ </div>
600
+ </div>
601
+ </div>
602
+ </div>
603
+ <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
604
+ <button id="confirmAction" class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">
605
+ Confirm
606
+ </button>
607
+ <button id="cancelAction" class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm">
608
+ Cancel
609
+ </button>
610
+ </div>
611
+ </div>
612
+ </div>
613
+ </div>
614
+
615
+ <!-- Notification Toast -->
616
+ <div id="toast" class="fixed bottom-4 right-4 hidden">
617
+ <div class="bg-green-500 text-white px-4 py-2 rounded-md shadow-lg flex items-center">
618
+ <i class="fas fa-check-circle mr-2"></i>
619
+ <span id="toastMessage">Operation completed successfully!</span>
620
+ <button id="closeToast" class="ml-4">
621
+ <i class="fas fa-times"></i>
622
+ </button>
623
+ </div>
624
+ </div>
625
+ </main>
626
+ </div>
627
+ </div>
628
+
629
+ <script>
630
+ // Sample data storage (in a real app, this would be a database)
631
+ let videos = [];
632
+ let tags = [
633
+ { id: 1, name: 'strength', color: 'red', count: 0 },
634
+ { id: 2, name: 'cardio', color: 'blue', count: 0 },
635
+ { id: 3, name: 'flexibility', color: 'green', count: 0 },
636
+ { id: 4, name: 'technique', color: 'yellow', count: 0 },
637
+ { id: 5, name: 'beginner', color: 'indigo', count: 0 },
638
+ { id: 6, name: 'advanced', color: 'purple', count: 0 }
639
+ ];
640
+
641
+ // DOM Elements
642
+ const menuBtn = document.getElementById('menuBtn');
643
+ const closeSidebar = document.getElementById('closeSidebar');
644
+ const sidebar = document.querySelector('.sidebar');
645
+ const pageTitle = document.getElementById('pageTitle');
646
+ const mainContent = document.getElementById('mainContent');
647
+
648
+ // Content sections
649
+ const dashboardContent = document.getElementById('dashboardContent');
650
+ const uploadContent = document.getElementById('uploadContent');
651
+ const libraryContent = document.getElementById('libraryContent');
652
+ const tagsContent = document.getElementById('tagsContent');
653
+
654
+ // Navigation buttons
655
+ const dashboardBtn = document.getElementById('dashboardBtn');
656
+ const uploadBtn = document.getElementById('uploadBtn');
657
+ const libraryBtn = document.getElementById('libraryBtn');
658
+ const tagsBtn = document.getElementById('tagsBtn');
659
+
660
+ // Quick action buttons
661
+ const quickUploadBtn = document.getElementById('quickUploadBtn');
662
+ const quickTagBtn = document.getElementById('quickTagBtn');
663
+ const quickShareBtn = document.getElementById('quickShareBtn');
664
+ const quickStatsBtn = document.getElementById('quickStatsBtn');
665
+ const viewAllVideos = document.getElementById('viewAllVideos');
666
+
667
+ // Upload section elements
668
+ const dropArea = document.getElementById('dropArea');
669
+ const videoUpload = document.getElementById('videoUpload');
670
+ const uploadQueue = document.getElementById('uploadQueue');
671
+ const startUpload = document.getElementById('startUpload');
672
+ const cancelUpload = document.getElementById('cancelUpload');
673
+
674
+ // Library section elements
675
+ const videoGrid = document.getElementById('videoGrid');
676
+ const sortBy = document.getElementById('sortBy');
677
+ const filterBy = document.getElementById('filterBy');
678
+ const activeFilters = document.getElementById('activeFilters');
679
+ const loadMoreVideos = document.getElementById('loadMoreVideos');
680
+ const loadMoreContainer = document.getElementById('loadMoreContainer');
681
+ const popularTags = document.getElementById('popularTags');
682
+
683
+ // Tags section elements
684
+ const tagsTable = document.getElementById('tagsTable');
685
+ const addNewTag = document.getElementById('addNewTag');
686
+ const tagSearch = document.getElementById('tagSearch');
687
+
688
+ // Modal elements
689
+ const videoModal = document.getElementById('videoModal');
690
+ const modalVideoTitle = document.getElementById('modalVideoTitle');
691
+ const modalVideoPlayer = document.getElementById('modalVideoPlayer');
692
+ const modalVideoDate = document.getElementById('modalVideoDate');
693
+ const modalVideoTags = document.getElementById('modalVideoTags');
694
+ const modalVideoWorkout = document.getElementById('modalVideoWorkout');
695
+ const modalVideoTraining = document.getElementById('modalVideoTraining');
696
+ const modalVideoDescription = document.getElementById('modalVideoDescription');
697
+ const videoLink = document.getElementById('videoLink');
698
+ const copyLink = document.getElementById('copyLink');
699
+ const closeModal = document.getElementById('closeModal');
700
+
701
+ const editVideoModal = document.getElementById('editVideoModal');
702
+ const editVideoId = document.getElementById('editVideoId');
703
+ const editVideoTitle = document.getElementById('editVideoTitle');
704
+ const editWorkoutName = document.getElementById('editWorkoutName');
705
+ const editTrainingName = document.getElementById('editTrainingName');
706
+ const editVideoTags = document.getElementById('editVideoTags');
707
+ const editVideoDescription = document.getElementById('editVideoDescription');
708
+ const saveVideoChanges = document.getElementById('saveVideoChanges');
709
+ const cancelVideoEdit = document.getElementById('cancelVideoEdit');
710
+ const closeEditModal = document.getElementById('closeEditModal');
711
+
712
+ const addTagModal = document.getElementById('addTagModal');
713
+ const newTagName = document.getElementById('newTagName');
714
+ const selectedTagColor = document.getElementById('selectedTagColor');
715
+ const saveNewTag = document.getElementById('saveNewTag');
716
+ const cancelNewTag = document.getElementById('cancelNewTag');
717
+ const closeTagModal = document.getElementById('closeTagModal');
718
+
719
+ const confirmModal = document.getElementById('confirmModal');
720
+ const confirmModalTitle = document.getElementById('confirmModalTitle');
721
+ const confirmModalMessage = document.getElementById('confirmModalMessage');
722
+ const confirmAction = document.getElementById('confirmAction');
723
+ const cancelAction = document.getElementById('cancelAction');
724
+
725
+ const toast = document.getElementById('toast');
726
+ const toastMessage = document.getElementById('toastMessage');
727
+ const closeToast = document.getElementById('closeToast');
728
+
729
+ // App state
730
+ let currentView = 'dashboard';
731
+ let currentVideoPage = 1;
732
+ let videosPerPage = 8;
733
+ let selectedVideoId = null;
734
+ let filesToUpload = [];
735
+ let activeTagFilters = [];
736
+ let actionToConfirm = null;
737
+
738
+ // Initialize the app
739
+ function init() {
740
+ // Load sample data
741
+ loadSampleVideos();
742
+ updateTagCounts();
743
+
744
+ // Set up event listeners
745
+ setupEventListeners();
746
+
747
+ // Render initial views
748
+ renderDashboard();
749
+ renderPopularTags();
750
+ }
751
+
752
+ // Load sample videos for demo purposes
753
+ function loadSampleVideos() {
754
+ const sampleVideos = [
755
+ {
756
+ id: 1,
757
+ title: 'Shoulder Press Technique',
758
+ workout: 'Upper Body Strength',
759
+ training: 'Shoulder Press',
760
+ description: 'Detailed explanation of proper shoulder press technique to maximize results and prevent injury.',
761
+ tags: ['strength', 'shoulders', 'technique'],
762
+ date: new Date('2023-06-15'),
763
+ size: 45,
764
+ thumbnail: 'https://img.freepik.com/free-photo/fit-man-training-gym_651396-1025.jpg',
765
+ videoUrl: 'https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4'
766
+ },
767
+ {
768
+ id: 2,
769
+ title: 'Squat Depth and Form',
770
+ workout: 'Lower Body Strength',
771
+ training: 'Barbell Squat',
772
+ description: 'How to achieve proper squat depth while maintaining good form throughout the movement.',
773
+ tags: ['strength', 'legs', 'technique', 'beginner'],
774
+ date: new Date('2023-06-10'),
775
+ size: 62,
776
+ thumbnail: 'https://img.freepik.com/free-photo/young-healthy-man-athlete-doing-exercise-with-ropes-gym-single-male-model-performing-hard-training-his-upper-body-concept-healthy-lifestyle-sport-fitness-bodybuilding-wellbeing_155003-27804.jpg',
777
+ videoUrl: 'https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4'
778
+ },
779
+ {
780
+ id: 3,
781
+ title: 'HIIT Circuit Demo',
782
+ workout: 'Cardio Blast',
783
+ training: 'HIIT Routine',
784
+ description: 'Full demonstration of our 20-minute high intensity interval training circuit.',
785
+ tags: ['cardio', 'hiit', 'full-body'],
786
+ date: new Date('2023-06-05'),
787
+ size: 85,
788
+ thumbnail: 'https://img.freepik.com/free-photo/young-fitness-man-studio_7502-5008.jpg',
789
+ videoUrl: 'https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4'
790
+ },
791
+ {
792
+ id: 4,
793
+ title: 'Deadlift Variations',
794
+ workout: 'Power Lifting',
795
+ training: 'Deadlift',
796
+ description: 'Comparison of conventional, sumo, and Romanian deadlift variations with pros and cons of each.',
797
+ tags: ['strength', 'deadlift', 'advanced'],
798
+ date: new Date('2023-05-28'),
799
+ size: 78,
800
+ thumbnail: 'https://img.freepik.com/free-photo/young-fitness-man-studio_7502-5006.jpg',
801
+ videoUrl: 'https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4'
802
+ },
803
+ {
804
+ id: 5,
805
+ title: 'Dynamic Warmup Routine',
806
+ workout: 'Pre-Workout',
807
+ training: 'Warmup',
808
+ description: '10-minute dynamic warmup routine to prepare your body for intense training sessions.',
809
+ tags: ['warmup', 'flexibility', 'beginner'],
810
+ date: new Date('2023-05-20'),
811
+ size: 35,
812
+ thumbnail: 'https://img.freepik.com/free-photo/young-sports-man-training-gym_1303-14701.jpg',
813
+ videoUrl: 'https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4'
814
+ },
815
+ {
816
+ id: 6,
817
+ title: 'Advanced Pushup Variations',
818
+ workout: 'Bodyweight Training',
819
+ training: 'Pushups',
820
+ description: '10 challenging pushup variations to take your upper body training to the next level.',
821
+ tags: ['strength', 'bodyweight', 'advanced'],
822
+ date: new Date('2023-05-15'),
823
+ size: 52,
824
+ thumbnail: 'https://img.freepik.com/free-photo/young-sports-man-training-gym_1303-14696.jpg',
825
+ videoUrl: 'https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4'
826
+ },
827
+ {
828
+ id: 7,
829
+ title: 'Foam Rolling Techniques',
830
+ workout: 'Recovery',
831
+ training: 'Mobility',
832
+ description: 'How to properly use a foam roller to improve recovery and mobility after workouts.',
833
+ tags: ['recovery', 'flexibility', 'beginner'],
834
+ date: new Date('2023-05-10'),
835
+ size: 48,
836
+ thumbnail: 'https://img.freepik.com/free-photo/young-sports-man-training-gym_1303-14700.jpg',
837
+ videoUrl: 'https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4'
838
+ },
839
+ {
840
+ id: 8,
841
+ title: 'Kettlebell Swing Form',
842
+ workout: 'Functional Training',
843
+ training: 'Kettlebell',
844
+ description: 'Step-by-step guide to mastering the kettlebell swing for power and endurance.',
845
+ tags: ['strength', 'kettlebell', 'technique'],
846
+ date: new Date('2023-05-05'),
847
+ size: 55,
848
+ thumbnail: 'https://img.freepik.com/free-photo/young-sports-man-training-gym_1303-14699.jpg',
849
+ videoUrl: 'https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4'
850
+ }
851
+ ];
852
+
853
+ videos = sampleVideos;
854
+ }
855
+
856
+ // Update tag counts based on videos
857
+ function updateTagCounts() {
858
+ tags.forEach(tag => {
859
+ tag.count = videos.filter(video => video.tags.includes(tag.name)).length;
860
+ });
861
+ }
862
+
863
+ // Set up all event listeners
864
+ function setupEventListeners() {
865
+ // Navigation
866
+ menuBtn.addEventListener('click', toggleSidebar);
867
+ closeSidebar.addEventListener('click', toggleSidebar);
868
+
869
+ dashboardBtn.addEventListener('click', () => switchView('dashboard'));
870
+ uploadBtn.addEventListener('click', () => switchView('upload'));
871
+ libraryBtn.addEventListener('click', () => switchView('library'));
872
+ tagsBtn.addEventListener('click', () => switchView('tags'));
873
+
874
+ // Quick actions
875
+ quickUploadBtn.addEventListener('click', () => switchView('upload'));
876
+ quickTagBtn.addEventListener('click', () => switchView('tags'));
877
+ quickShareBtn.addEventListener('click', () => showToast('Share feature coming soon!'));
878
+ quickStatsBtn.addEventListener('click', () => showToast('Statistics feature coming soon!'));
879
+ viewAllVideos.addEventListener('click', () => switchView('library'));
880
+
881
+ // Upload section
882
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
883
+ dropArea.addEventListener(eventName, preventDefaults, false);
884
+ });
885
+
886
+ ['dragenter', 'dragover'].forEach(eventName => {
887
+ dropArea.addEventListener(eventName, highlight, false);
888
+ });
889
+
890
+ ['dragleave', 'drop'].forEach(eventName => {
891
+ dropArea.addEventListener(eventName, unhighlight, false);
892
+ });
893
+
894
+ dropArea.addEventListener('drop', handleDrop, false);
895
+ videoUpload.addEventListener('change', handleFiles, false);
896
+ startUpload.addEventListener('click', uploadFiles);
897
+ cancelUpload.addEventListener('click', clearUploadQueue);
898
+
899
+ // Library section
900
+ sortBy.addEventListener('change', renderVideoLibrary);
901
+ filterBy.addEventListener('change', renderVideoLibrary);
902
+ loadMoreVideos.addEventListener('click', loadMoreVideosHandler);
903
+
904
+ // Tags section
905
+ addNewTag.addEventListener('click', showAddTagModal);
906
+ tagSearch.addEventListener('input', filterTags);
907
+
908
+ // Video modal
909
+ closeModal.addEventListener('click', () => videoModal.classList.add('hidden'));
910
+ copyLink.addEventListener('click', copyVideoLink);
911
+ editVideoBtn.addEventListener('click', showEditVideoModal);
912
+ downloadVideoBtn.addEventListener('click', downloadVideo);
913
+ deleteVideoBtn.addEventListener('click', confirmDeleteVideo);
914
+
915
+ // Edit video modal
916
+ closeEditModal.addEventListener('click', () => editVideoModal.classList.add('hidden'));
917
+ cancelVideoEdit.addEventListener('click', () => editVideoModal.classList.add('hidden'));
918
+ saveVideoChanges.addEventListener('click', saveVideoEdits);
919
+
920
+ // Add tag modal
921
+ closeTagModal.addEventListener('click', () => addTagModal.classList.add('hidden'));
922
+ cancelNewTag.addEventListener('click', () => addTagModal.classList.add('hidden'));
923
+ saveNewTag.addEventListener('click', addNewTagHandler);
924
+
925
+ // Color selection in add tag modal
926
+ document.querySelectorAll('[data-color]').forEach(el => {
927
+ el.addEventListener('click', function() {
928
+ document.querySelectorAll('[data-color]').forEach(item => {
929
+ item.classList.remove('border-gray-300');
930
+ item.classList.add('border-transparent');
931
+ });
932
+ this.classList.remove('border-transparent');
933
+ this.classList.add('border-gray-300');
934
+ selectedTagColor.value = this.getAttribute('data-color');
935
+ });
936
+ });
937
+
938
+ // Confirmation modal
939
+ closeEditModal.addEventListener('click', () => confirmModal.classList.add('hidden'));
940
+ cancelAction.addEventListener('click', () => confirmModal.classList.add('hidden'));
941
+ confirmAction.addEventListener('click', performConfirmedAction);
942
+
943
+ // Toast notification
944
+ closeToast.addEventListener('click', () => toast.classList.add('hidden'));
945
+
946
+ // Filter buttons
947
+ document.querySelectorAll('[data-filter]').forEach(btn => {
948
+ btn.addEventListener('click', function() {
949
+ const filter = this.getAttribute('data-filter');
950
+ applyQuickFilter(filter);
951
+ });
952
+ });
953
+ }
954
+
955
+ // Toggle sidebar on mobile
956
+ function toggleSidebar() {
957
+ sidebar.classList.toggle('open');
958
+ }
959
+
960
+ // Switch between different views
961
+ function switchView(view) {
962
+ currentView = view;
963
+
964
+ // Hide all content sections
965
+ dashboardContent.classList.add('hidden');
966
+ uploadContent.classList.add('hidden');
967
+ libraryContent.classList.add('hidden');
968
+ tagsContent.classList.add('hidden');
969
+
970
+ // Reset active states on nav buttons
971
+ dashboardBtn.classList.remove('bg-indigo-800');
972
+ uploadBtn.classList.remove('bg-indigo-800');
973
+ libraryBtn.classList.remove('bg-indigo-800');
974
+ tagsBtn.classList.remove('bg-indigo-800');
975
+
976
+ // Show the selected content section
977
+ switch(view) {
978
+ case 'dashboard':
979
+ dashboardContent.classList.remove('hidden');
980
+ dashboardBtn.classList.add('bg-indigo-800');
981
+ pageTitle.textContent = 'Dashboard';
982
+ renderDashboard();
983
+ break;
984
+ case 'upload':
985
+ uploadContent.classList.remove('hidden');
986
+ uploadBtn.classList.add('bg-indigo-800');
987
+ pageTitle.textContent = 'Upload Videos';
988
+ break;
989
+ case 'library':
990
+ libraryContent.classList.remove('hidden');
991
+ libraryBtn.classList.add('bg-indigo-800');
992
+ pageTitle.textContent = 'Video Library';
993
+ currentVideoPage = 1;
994
+ renderVideoLibrary();
995
+ break;
996
+ case 'tags':
997
+ tagsContent.classList.remove('hidden');
998
+ tagsBtn.classList.add('bg-indigo-800');
999
+ pageTitle.textContent = 'Manage Tags';
1000
+ renderTagsTable();
1001
+ break;
1002
+ }
1003
+
1004
+ // Close sidebar on mobile after selection
1005
+ if (window.innerWidth < 768) {
1006
+ sidebar.classList.remove('open');
1007
+ }
1008
+ }
1009
+
1010
+ // Render dashboard content
1011
+ function renderDashboard() {
1012
+ // Update stats
1013
+ document.getElementById('totalVideos').textContent = videos.length;
1014
+ document.getElementById('totalTags').textContent = tags.length;
1015
+
1016
+ const totalSize = videos.reduce((sum, video) => sum + video.size, 0);
1017
+ document.getElementById('storageUsed').textContent = `${totalSize} MB`;
1018
+
1019
+ // Render recent videos
1020
+ const recentVideosContainer = document.getElementById('recentVideos');
1021
+ recentVideosContainer.innerHTML = '';
1022
+
1023
+ // Sort by date (newest first) and take first 3
1024
+ const recentVideos = [...videos].sort((a, b) => b.date - a.date).slice(0, 3);
1025
+
1026
+ recentVideos.forEach(video => {
1027
+ const videoElement = createVideoCard(video, true);
1028
+ recentVideosContainer.appendChild(videoElement);
1029
+ });
1030
+ }
1031
+
1032
+ // Render video library
1033
+ function renderVideoLibrary() {
1034
+ videoGrid.innerHTML = '';
1035
+ currentVideoPage = 1;
1036
+
1037
+ let filteredVideos = [...videos];
1038
+
1039
+ // Apply tag filters if any
1040
+ if (activeTagFilters.length > 0) {
1041
+ filteredVideos = filteredVideos.filter(video =>
1042
+ activeTagFilters.some(tag => video.tags.includes(tag))
1043
+ );
1044
+ }
1045
+
1046
+ // Apply time filter
1047
+ const timeFilter = filterBy.value;
1048
+ if (timeFilter !== 'all') {
1049
+ const now = new Date();
1050
+ let startDate;
1051
+
1052
+ switch(timeFilter) {
1053
+ case 'week':
1054
+ startDate = new Date(now.setDate(now.getDate() - 7));
1055
+ break;
1056
+ case 'month':
1057
+ startDate = new Date(now.setMonth(now.getMonth() - 1));
1058
+ break;
1059
+ case 'year':
1060
+ startDate = new Date(now.setFullYear(now.getFullYear() - 1));
1061
+ break;
1062
+ }
1063
+
1064
+ filteredVideos = filteredVideos.filter(video => video.date >= startDate);
1065
+ }
1066
+
1067
+ // Apply sorting
1068
+ const sortOption = sortBy.value;
1069
+ switch(sortOption) {
1070
+ case 'date-desc':
1071
+ filteredVideos.sort((a, b) => b.date - a.date);
1072
+ break;
1073
+ case 'date-asc':
1074
+ filteredVideos.sort((a, b) => a.date - b.date);
1075
+ break;
1076
+ case 'name-asc':
1077
+ filteredVideos.sort((a, b) => a.title.localeCompare(b.title));
1078
+ break;
1079
+ case 'name-desc':
1080
+ filteredVideos.sort((a, b) => b.title.localeCompare(a.title));
1081
+ break;
1082
+ }
1083
+
1084
+ // Display active filters
1085
+ renderActiveFilters();
1086
+
1087
+ // Check if there are videos to display
1088
+ if (filteredVideos.length === 0) {
1089
+ videoGrid.innerHTML = `
1090
+ <div class="col-span-full text-center py-10">
1091
+ <i class="fas fa-video-slash text-4xl text-gray-400 mb-3"></i>
1092
+ <h3 class="text-lg font-medium text-gray-700">No videos found</h3>
1093
+ <p class="text-gray-500">Try adjusting your filters or upload new videos</p>
1094
+ </div>
1095
+ `;
1096
+ loadMoreContainer.classList.add('hidden');
1097
+ return;
1098
+ }
1099
+
1100
+ // Display first page of videos
1101
+ displayVideosPaginated(filteredVideos);
1102
+
1103
+ // Show/hide load more button
1104
+ if (filteredVideos.length > videosPerPage * currentVideoPage) {
1105
+ loadMoreContainer.classList.remove('hidden');
1106
+ } else {
1107
+ loadMoreContainer.classList.add('hidden');
1108
+ }
1109
+ }
1110
+
1111
+ // Display videos with pagination
1112
+ function displayVideosPaginated(videoList) {
1113
+ const startIndex = 0;
1114
+ const endIndex = Math.min(videoList.length, videosPerPage * currentVideoPage);
1115
+
1116
+ for (let i = startIndex; i < endIndex; i++) {
1117
+ const video = videoList[i];
1118
+ const videoElement = createVideoCard(video);
1119
+ videoGrid.appendChild(videoElement);
1120
+ }
1121
+ }
1122
+
1123
+ // Load more videos handler
1124
+ function loadMoreVideosHandler() {
1125
+ currentVideoPage++;
1126
+ renderVideoLibrary();
1127
+
1128
+ // Scroll to the bottom of the video grid
1129
+ setTimeout(() => {
1130
+ videoGrid.scrollIntoView({ behavior: 'smooth', block: 'end' });
1131
+ }, 100);
1132
+ }
1133
+
1134
+ // Create a video card element
1135
+ function createVideoCard(video, isSmall = false) {
1136
+ const videoElement = document.createElement('div');
1137
+ videoElement.className = 'bg-white rounded-lg overflow-hidden shadow-md video-thumbnail';
1138
+ videoElement.dataset.id = video.id;
1139
+
1140
+ // Format date
1141
+ const formattedDate = video.date.toLocaleDateString('en-US', {
1142
+ year: 'numeric',
1143
+ month: 'short',
1144
+ day: 'numeric'
1145
+ });
1146
+
1147
+ if (isSmall) {
1148
+ videoElement.innerHTML = `
1149
+ <div class="cursor-pointer" onclick="openVideoModal(${video.id})">
1150
+ <div class="relative pb-[56.25%] bg-gray-200">
1151
+ <img src="${video.thumbnail}" alt="${video.title}" class="absolute h-full w-full object-cover">
1152
+ <div class="absolute bottom-2 right-2 bg-black bg-opacity-70 text-white text-xs px-2 py-1 rounded">
1153
+ ${video.size} MB
1154
+ </div>
1155
+ </div>
1156
+ <div class="p-3">
1157
+ <h3 class="font-medium text-gray-800 truncate">${video.title}</h3>
1158
+ <p class="text-xs text-gray-500 mt-1">${formattedDate}</p>
1159
+ <div class="flex flex-wrap gap-1 mt-2">
1160
+ ${video.tags.map(tag => createTagElement(tag)).join('')}
1161
+ </div>
1162
+ </div>
1163
+ </div>
1164
+ `;
1165
+ } else {
1166
+ videoElement.innerHTML = `
1167
+ <div class="cursor-pointer" onclick="openVideoModal(${video.id})">
1168
+ <div class="relative pb-[56.25%] bg-gray-200">
1169
+ <img src="${video.thumbnail}" alt="${video.title}" class="absolute h-full w-full object-cover">
1170
+ <div class="absolute inset-0 flex items-center justify-center opacity-0 hover:opacity-100 bg-black bg-opacity-30 transition-opacity">
1171
+ <div class="bg-white bg-opacity-80 rounded-full p-3">
1172
+ <i class="fas fa-play text-indigo-600"></i>
1173
+ </div>
1174
+ </div>
1175
+ <div class="absolute bottom-2 right-2 bg-black bg-opacity-70 text-white text-xs px-2 py-1 rounded">
1176
+ ${video.size} MB
1177
+ </div>
1178
+ </div>
1179
+ <div class="p-4">
1180
+ <h3 class="font-medium text-gray-800 truncate">${video.title}</h3>
1181
+ <p class="text-sm text-gray-500 mt-1">${video.workout} • ${video.training}</p>
1182
+ <p class="text-xs text-gray-500 mt-1">${formattedDate}</p>
1183
+ <div class="flex flex-wrap gap-1 mt-2">
1184
+ ${video.tags.map(tag => createTagElement(tag)).join('')}
1185
+ </div>
1186
+ </div>
1187
+ </div>
1188
+ `;
1189
+ }
1190
+
1191
+ return videoElement;
1192
+ }
1193
+
1194
+ // Create a tag element
1195
+ function createTagElement(tagName, isClickable = true) {
1196
+ const tag = tags.find(t => t.name === tagName);
1197
+ const color = tag ? tag.color : 'gray';
1198
+
1199
+ if (isClickable) {
1200
+ return `<span class="tag-item inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-${color}-100 text-${color}-800" onclick="event.stopPropagation(); filterByTag('${tagName}')">${tagName}</span>`;
1201
+ } else {
1202
+ return `<span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-${color}-100 text-${color}-800">${tagName}</span>`;
1203
+ }
1204
+ }
1205
+
1206
+ // Render active filters
1207
+ function renderActiveFilters() {
1208
+ activeFilters.innerHTML = '';
1209
+
1210
+ if (activeTagFilters.length > 0) {
1211
+ const filterTitle = document.createElement('span');
1212
+ filterTitle.className = 'text-sm text-gray-500 mr-2';
1213
+ filterTitle.textContent = 'Active filters:';
1214
+ activeFilters.appendChild(filterTitle);
1215
+
1216
+ activeTagFilters.forEach(tag => {
1217
+ const tagElement = document.createElement('span');
1218
+ tagElement.className = 'tag-item inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-indigo-100 text-indigo-800';
1219
+ tagElement.innerHTML = `${tag} <button class="ml-1 text-indigo-500 hover:text-indigo-700" onclick="removeTagFilter('${tag}')"><i class="fas fa-times"></i></button>`;
1220
+ activeFilters.appendChild(tagElement);
1221
+ });
1222
+
1223
+ if (activeTagFilters.length > 0) {
1224
+ const clearAll = document.createElement('button');
1225
+ clearAll.className = 'text-sm text-indigo-600 hover:text-indigo-800 ml-2';
1226
+ clearAll.textContent = 'Clear all';
1227
+ clearAll.onclick = clearAllFilters;
1228
+ activeFilters.appendChild(clearAll);
1229
+ }
1230
+ }
1231
+ }
1232
+
1233
+ // Filter by tag
1234
+ function filterByTag(tagName) {
1235
+ if (!activeTagFilters.includes(tagName)) {
1236
+ activeTagFilters.push(tagName);
1237
+ renderVideoLibrary();
1238
+ }
1239
+ }
1240
+
1241
+ // Remove tag filter
1242
+ function removeTagFilter(tagName) {
1243
+ activeTagFilters = activeTagFilters.filter(tag => tag !== tagName);
1244
+ renderVideoLibrary();
1245
+ }
1246
+
1247
+ // Clear all filters
1248
+ function clearAllFilters() {
1249
+ activeTagFilters = [];
1250
+ filterBy.value = 'all';
1251
+ renderVideoLibrary();
1252
+ }
1253
+
1254
+ // Apply quick filter from sidebar
1255
+ function applyQuickFilter(filter) {
1256
+ activeTagFilters = [];
1257
+
1258
+ switch(filter) {
1259
+ case 'recent':
1260
+ sortBy.value = 'date-desc';
1261
+ filterBy.value = 'all';
1262
+ break;
1263
+ case 'week':
1264
+ filterBy.value = 'week';
1265
+ break;
1266
+ case 'month':
1267
+ filterBy.value = 'month';
1268
+ break;
1269
+ }
1270
+
1271
+ switchView('library');
1272
+ }
1273
+
1274
+ // Render popular tags in sidebar
1275
+ function renderPopularTags() {
1276
+ popularTags.innerHTML = '';
1277
+
1278
+ // Sort tags by count (descending) and take top 6
1279
+ const popular = [...tags].sort((a, b) => b.count - a.count).slice(0, 6);
1280
+
1281
+ popular.forEach(tag => {
1282
+ const tagElement = document.createElement('span');
1283
+ tagElement.className = `tag-item inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-${tag.color}-100 text-${tag.color}-800`;
1284
+ tagElement.textContent = tag.name;
1285
+ tagElement.onclick = function() {
1286
+ switchView('library');
1287
+ filterByTag(tag.name);
1288
+ };
1289
+ popularTags.appendChild(tagElement);
1290
+ });
1291
+ }
1292
+
1293
+ // Render tags table
1294
+ function renderTagsTable() {
1295
+ tagsTable.innerHTML = '';
1296
+
1297
+ if (tags.length === 0) {
1298
+ tagsTable.innerHTML = `
1299
+ <tr>
1300
+ <td colspan="4" class="px-6 py-4 text-center text-gray-500">
1301
+ No tags found. Create your first tag to get started.
1302
+ </td>
1303
+ </tr>
1304
+ `;
1305
+ return;
1306
+ }
1307
+
1308
+ tags.forEach(tag => {
1309
+ const row = document.createElement('tr');
1310
+ row.innerHTML = `
1311
+ <td class="px-6 py-4 whitespace-nowrap">
1312
+ <span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-${tag.color}-100 text-${tag.color}-800">
1313
+ ${tag.name}
1314
+ </span>
1315
+ </td>
1316
+ <td class="px-6 py-4 whitespace-nowrap">
1317
+ <div class="w-4 h-4 rounded-full bg-${tag.color}-500"></div>
1318
+ </td>
1319
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
1320
+ ${tag.count} videos
1321
+ </td>
1322
+ <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
1323
+ <button class="text-indigo-600 hover:text-indigo-900 mr-3" onclick="editTag(${tag.id})">
1324
+ <i class="fas fa-edit"></i>
1325
+ </button>
1326
+ <button class="text-red-600 hover:text-red-900" onclick="confirmDeleteTag(${tag.id})">
1327
+ <i class="fas fa-trash-alt"></i>
1328
+ </button>
1329
+ </td>
1330
+ `;
1331
+ tagsTable.appendChild(row);
1332
+ });
1333
+ }
1334
+
1335
+ // Filter tags based on search input
1336
+ function filterTags() {
1337
+ const searchTerm = tagSearch.value.toLowerCase();
1338
+
1339
+ document.querySelectorAll('#tagsTable tr').forEach(row => {
1340
+ if (row.cells.length === 1) return; // Skip the "no tags" row
1341
+
1342
+ const tagName = row.cells[0].textContent.toLowerCase();
1343
+ if (tagName.includes(searchTerm)) {
1344
+ row.style.display = '';
1345
+ } else {
1346
+ row.style.display = 'none';
1347
+ }
1348
+ });
1349
+ }
1350
+
1351
+ // Show add tag modal
1352
+ function showAddTagModal() {
1353
+ newTagName.value = '';
1354
+ selectedTagColor.value = 'indigo';
1355
+
1356
+ // Reset color selection
1357
+ document.querySelectorAll('[data-color]').forEach(item => {
1358
+ item.classList.remove('border-gray-300');
1359
+ item.classList.add('border-transparent');
1360
+ });
1361
+
1362
+ // Select indigo by default
1363
+ document.querySelector('[data-color="indigo"]').classList.add('border-gray-300');
1364
+
1365
+ addTagModal.classList.remove('hidden');
1366
+ }
1367
+
1368
+ // Add new tag handler
1369
+ function addNewTagHandler() {
1370
+ const name = newTagName.value.trim();
1371
+ const color = selectedTagColor.value;
1372
+
1373
+ if (!name) {
1374
+ showToast('Please enter a tag name');
1375
+ return;
1376
+ }
1377
+
1378
+ if (tags.some(tag => tag.name === name)) {
1379
+ showToast('Tag already exists');
1380
+ return;
1381
+ }
1382
+
1383
+ const newTag = {
1384
+ id: tags.length > 0 ? Math.max(...tags.map(t => t.id)) + 1 : 1,
1385
+ name,
1386
+ color,
1387
+ count: 0
1388
+ };
1389
+
1390
+ tags.push(newTag);
1391
+ renderTagsTable();
1392
+ renderPopularTags();
1393
+ addTagModal.classList.add('hidden');
1394
+ showToast('Tag added successfully');
1395
+ }
1396
+
1397
+ // Edit tag
1398
+ function editTag(tagId) {
1399
+ // In a real app, this would open an edit modal
1400
+ showToast('Edit tag feature coming soon!');
1401
+ }
1402
+
1403
+ // Confirm tag deletion
1404
+ function confirmDeleteTag(tagId) {
1405
+ const tag = tags.find(t => t.id === tagId);
1406
+
1407
+ if (!tag) return;
1408
+
1409
+ if (tag.count > 0) {
1410
+ showToast('Cannot delete tag that is in use by videos');
1411
+ return;
1412
+ }
1413
+
1414
+ confirmModalTitle.textContent = 'Delete Tag';
1415
+ confirmModalMessage.textContent = `Are you sure you want to delete the tag "${tag.name}"? This action cannot be undone.`;
1416
+
1417
+ actionToConfirm = () => {
1418
+ tags = tags.filter(t => t.id !== tagId);
1419
+ renderTagsTable();
1420
+ renderPopularTags();
1421
+ confirmModal.classList.add('hidden');
1422
+ showToast('Tag deleted successfully');
1423
+ };
1424
+
1425
+ confirmModal.classList.remove('hidden');
1426
+ }
1427
+
1428
+ // Perform confirmed action
1429
+ function performConfirmedAction() {
1430
+ if (actionToConfirm) {
1431
+ actionToConfirm();
1432
+ actionToConfirm = null;
1433
+ }
1434
+ confirmModal.classList.add('hidden');
1435
+ }
1436
+
1437
+ // Upload section functions
1438
+ function preventDefaults(e) {
1439
+ e.preventDefault();
1440
+ e.stopPropagation();
1441
+ }
1442
+
1443
+ function highlight() {
1444
+ dropArea.classList.add('dragover');
1445
+ }
1446
+
1447
+ function unhighlight() {
1448
+ dropArea.classList.remove('dragover');
1449
+ }
1450
+
1451
+ function handleDrop(e) {
1452
+ const dt = e.dataTransfer;
1453
+ const files = dt.files;
1454
+ handleFiles({ target: { files } });
1455
+ }
1456
+
1457
+ function handleFiles(e) {
1458
+ filesToUpload = [...e.target.files];
1459
+ renderUploadQueue();
1460
+ }
1461
+
1462
+ function renderUploadQueue() {
1463
+ uploadQueue.innerHTML = '';
1464
+
1465
+ if (filesToUpload.length === 0) {
1466
+ uploadQueue.innerHTML = `
1467
+ <tr>
1468
+ <td colspan="4" class="px-6 py-4 text-center text-gray-
1469
+ </html>
prompts.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ build a workout video archiver and editor app. where trainer can upload and edit his videos of exercises for every training. he can add tagging for workout and name of workout and training. then he could she it via whatsapp or email or link and he could view the videos by tag/workout/week/moth and sort chronologically or by tag