Hairitics commited on
Commit
24a7b9b
·
verified ·
1 Parent(s): 1f34ea2

a site to organize my Midjourney Prompts and Pictures - Initial Deployment

Browse files
Files changed (3) hide show
  1. README.md +7 -5
  2. index.html +761 -19
  3. prompts.txt +1 -0
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Midjourney Prompt Vault
3
- emoji: 🐨
4
- colorFrom: red
5
- colorTo: gray
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: midjourney-prompt-vault
3
+ emoji: 🐳
4
+ colorFrom: purple
5
+ colorTo: yellow
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,761 @@
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>Midjourney Prompt Organizer</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
+ .prompt-card:hover .prompt-actions {
11
+ opacity: 1;
12
+ }
13
+ .tag:hover {
14
+ transform: scale(1.05);
15
+ }
16
+ .grid-item {
17
+ transition: all 0.3s ease;
18
+ }
19
+ .grid-item:hover {
20
+ transform: translateY(-5px);
21
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
22
+ }
23
+ #lightbox {
24
+ transition: opacity 0.3s ease;
25
+ }
26
+ .loader {
27
+ border-top-color: #6366f1;
28
+ animation: spin 1s linear infinite;
29
+ }
30
+ @keyframes spin {
31
+ 0% { transform: rotate(0deg); }
32
+ 100% { transform: rotate(360deg); }
33
+ }
34
+ </style>
35
+ </head>
36
+ <body class="bg-gray-100 min-h-screen">
37
+ <!-- Header -->
38
+ <header class="bg-indigo-600 text-white shadow-lg">
39
+ <div class="container mx-auto px-4 py-6">
40
+ <div class="flex flex-col md:flex-row justify-between items-center">
41
+ <div class="flex items-center mb-4 md:mb-0">
42
+ <i class="fas fa-robot text-3xl mr-3"></i>
43
+ <h1 class="text-2xl md:text-3xl font-bold">Midjourney Prompt Vault</h1>
44
+ </div>
45
+ <button id="addNewBtn" class="bg-indigo-500 hover:bg-indigo-700 text-white font-bold py-2 px-4 rounded-full flex items-center transition duration-300">
46
+ <i class="fas fa-plus mr-2"></i> New Prompt
47
+ </button>
48
+ </div>
49
+ </div>
50
+ </header>
51
+
52
+ <!-- Main Content -->
53
+ <main class="container mx-auto px-4 py-8">
54
+ <!-- Search and Filters -->
55
+ <div class="bg-white rounded-xl shadow-md p-6 mb-8">
56
+ <div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
57
+ <div class="relative flex-grow">
58
+ <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
59
+ <input id="searchInput" type="text" placeholder="Search prompts..." class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500">
60
+ </div>
61
+ <div class="flex flex-wrap gap-2">
62
+ <select id="sortSelect" class="px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500">
63
+ <option value="newest">Newest First</option>
64
+ <option value="oldest">Oldest First</option>
65
+ <option value="az">A-Z</option>
66
+ <option value="za">Z-A</option>
67
+ </select>
68
+ <select id="filterSelect" class="px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500">
69
+ <option value="all">All Prompts</option>
70
+ <option value="favorite">Favorites</option>
71
+ <option value="character">Characters</option>
72
+ <option value="landscape">Landscapes</option>
73
+ <option value="concept">Concepts</option>
74
+ <option value="portrait">Portraits</option>
75
+ </select>
76
+ </div>
77
+ </div>
78
+ <div id="activeTags" class="flex flex-wrap gap-2 mt-4"></div>
79
+ </div>
80
+
81
+ <!-- Prompt Statistics -->
82
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
83
+ <div class="bg-white rounded-xl shadow-md p-6">
84
+ <div class="flex items-center">
85
+ <div class="p-3 rounded-full bg-indigo-100 text-indigo-600 mr-4">
86
+ <i class="fas fa-list text-lg"></i>
87
+ </div>
88
+ <div>
89
+ <p class="text-gray-500">Total Prompts</p>
90
+ <h3 id="totalPrompts" class="text-2xl font-bold">0</h3>
91
+ </div>
92
+ </div>
93
+ </div>
94
+ <div class="bg-white rounded-xl shadow-md p-6">
95
+ <div class="flex items-center">
96
+ <div class="p-3 rounded-full bg-blue-100 text-blue-600 mr-4">
97
+ <i class="fas fa-star text-lg"></i>
98
+ </div>
99
+ <div>
100
+ <p class="text-gray-500">Favorites</p>
101
+ <h3 id="favoritePrompts" class="text-2xl font-bold">0</h3>
102
+ </div>
103
+ </div>
104
+ </div>
105
+ <div class="bg-white rounded-xl shadow-md p-6">
106
+ <div class="flex items-center">
107
+ <div class="p-3 rounded-full bg-green-100 text-green-600 mr-4">
108
+ <i class="fas fa-tags text-lg"></i>
109
+ </div>
110
+ <div>
111
+ <p class="text-gray-500">Unique Tags</p>
112
+ <h3 id="uniqueTags" class="text-2xl font-bold">0</h3>
113
+ </div>
114
+ </div>
115
+ </div>
116
+ <div class="bg-white rounded-xl shadow-md p-6">
117
+ <div class="flex items-center">
118
+ <div class="p-3 rounded-full bg-purple-100 text-purple-600 mr-4">
119
+ <i class="fas fa-image text-lg"></i>
120
+ </div>
121
+ <div>
122
+ <p class="text-gray-500">Images</p>
123
+ <h3 id="totalImages" class="text-2xl font-bold">0</h3>
124
+ </div>
125
+ </div>
126
+ </div>
127
+ </div>
128
+
129
+ <!-- Prompts Grid -->
130
+ <div id="promptsContainer" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
131
+ <!-- Prompts will be loaded here -->
132
+ <div id="emptyState" class="col-span-full text-center py-20">
133
+ <i class="fas fa-robot text-6xl text-gray-300 mb-4"></i>
134
+ <h3 class="text-2xl font-bold text-gray-700 mb-2">No prompts found</h3>
135
+ <p class="text-gray-500 mb-6">Start by adding your first Midjourney prompt</p>
136
+ <button id="emptyAddBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-2 px-6 rounded-full inline-flex items-center transition duration-300">
137
+ <i class="fas fa-plus mr-2"></i> Add Prompt
138
+ </button>
139
+ </div>
140
+ </div>
141
+ </main>
142
+
143
+ <!-- Add/Edit Prompt Modal -->
144
+ <div id="promptModal" class="fixed inset-0 bg-black bg-opacity-50 z-50 hidden flex items-center justify-center p-4">
145
+ <div class="bg-white rounded-xl shadow-xl w-full max-w-2xl max-h-[90vh] overflow-y-auto">
146
+ <div class="p-6">
147
+ <div class="flex justify-between items-center mb-4">
148
+ <h2 class="text-2xl font-bold" id="modalTitle">Add New Prompt</h2>
149
+ <button id="closeModal" class="text-gray-500 hover:text-gray-700">
150
+ <i class="fas fa-times text-xl"></i>
151
+ </button>
152
+ </div>
153
+
154
+ <form id="promptForm" class="space-y-4">
155
+ <input type="hidden" id="promptId">
156
+
157
+ <div>
158
+ <label for="promptText" class="block text-sm font-medium text-gray-700 mb-1">Prompt</label>
159
+ <textarea id="promptText" rows="5" class="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="Enter your Midjourney prompt..."></textarea>
160
+ </div>
161
+
162
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
163
+ <div>
164
+ <label for="promptName" class="block text-sm font-medium text-gray-700 mb-1">Name</label>
165
+ <input type="text" id="promptName" class="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="My Awesome Art">
166
+ </div>
167
+ <div>
168
+ <label for="promptModel" class="block text-sm font-medium text-gray-700 mb-1">Model Version</label>
169
+ <select id="promptModel" class="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500">
170
+ <option value="MJ 5.2">Midjourney 5.2</option>
171
+ <option value="MJ 5.1">Midjourney 5.1</option>
172
+ <option value="Niji 5">Niji 5</option>
173
+ <option value="Niji 4">Niji 4</option>
174
+ <option value="Other">Other</option>
175
+ </select>
176
+ </div>
177
+ </div>
178
+
179
+ <div>
180
+ <label for="promptParameters" class="block text-sm font-medium text-gray-700 mb-1">Parameters</label>
181
+ <input type="text" id="promptParameters" class="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="--ar 16:9 --v 5.2 --q 2">
182
+ </div>
183
+
184
+ <div>
185
+ <label for="promptImages" class="block text-sm font-medium text-gray-700 mb-1">Image URLs (one per line)</label>
186
+ <textarea id="promptImages" rows="3" class="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="https://example.com/image1.jpg"></textarea>
187
+ </div>
188
+
189
+ <div>
190
+ <label class="block text-sm font-medium text-gray-700 mb-2">Tags</label>
191
+ <div class="flex flex-wrap gap-2 mb-2" id="currentTags"></div>
192
+ <div class="flex">
193
+ <input type="text" id="newTag" class="flex-grow p-2 border border-gray-300 rounded-l-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="Add new tag">
194
+ <button type="button" id="addTagBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 rounded-r-lg">Add</button>
195
+ </div>
196
+ </div>
197
+
198
+ <div class="flex items-center">
199
+ <input type="checkbox" id="isFavorite" class="w-4 h-4 text-indigo-600 border-gray-300 rounded focus:ring-indigo-500">
200
+ <label for="isFavorite" class="ml-2 text-sm text-gray-700">Mark as favorite</label>
201
+ </div>
202
+
203
+ <div class="flex justify-end space-x-3 pt-4">
204
+ <button type="button" id="cancelPrompt" class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50">Cancel</button>
205
+ <button type="submit" id="savePrompt" class="px-6 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">Save Prompt</button>
206
+ </div>
207
+ </form>
208
+ </div>
209
+ </div>
210
+ </div>
211
+
212
+ <!-- Lightbox Modal -->
213
+ <div id="lightbox" class="fixed inset-0 bg-black bg-opacity-90 z-50 hidden flex items-center justify-center p-4">
214
+ <div class="relative max-w-6xl w-full">
215
+ <button id="closeLightbox" class="absolute top-4 right-4 text-white text-3xl z-50">
216
+ <i class="fas fa-times"></i>
217
+ </button>
218
+ <div class="flex justify-between items-center absolute top-1/2 left-0 right-0 transform -translate-y-1/2 z-50 px-4">
219
+ <button id="prevImage" class="bg-black bg-opacity-50 text-white rounded-full w-10 h-10 flex items-center justify-center hover:bg-opacity-70">
220
+ <i class="fas fa-chevron-left"></i>
221
+ </button>
222
+ <button id="nextImage" class="bg-black bg-opacity-50 text-white rounded-full w-10 h-10 flex items-center justify-center hover:bg-opacity-70">
223
+ <i class="fas fa-chevron-right"></i>
224
+ </button>
225
+ </div>
226
+ <img id="lightboxImage" src="" alt="" class="max-h-[90vh] w-auto mx-auto">
227
+ <div id="lightboxCaption" class="text-white text-center mt-4"></div>
228
+ </div>
229
+ </div>
230
+
231
+ <!-- Loading Overlay -->
232
+ <div id="loadingOverlay" class="fixed inset-0 bg-black bg-opacity-50 z-50 hidden flex items-center justify-center">
233
+ <div class="bg-white p-8 rounded-lg shadow-xl flex flex-col items-center">
234
+ <div class="loader ease-linear rounded-full border-4 border-t-4 border-gray-200 h-12 w-12 mb-4"></div>
235
+ <p class="text-gray-700">Loading prompts...</p>
236
+ </div>
237
+ </div>
238
+
239
+ <script>
240
+ document.addEventListener('DOMContentLoaded', function() {
241
+ // Elements
242
+ const promptsContainer = document.getElementById('promptsContainer');
243
+ const emptyState = document.getElementById('emptyState');
244
+ const promptModal = document.getElementById('promptModal');
245
+ const lightbox = document.getElementById('lightbox');
246
+ const loadingOverlay = document.getElementById('loadingOverlay');
247
+
248
+ // Buttons
249
+ const addNewBtn = document.getElementById('addNewBtn');
250
+ const emptyAddBtn = document.getElementById('emptyAddBtn');
251
+ const closeModal = document.getElementById('closeModal');
252
+ const closeLightbox = document.getElementById('closeLightbox');
253
+ const prevImage = document.getElementById('prevImage');
254
+ const nextImage = document.getElementById('nextImage');
255
+ const cancelPrompt = document.getElementById('cancelPrompt');
256
+ const savePrompt = document.getElementById('savePrompt');
257
+ const addTagBtn = document.getElementById('addTagBtn');
258
+
259
+ // Form elements
260
+ const promptForm = document.getElementById('promptForm');
261
+ const promptId = document.getElementById('promptId');
262
+ const promptName = document.getElementById('promptName');
263
+ const promptText = document.getElementById('promptText');
264
+ const promptModel = document.getElementById('promptModel');
265
+ const promptParameters = document.getElementById('promptParameters');
266
+ const promptImages = document.getElementById('promptImages');
267
+ const currentTags = document.getElementById('currentTags');
268
+ const newTag = document.getElementById('newTag');
269
+ const isFavorite = document.getElementById('isFavorite');
270
+
271
+ // Search and filter elements
272
+ const searchInput = document.getElementById('searchInput');
273
+ const sortSelect = document.getElementById('sortSelect');
274
+ const filterSelect = document.getElementById('filterSelect');
275
+ const activeTags = document.getElementById('activeTags');
276
+
277
+ // Stats elements
278
+ const totalPrompts = document.getElementById('totalPrompts');
279
+ const favoritePrompts = document.getElementById('favoritePrompts');
280
+ const uniqueTags = document.getElementById('uniqueTags');
281
+ const totalImages = document.getElementById('totalImages');
282
+
283
+ // State
284
+ let prompts = JSON.parse(localStorage.getItem('midjourneyPrompts')) || [];
285
+ let currentTagsArray = [];
286
+ let currentLightboxImages = [];
287
+ let currentLightboxIndex = 0;
288
+
289
+ // Initialize
290
+ updateStats();
291
+ renderPrompts();
292
+ renderTagFilters();
293
+
294
+ // Event Listeners
295
+ addNewBtn.addEventListener('click', openNewPromptModal);
296
+ emptyAddBtn.addEventListener('click', openNewPromptModal);
297
+ closeModal.addEventListener('click', closePromptModal);
298
+ closeLightbox.addEventListener('click', closeLightboxModal);
299
+ cancelPrompt.addEventListener('click', closePromptModal);
300
+ promptForm.addEventListener('submit', savePromptHandler);
301
+ addTagBtn.addEventListener('click', addTag);
302
+
303
+ // Search and filter listeners
304
+ searchInput.addEventListener('input', renderPrompts);
305
+ sortSelect.addEventListener('change', renderPrompts);
306
+ filterSelect.addEventListener('change', renderPrompts);
307
+
308
+ // Functions
309
+ function openNewPromptModal() {
310
+ promptId.value = '';
311
+ promptForm.reset();
312
+ currentTagsArray = [];
313
+ renderCurrentTags();
314
+ document.getElementById('modalTitle').textContent = 'Add New Prompt';
315
+ promptModal.classList.remove('hidden');
316
+ }
317
+
318
+ function openEditPromptModal(id) {
319
+ const prompt = prompts.find(p => p.id === id);
320
+ if (prompt) {
321
+ promptId.value = prompt.id;
322
+ promptName.value = prompt.name || '';
323
+ promptText.value = prompt.text;
324
+ promptModel.value = prompt.model || 'MJ 5.2';
325
+ promptParameters.value = prompt.parameters || '';
326
+ promptImages.value = prompt.images?.join('\n') || '';
327
+ isFavorite.checked = prompt.favorite || false;
328
+ currentTagsArray = [...(prompt.tags || [])];
329
+ renderCurrentTags();
330
+
331
+ document.getElementById('modalTitle').textContent = 'Edit Prompt';
332
+ promptModal.classList.remove('hidden');
333
+ }
334
+ }
335
+
336
+ function closePromptModal() {
337
+ promptModal.classList.add('hidden');
338
+ }
339
+
340
+ function closeLightboxModal() {
341
+ lightbox.classList.add('hidden');
342
+ }
343
+
344
+ function addTag() {
345
+ const tag = newTag.value.trim();
346
+ if (tag && !currentTagsArray.includes(tag)) {
347
+ currentTagsArray.push(tag);
348
+ renderCurrentTags();
349
+ newTag.value = '';
350
+ }
351
+ }
352
+
353
+ function removeTag(tag) {
354
+ currentTagsArray = currentTagsArray.filter(t => t !== tag);
355
+ renderCurrentTags();
356
+ renderPrompts();
357
+ }
358
+
359
+ function renderCurrentTags() {
360
+ currentTags.innerHTML = '';
361
+ currentTagsArray.forEach(tag => {
362
+ const tagElement = document.createElement('span');
363
+ tagElement.className = 'inline-flex items-center bg-indigo-100 text-indigo-800 text-sm px-3 py-1 rounded-full';
364
+ tagElement.innerHTML = `
365
+ ${tag}
366
+ <button data-tag="${tag}" class="ml-2 text-indigo-600 hover:text-indigo-900">
367
+ <i class="fas fa-times"></i>
368
+ </button>
369
+ `;
370
+ currentTags.appendChild(tagElement);
371
+ });
372
+
373
+ // Add event listeners to remove buttons
374
+ currentTags.querySelectorAll('button').forEach(button => {
375
+ button.addEventListener('click', (e) => {
376
+ e.stopPropagation();
377
+ removeTag(button.dataset.tag);
378
+ });
379
+ });
380
+ }
381
+
382
+ function savePromptHandler(e) {
383
+ e.preventDefault();
384
+
385
+ const id = promptId.value || Date.now().toString();
386
+ const name = promptName.value.trim();
387
+ const text = promptText.value.trim();
388
+ const model = promptModel.value;
389
+ const parameters = promptParameters.value.trim();
390
+ const images = promptImages.value.split('\n').filter(url => url.trim());
391
+ const favorite = isFavorite.checked;
392
+ const tags = [...currentTagsArray];
393
+ const createdAt = promptId.value ?
394
+ (prompts.find(p => p.id === id)?.createdAt || new Date().toISOString()) :
395
+ new Date().toISOString();
396
+ const updatedAt = new Date().toISOString();
397
+
398
+ if (!text) {
399
+ alert('Prompt text is required');
400
+ return;
401
+ }
402
+
403
+ const prompt = {
404
+ id,
405
+ name,
406
+ text,
407
+ model,
408
+ parameters,
409
+ images,
410
+ favorite,
411
+ tags,
412
+ createdAt,
413
+ updatedAt
414
+ };
415
+
416
+ // Check if we're updating an existing prompt
417
+ const index = prompts.findIndex(p => p.id === id);
418
+ if (index !== -1) {
419
+ prompts[index] = prompt;
420
+ } else {
421
+ prompts.unshift(prompt);
422
+ }
423
+
424
+ // Save to local storage
425
+ localStorage.setItem('midjourneyPrompts', JSON.stringify(prompts));
426
+
427
+ // Update UI
428
+ updateStats();
429
+ renderPrompts();
430
+ renderTagFilters();
431
+ closePromptModal();
432
+ }
433
+
434
+ function deletePrompt(id) {
435
+ if (confirm('Are you sure you want to delete this prompt?')) {
436
+ prompts = prompts.filter(p => p.id !== id);
437
+ localStorage.setItem('midjourneyPrompts', JSON.stringify(prompts));
438
+ updateStats();
439
+ renderPrompts();
440
+ renderTagFilters();
441
+ }
442
+ }
443
+
444
+ function toggleFavorite(id) {
445
+ const prompt = prompts.find(p => p.id === id);
446
+ if (prompt) {
447
+ prompt.favorite = !prompt.favorite;
448
+ localStorage.setItem('midjourneyPrompts', JSON.stringify(prompts));
449
+ updateStats();
450
+ renderPrompts();
451
+ }
452
+ }
453
+
454
+ function updateStats() {
455
+ totalPrompts.textContent = prompts.length;
456
+ favoritePrompts.textContent = prompts.filter(p => p.favorite).length;
457
+
458
+ // Calculate unique tags
459
+ const allTags = prompts.flatMap(p => p.tags || []);
460
+ const uniqueTagsSet = new Set(allTags);
461
+ uniqueTags.textContent = uniqueTagsSet.size;
462
+
463
+ // Calculate total images
464
+ const totalImagesCount = prompts.reduce((sum, p) => sum + (p.images?.length || 0), 0);
465
+ totalImages.textContent = totalImagesCount;
466
+ }
467
+
468
+ function renderPrompts() {
469
+ loadingOverlay.classList.remove('hidden');
470
+
471
+ // Simulate loading (for demo purposes)
472
+ setTimeout(() => {
473
+ let filteredPrompts = [...prompts];
474
+
475
+ // Apply search filter
476
+ const searchTerm = searchInput.value.toLowerCase();
477
+ if (searchTerm) {
478
+ filteredPrompts = filteredPrompts.filter(p =>
479
+ p.text.toLowerCase().includes(searchTerm) ||
480
+ (p.name && p.name.toLowerCase().includes(searchTerm)) ||
481
+ (p.tags && p.tags.some(tag => tag.toLowerCase().includes(searchTerm)))
482
+ );
483
+ }
484
+
485
+ // Apply category filter
486
+ const filterValue = filterSelect.value;
487
+ if (filterValue !== 'all') {
488
+ if (filterValue === 'favorite') {
489
+ filteredPrompts = filteredPrompts.filter(p => p.favorite);
490
+ } else {
491
+ filteredPrompts = filteredPrompts.filter(p =>
492
+ p.tags && p.tags.includes(filterValue)
493
+ );
494
+ }
495
+ }
496
+
497
+ // Apply active tag filters
498
+ const activeTagButtons = activeTags.querySelectorAll('.tag-filter');
499
+ const activeTagsArray = Array.from(activeTagButtons).map(btn => btn.dataset.tag);
500
+
501
+ if (activeTagsArray.length > 0) {
502
+ filteredPrompts = filteredPrompts.filter(p =>
503
+ p.tags && activeTagsArray.every(tag => p.tags.includes(tag))
504
+ );
505
+ }
506
+
507
+ // Apply sorting
508
+ const sortValue = sortSelect.value;
509
+ switch (sortValue) {
510
+ case 'newest':
511
+ filteredPrompts.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
512
+ break;
513
+ case 'oldest':
514
+ filteredPrompts.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt));
515
+ break;
516
+ case 'az':
517
+ filteredPrompts.sort((a, b) => (a.name || a.text).localeCompare(b.name || b.text));
518
+ break;
519
+ case 'za':
520
+ filteredPrompts.sort((a, b) => (b.name || b.text).localeCompare(a.name || a.text));
521
+ break;
522
+ }
523
+
524
+ // Clear the container
525
+ promptsContainer.innerHTML = '';
526
+
527
+ // Show empty state if no prompts
528
+ if (filteredPrompts.length === 0) {
529
+ emptyState.classList.remove('hidden');
530
+ promptsContainer.appendChild(emptyState);
531
+ } else {
532
+ emptyState.classList.add('hidden');
533
+
534
+ // Render prompts
535
+ filteredPrompts.forEach(prompt => {
536
+ const promptCard = document.createElement('div');
537
+ promptCard.className = 'grid-item bg-white rounded-xl shadow-md overflow-hidden hover:shadow-lg transition duration-300';
538
+
539
+ // First image or placeholder
540
+ const firstImage = prompt.images?.[0] || '';
541
+ const hasImages = prompt.images && prompt.images.length > 0;
542
+
543
+ promptCard.innerHTML = `
544
+ <div class="relative">
545
+ ${hasImages ? `
546
+ <img src="${firstImage}" alt="${prompt.name || 'Midjourney creation'}" class="w-full h-48 object-cover cursor-pointer view-image" data-prompt-id="${prompt.id}" data-image-index="0">
547
+ ` : `
548
+ <div class="w-full h-48 bg-gray-100 flex items-center justify-center text-gray-400">
549
+ <i class="fas fa-image text-4xl"></i>
550
+ </div>
551
+ `}
552
+ ${prompt.favorite ? `
553
+ <div class="absolute top-2 right-2 bg-yellow-500 text-white p-2 rounded-full shadow-md">
554
+ <i class="fas fa-star"></i>
555
+ </div>
556
+ ` : ''}
557
+ <div class="prompt-actions absolute top-2 left-2 opacity-0 transition-opacity duration-300 flex gap-2">
558
+ <button class="edit-prompt bg-indigo-600 text-white p-2 rounded-full shadow-md hover:bg-indigo-700" data-id="${prompt.id}">
559
+ <i class="fas fa-pencil-alt text-sm"></i>
560
+ </button>
561
+ <button class="delete-prompt bg-red-600 text-white p-2 rounded-full shadow-md hover:bg-red-700" data-id="${prompt.id}">
562
+ <i class="fas fa-trash-alt text-sm"></i>
563
+ </button>
564
+ </div>
565
+ </div>
566
+ <div class="p-4">
567
+ <div class="flex justify-between items-start mb-2">
568
+ <h3 class="font-bold text-lg truncate">${prompt.name || 'Untitled Prompt'}</h3>
569
+ <button class="favorite-prompt text-gray-400 hover:text-yellow-500 ${prompt.favorite ? 'text-yellow-500' : ''}" data-id="${prompt.id}">
570
+ <i class="fas fa-star"></i>
571
+ </button>
572
+ </div>
573
+ <p class="text-gray-600 text-sm mb-3 line-clamp-3">${prompt.text}</p>
574
+ <div class="flex flex-wrap gap-1 mb-2">
575
+ ${(prompt.tags || []).slice(0, 3).map(tag => `
576
+ <span class="tag bg-indigo-100 text-indigo-800 text-xs px-2 py-1 rounded-full">${tag}</span>
577
+ `).join('')}
578
+ ${!prompt.tags || prompt.tags.length === 0 ? '' : prompt.tags.length > 3 ? `
579
+ <span class="tag bg-gray-100 text-gray-800 text-xs px-2 py-1 rounded-full">+${prompt.tags.length - 3}</span>
580
+ ` : ''}
581
+ </div>
582
+ <div class="flex justify-between items-center text-xs text-gray-500">
583
+ <span>${new Date(prompt.createdAt).toLocaleDateString()}</span>
584
+ ${hasImages && prompt.images.length > 1 ? `
585
+ <span class="flex items-center">
586
+ <i class="fas fa-images mr-1"></i>
587
+ ${prompt.images.length}
588
+ </span>
589
+ ` : ''}
590
+ </div>
591
+ </div>
592
+ `;
593
+
594
+ promptsContainer.appendChild(promptCard);
595
+ });
596
+ }
597
+
598
+ // Add event listeners to the newly created elements
599
+ addPromptEventListeners();
600
+ loadingOverlay.classList.add('hidden');
601
+ }, 500);
602
+ }
603
+
604
+ function addPromptEventListeners() {
605
+ // Edit buttons
606
+ document.querySelectorAll('.edit-prompt').forEach(button => {
607
+ button.addEventListener('click', (e) => {
608
+ e.stopPropagation();
609
+ openEditPromptModal(button.dataset.id);
610
+ });
611
+ });
612
+
613
+ // Delete buttons
614
+ document.querySelectorAll('.delete-prompt').forEach(button => {
615
+ button.addEventListener('click', (e) => {
616
+ e.stopPropagation();
617
+ deletePrompt(button.dataset.id);
618
+ });
619
+ });
620
+
621
+ // Favorite buttons
622
+ document.querySelectorAll('.favorite-prompt').forEach(button => {
623
+ button.addEventListener('click', (e) => {
624
+ e.stopPropagation();
625
+ toggleFavorite(button.dataset.id);
626
+ });
627
+ });
628
+
629
+ // Image click (lightbox)
630
+ document.querySelectorAll('.view-image').forEach(img => {
631
+ img.addEventListener('click', (e) => {
632
+ const promptId = img.dataset.promptId;
633
+ const prompt = prompts.find(p => p.id === promptId);
634
+
635
+ if (prompt && prompt.images && prompt.images.length > 0) {
636
+ currentLightboxImages = prompt.images;
637
+ currentLightboxIndex = parseInt(img.dataset.imageIndex);
638
+ openLightboxModal(currentLightboxIndex);
639
+ }
640
+ });
641
+ });
642
+
643
+ // Tag filters
644
+ document.querySelectorAll('.tag').forEach(tag => {
645
+ tag.addEventListener('click', (e) => {
646
+ e.stopPropagation();
647
+ const tagText = tag.textContent.replace(/^\+/, '');
648
+ toggleTagFilter(tagText);
649
+ });
650
+ });
651
+ }
652
+
653
+ function openLightboxModal(index) {
654
+ if (currentLightboxImages.length === 0) return;
655
+
656
+ const imageUrl = currentLightboxImages[index];
657
+ const promptId = currentLightboxImages.promptId;
658
+ const prompt = promptId ? prompts.find(p => p.id === promptId) : null;
659
+
660
+ document.getElementById('lightboxImage').src = imageUrl;
661
+ document.getElementById('lightboxCaption').textContent = prompt ? (prompt.name || prompt.text.substring(0, 100) + (prompt.text.length > 100 ? '...' : '')) : '';
662
+
663
+ // Update navigation visibility
664
+ prevImage.style.visibility = index > 0 ? 'visible' : 'hidden';
665
+ nextImage.style.visibility = index < currentLightboxImages.length - 1 ? 'visible' : 'hidden';
666
+
667
+ lightbox.classList.remove('hidden');
668
+ }
669
+
670
+ function renderTagFilters() {
671
+ // Get all unique tags
672
+ const allTags = prompts.flatMap(p => p.tags || []);
673
+ const tagCounts = {};
674
+
675
+ allTags.forEach(tag => {
676
+ tagCounts[tag] = (tagCounts[tag] || 0) + 1;
677
+ });
678
+
679
+ const uniqueTags = Object.keys(tagCounts);
680
+
681
+ // Clear active tags (except the applied ones)
682
+ const appliedTags = Array.from(activeTags.querySelectorAll('.tag-filter')).map(el => el.dataset.tag);
683
+ activeTags.innerHTML = '';
684
+
685
+ // Add the applied tags back
686
+ appliedTags.forEach(tag => {
687
+ if (uniqueTags.includes(tag)) {
688
+ addActiveTagFilter(tag);
689
+ }
690
+ });
691
+ }
692
+
693
+ function toggleTagFilter(tag) {
694
+ const isActive = activeTags.querySelector(`[data-tag="${tag}"]`);
695
+
696
+ if (isActive) {
697
+ isActive.remove();
698
+ } else {
699
+ addActiveTagFilter(tag);
700
+ }
701
+
702
+ renderPrompts();
703
+ }
704
+
705
+ function addActiveTagFilter(tag) {
706
+ const activeTag = document.createElement('span');
707
+ activeTag.className = 'tag-filter inline-flex items-center bg-indigo-600 text-white text-sm px-3 py-1 rounded-full cursor-pointer';
708
+ activeTag.dataset.tag = tag;
709
+ activeTag.innerHTML = `
710
+ ${tag}
711
+ <button class="ml-2 text-white hover:text-indigo-200">
712
+ <i class="fas fa-times"></i>
713
+ </button>
714
+ `;
715
+
716
+ activeTag.addEventListener('click', (e) => {
717
+ if (e.target.tagName === 'BUTTON' || e.target.tagName === 'I') {
718
+ e.stopPropagation();
719
+ activeTag.remove();
720
+ renderPrompts();
721
+ } else {
722
+ toggleTagFilter(tag);
723
+ }
724
+ });
725
+
726
+ activeTags.appendChild(activeTag);
727
+ }
728
+
729
+ // Set up lightbox navigation
730
+ prevImage.addEventListener('click', () => {
731
+ if (currentLightboxIndex > 0) {
732
+ currentLightboxIndex--;
733
+ openLightboxModal(currentLightboxIndex);
734
+ }
735
+ });
736
+
737
+ nextImage.addEventListener('click', () => {
738
+ if (currentLightboxIndex < currentLightboxImages.length - 1) {
739
+ currentLightboxIndex++;
740
+ openLightboxModal(currentLightboxIndex);
741
+ }
742
+ });
743
+
744
+ // Keyboard navigation for lightbox
745
+ document.addEventListener('keydown', (e) => {
746
+ if (!lightbox.classList.contains('hidden')) {
747
+ if (e.key === 'Escape') {
748
+ closeLightboxModal();
749
+ } else if (e.key === 'ArrowLeft' && currentLightboxIndex > 0) {
750
+ currentLightboxIndex--;
751
+ openLightboxModal(currentLightboxIndex);
752
+ } else if (e.key === 'ArrowRight' && currentLightboxIndex < currentLightboxImages.length - 1) {
753
+ currentLightboxIndex++;
754
+ openLightboxModal(currentLightboxIndex);
755
+ }
756
+ }
757
+ });
758
+ });
759
+ </script>
760
+ <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=Hairitics/midjourney-prompt-vault" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
761
+ </html>
prompts.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ a site to organize my Midjourney Prompts and Pictures