Diquels commited on
Commit
993c8b7
·
verified ·
1 Parent(s): 3643ac9

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +1302 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Memory
3
- emoji: 🌍
4
- colorFrom: green
5
- colorTo: blue
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: memory
3
+ emoji: 🐳
4
+ colorFrom: yellow
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,1302 @@
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="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Prompt Manager</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
+ <script>
10
+ tailwind.config = {
11
+ theme: {
12
+ extend: {
13
+ colors: {
14
+ pastel: {
15
+ pink: '#FFD1DC',
16
+ purple: '#E0BBE4',
17
+ blue: '#B5EAD7',
18
+ yellow: '#FFE5B4',
19
+ green: '#C7E9C0',
20
+ peach: '#FFC8A2',
21
+ lavender: '#D4A5C3',
22
+ mint: '#A2D7D8',
23
+ },
24
+ border: {
25
+ active: '#8B5CF6', // violet plus visible
26
+ }
27
+ }
28
+ }
29
+ }
30
+ }
31
+ </script>
32
+ <style>
33
+ .prompt-card:hover {
34
+ transform: translateY(-5px);
35
+ box-shadow: 0 10px 20px rgba(0,0,0,0.1);
36
+ }
37
+ .tag:hover {
38
+ transform: scale(1.05);
39
+ }
40
+ .category-btn:hover {
41
+ transform: scale(1.03);
42
+ }
43
+ .fade-in {
44
+ animation: fadeIn 0.3s ease-in-out;
45
+ }
46
+ @keyframes fadeIn {
47
+ from { opacity: 0; }
48
+ to { opacity: 1; }
49
+ }
50
+ .scrollbar-hide::-webkit-scrollbar {
51
+ display: none;
52
+ }
53
+ .star-rating .star {
54
+ cursor: pointer;
55
+ transition: all 0.2s;
56
+ }
57
+ .star-rating .star:hover {
58
+ transform: scale(1.2);
59
+ }
60
+ .active-filter {
61
+ border: 2px solid #8B5CF6;
62
+ box-shadow: 0 0 0 1px rgba(139, 92, 246, 0.3);
63
+ }
64
+ .prompt-modal-content {
65
+ max-height: 80vh;
66
+ overflow-y: auto;
67
+ }
68
+ .ai-select-container {
69
+ position: relative;
70
+ }
71
+ .ai-select-dropdown {
72
+ display: none;
73
+ position: absolute;
74
+ background: white;
75
+ border: 1px solid #ddd;
76
+ border-radius: 0.5rem;
77
+ width: 100%;
78
+ z-index: 10;
79
+ max-height: 200px;
80
+ overflow-y: auto;
81
+ }
82
+ .ai-select-container.open .ai-select-dropdown {
83
+ display: block;
84
+ }
85
+ .filter-dropdown {
86
+ position: relative;
87
+ }
88
+ .filter-dropdown-btn {
89
+ width: 100%;
90
+ text-align: left;
91
+ }
92
+ .filter-dropdown-content {
93
+ display: none;
94
+ position: absolute;
95
+ background-color: white;
96
+ min-width: 160px;
97
+ box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
98
+ z-index: 1;
99
+ border-radius: 0.5rem;
100
+ max-height: 300px;
101
+ overflow-y: auto;
102
+ }
103
+ .filter-dropdown:hover .filter-dropdown-content {
104
+ display: block;
105
+ }
106
+ .filter-dropdown-item {
107
+ padding: 8px 16px;
108
+ cursor: pointer;
109
+ }
110
+ .filter-dropdown-item:hover {
111
+ background-color: #f1f1f1;
112
+ }
113
+ </style>
114
+ </head>
115
+ <body class="bg-pastel-blue min-h-screen">
116
+ <div class="container mx-auto px-4 py-8">
117
+ <!-- Header -->
118
+ <header class="flex justify-between items-center mb-8">
119
+ <div class="flex items-center">
120
+ <i class="fas fa-database text-4xl text-pastel-purple mr-4"></i>
121
+ <h1 class="text-4xl font-bold text-gray-700">Prompt Manager</h1>
122
+ </div>
123
+ <button id="addPromptBtn" class="bg-pastel-pink hover:bg-pastel-lavender text-white px-6 py-3 rounded-full shadow-md transition-all">
124
+ <i class="fas fa-plus mr-2"></i> Nouveau Prompt
125
+ </button>
126
+ </header>
127
+
128
+ <!-- Main Content -->
129
+ <div class="flex flex-col lg:flex-row gap-8">
130
+ <!-- Sidebar -->
131
+ <div class="w-full lg:w-1/4 bg-white rounded-2xl p-6 shadow-lg">
132
+ <div class="mb-8">
133
+ <h2 class="text-xl font-semibold text-gray-700 mb-4">Catégories</h2>
134
+ <div class="space-y-2">
135
+ <button class="category-btn w-full text-left px-4 py-2 rounded-lg bg-pastel-green hover:bg-pastel-mint transition-all" data-category="all">
136
+ <i class="fas fa-list mr-2"></i> Tous les prompts
137
+ </button>
138
+ <button class="category-btn w-full text-left px-4 py-2 rounded-lg bg-pastel-yellow hover:bg-pastel-peach transition-all" data-category="creative">
139
+ <i class="fas fa-paint-brush mr-2"></i> Créatif
140
+ </button>
141
+ <button class="category-btn w-full text-left px-4 py-2 rounded-lg bg-pastel-purple hover:bg-pastel-lavender transition-all" data-category="technical">
142
+ <i class="fas fa-code mr-2"></i> Technique
143
+ </button>
144
+ <button class="category-btn w-full text-left px-4 py-2 rounded-lg bg-pastel-peach hover:bg-pastel-pink transition-all" data-category="business">
145
+ <i class="fas fa-briefcase mr-2"></i> Business
146
+ </button>
147
+ </div>
148
+ </div>
149
+
150
+ <div class="mb-8">
151
+ <h2 class="text-xl font-semibold text-gray-700 mb-4">Trier par</h2>
152
+ <div class="space-y-2">
153
+ <button class="sort-btn w-full text-left px-4 py-2 rounded-lg bg-pastel-blue hover:bg-pastel-mint transition-all" data-sort="date-desc">
154
+ <i class="fas fa-clock mr-2"></i> Plus récent
155
+ </button>
156
+ <button class="sort-btn w-full text-left px-4 py-2 rounded-lg bg-pastel-lavender hover:bg-pastel-pink transition-all" data-sort="rating-desc">
157
+ <i class="fas fa-star mr-2"></i> Meilleures notes
158
+ </button>
159
+ </div>
160
+ </div>
161
+
162
+ <div>
163
+ <h2 class="text-xl font-semibold text-gray-700 mb-4">Filtres</h2>
164
+ <div class="mb-4">
165
+ <h3 class="text-sm font-medium text-gray-700 mb-2">IA Optimisée</h3>
166
+ <div class="filter-dropdown">
167
+ <button class="filter-dropdown-btn px-4 py-2 bg-gray-100 rounded-lg w-full text-left flex justify-between items-center">
168
+ <span>Sélectionner une IA</span>
169
+ <i class="fas fa-chevron-down"></i>
170
+ </button>
171
+ <div class="filter-dropdown-content">
172
+ <div class="p-2">
173
+ <h4 class="font-medium text-sm mb-1 text-gray-500">OpenAI</h4>
174
+ <div class="space-y-1">
175
+ <div class="filter-dropdown-item" data-ai="gpt-4">GPT-4</div>
176
+ <div class="filter-dropdown-item" data-ai="gpt-4-turbo">GPT-4 Turbo</div>
177
+ <div class="filter-dropdown-item" data-ai="gpt-4o">GPT-4o</div>
178
+ <div class="filter-dropdown-item" data-ai="gpt-3.5">GPT-3.5</div>
179
+ </div>
180
+ </div>
181
+ <div class="p-2">
182
+ <h4 class="font-medium text-sm mb-1 text-gray-500">Google</h4>
183
+ <div class="space-y-1">
184
+ <div class="filter-dropdown-item" data-ai="gemini-pro">Gemini Pro</div>
185
+ <div class="filter-dropdown-item" data-ai="gemini-ultra">Gemini Ultra</div>
186
+ <div class="filter-dropdown-item" data-ai="bard">Bard</div>
187
+ </div>
188
+ </div>
189
+ <div class="p-2">
190
+ <h4 class="font-medium text-sm mb-1 text-gray-500">Anthropic</h4>
191
+ <div class="space-y-1">
192
+ <div class="filter-dropdown-item" data-ai="claude-3-opus">Claude 3 Opus</div>
193
+ <div class="filter-dropdown-item" data-ai="claude-3-sonnet">Claude 3 Sonnet</div>
194
+ <div class="filter-dropdown-item" data-ai="claude-3-haiku">Claude 3 Haiku</div>
195
+ <div class="filter-dropdown-item" data-ai="claude-2">Claude 2</div>
196
+ </div>
197
+ </div>
198
+ <div class="p-2">
199
+ <h4 class="font-medium text-sm mb-1 text-gray-500">Meta</h4>
200
+ <div class="space-y-1">
201
+ <div class="filter-dropdown-item" data-ai="llama-3">Llama 3</div>
202
+ <div class="filter-dropdown-item" data-ai="llama-2">Llama 2</div>
203
+ </div>
204
+ </div>
205
+ <div class="p-2">
206
+ <h4 class="font-medium text-sm mb-1 text-gray-500">Autres</h4>
207
+ <div class="space-y-1">
208
+ <div class="filter-dropdown-item" data-ai="mistral">Mistral</div>
209
+ <div class="filter-dropdown-item" data-ai="copilot">Copilot</div>
210
+ <div class="filter-dropdown-item" data-ai="perplexity">Perplexity</div>
211
+ </div>
212
+ </div>
213
+ </div>
214
+ </div>
215
+ <div class="flex flex-wrap gap-2 mt-2" id="selectedAIFilters"></div>
216
+ </div>
217
+ <div>
218
+ <h3 class="text-sm font-medium text-gray-700 mb-2">Tags</h3>
219
+ <div class="flex flex-wrap gap-2">
220
+ <span class="tag cursor-pointer px-3 py-1 bg-pastel-mint rounded-full text-sm transition-all" data-tag="ia">IA</span>
221
+ <span class="tag cursor-pointer px-3 py-1 bg-pastel-yellow rounded-full text-sm transition-all" data-tag="marketing">Marketing</span>
222
+ <span class="tag cursor-pointer px-3 py-1 bg-pastel-pink rounded-full text-sm transition-all" data-tag="copywriting">Copywriting</span>
223
+ <span class="tag cursor-pointer px-3 py-1 bg-pastel-green rounded-full text-sm transition-all" data-tag="productivite">Productivité</span>
224
+ <span class="tag cursor-pointer px-3 py-1 bg-pastel-purple rounded-full text-sm transition-all" data-tag="design">Design</span>
225
+ </div>
226
+ </div>
227
+ </div>
228
+ </div>
229
+
230
+ <!-- Prompt Display Area -->
231
+ <div class="w-full lg:w-3/4">
232
+ <!-- View Toggle -->
233
+ <div class="flex justify-between items-center mb-6 bg-white p-4 rounded-2xl shadow-lg">
234
+ <h2 class="text-xl font-semibold text-gray-700">Mes Prompts</h2>
235
+ <div class="flex space-x-2">
236
+ <button id="listViewBtn" class="p-2 bg-pastel-blue rounded-lg text-gray-700">
237
+ <i class="fas fa-list"></i>
238
+ </button>
239
+ <button id="gridViewBtn" class="p-2 bg-pastel-green rounded-lg text-gray-700">
240
+ <i class="fas fa-th-large"></i>
241
+ </button>
242
+ </div>
243
+ </div>
244
+
245
+ <!-- Prompts Container -->
246
+ <div id="promptsContainer" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
247
+ <!-- Prompts will be loaded here -->
248
+ </div>
249
+ </div>
250
+ </div>
251
+ </div>
252
+
253
+ <!-- Add/Edit Prompt Modal -->
254
+ <div id="promptModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
255
+ <div class="bg-white rounded-2xl p-8 w-full max-w-2xl relative">
256
+ <button id="closeModalBtn" class="absolute top-4 right-4 text-gray-500 hover:text-gray-700">
257
+ <i class="fas fa-times text-2xl"></i>
258
+ </button>
259
+ <h2 class="text-2xl font-bold text-gray-700 mb-6" id="modalTitle">Ajouter un nouveau prompt</h2>
260
+
261
+ <form id="promptForm" class="space-y-6">
262
+ <input type="hidden" id="promptId">
263
+ <div>
264
+ <label for="promptTitle" class="block text-sm font-medium text-gray-700 mb-1">Titre</label>
265
+ <input type="text" id="promptTitle" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-pastel-purple focus:border-transparent">
266
+ </div>
267
+
268
+ <div>
269
+ <label for="promptContent" class="block text-sm font-medium text-gray-700 mb-1">Contenu du prompt</label>
270
+ <textarea id="promptContent" rows="5" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-pastel-purple focus:border-transparent"></textarea>
271
+ </div>
272
+
273
+ <div>
274
+ <label class="block text-sm font-medium text-gray-700 mb-1">Catégorie</label>
275
+ <div class="flex flex-wrap gap-2">
276
+ <label class="inline-flex items-center">
277
+ <input type="radio" name="category" value="creative" class="h-4 w-4 text-pastel-yellow focus:ring-pastel-yellow">
278
+ <span class="ml-2 text-gray-700">Créatif</span>
279
+ </label>
280
+ <label class="inline-flex items-center">
281
+ <input type="radio" name="category" value="technical" class="h-4 w-4 text-pastel-purple focus:ring-pastel-purple">
282
+ <span class="ml-2 text-gray-700">Technique</span>
283
+ </label>
284
+ <label class="inline-flex items-center">
285
+ <input type="radio" name="category" value="business" class="h-4 w-4 text-pastel-peach focus:ring-pastel-peach">
286
+ <span class="ml-2 text-gray-700">Business</span>
287
+ </label>
288
+ </div>
289
+ </div>
290
+
291
+ <div>
292
+ <label class="block text-sm font-medium text-gray-700 mb-1">Optimisé pour</label>
293
+ <div class="ai-select-container">
294
+ <div class="flex flex-wrap gap-2" id="selectedAIList"></div>
295
+ <div class="relative mt-2">
296
+ <input type="text" id="aiSearch" class="w-full px-4 py-2 border border-gray-300 rounded-lg" placeholder="Rechercher ou ajouter une IA...">
297
+ <div class="ai-select-dropdown" id="aiDropdown"></div>
298
+ </div>
299
+ <button type="button" id="addNewAI" class="hidden mt-2 text-sm text-pastel-purple hover:underline">Ajouter une nouvelle IA</button>
300
+ </div>
301
+ </div>
302
+
303
+ <div>
304
+ <label for="promptTags" class="block text-sm font-medium text-gray-700 mb-1">Tags (séparés par des virgules)</label>
305
+ <input type="text" id="promptTags" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-pastel-purple focus:border-transparent" placeholder="IA, marketing, productivité">
306
+ </div>
307
+
308
+ <div>
309
+ <label class="block text-sm font-medium text-gray-700 mb-1">Note</label>
310
+ <div class="star-rating flex" id="editRating">
311
+ <i class="far fa-star star text-2xl text-pastel-yellow" data-rating="1"></i>
312
+ <i class="far fa-star star text-2xl text-pastel-yellow" data-rating="2"></i>
313
+ <i class="far fa-star star text-2xl text-pastel-yellow" data-rating="3"></i>
314
+ <i class="far fa-star star text-2xl text-pastel-yellow" data-rating="4"></i>
315
+ <i class="far fa-star star text-2xl text-pastel-yellow" data-rating="5"></i>
316
+ </div>
317
+ <input type="hidden" id="promptRating" value="0">
318
+ </div>
319
+
320
+ <div class="flex justify-end space-x-4">
321
+ <button type="button" id="cancelPromptBtn" class="px-6 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-all">
322
+ Annuler
323
+ </button>
324
+ <button type="submit" class="px-6 py-2 bg-pastel-pink text-white rounded-lg hover:bg-pastel-lavender transition-all">
325
+ Enregistrer
326
+ </button>
327
+ </div>
328
+ </form>
329
+ </div>
330
+ </div>
331
+
332
+ <!-- View Prompt Modal -->
333
+ <div id="viewPromptModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
334
+ <div class="bg-white rounded-2xl p-8 w-full max-w-4xl relative">
335
+ <button id="closeViewModalBtn" class="absolute top-4 right-4 text-gray-500 hover:text-gray-700">
336
+ <i class="fas fa-times text-2xl"></i>
337
+ </button>
338
+ <div class="flex justify-between items-center mb-6">
339
+ <h2 class="text-2xl font-bold text-gray-700" id="viewPromptTitle"></h2>
340
+ <div class="flex space-x-4">
341
+ <button id="editPromptBtn" class="px-4 py-2 bg-pastel-blue text-white rounded-lg hover:bg-pastel-mint transition-all">
342
+ <i class="fas fa-edit mr-2"></i> Modifier
343
+ </button>
344
+ <button id="copyPromptBtn" class="px-4 py-2 bg-pastel-green text-white rounded-lg hover:bg-pastel-mint transition-all">
345
+ <i class="fas fa-copy mr-2"></i> Copier
346
+ </button>
347
+ </div>
348
+ </div>
349
+
350
+ <div class="prompt-modal-content space-y-6">
351
+ <div class="bg-gray-50 p-4 rounded-lg">
352
+ <pre class="whitespace-pre-wrap text-gray-800" id="viewPromptContent"></pre>
353
+ </div>
354
+
355
+ <div>
356
+ <h3 class="text-lg font-semibold text-gray-700 mb-2">Détails</h3>
357
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
358
+ <div>
359
+ <h4 class="text-sm font-medium text-gray-500">Catégorie</h4>
360
+ <p class="text-gray-800" id="viewPromptCategory"></p>
361
+ </div>
362
+ <div>
363
+ <h4 class="text-sm font-medium text-gray-500">Optimisé pour</h4>
364
+ <div class="flex flex-wrap gap-2" id="viewPromptAI"></div>
365
+ </div>
366
+ <div>
367
+ <h4 class="text-sm font-medium text-gray-500">Tags</h4>
368
+ <div class="flex flex-wrap gap-2" id="viewPromptTags"></div>
369
+ </div>
370
+ <div>
371
+ <h4 class="text-sm font-medium text-gray-500">Note</h4>
372
+ <div class="flex" id="viewPromptRating"></div>
373
+ </div>
374
+ <div>
375
+ <h4 class="text-sm font-medium text-gray-500">Date de création</h4>
376
+ <p class="text-gray-800" id="viewPromptDate"></p>
377
+ </div>
378
+ </div>
379
+ </div>
380
+ </div>
381
+ </div>
382
+ </div>
383
+
384
+ <script>
385
+ // ==============================================
386
+ // Mémoire Python simulée avec localStorage
387
+ // ==============================================
388
+
389
+ class PromptDatabase {
390
+ constructor() {
391
+ this.key = 'promptManagerDatabase';
392
+ this.availableAIs = [
393
+ // OpenAI
394
+ { id: "gpt-4", name: "GPT-4" },
395
+ { id: "gpt-4-turbo", name: "GPT-4 Turbo" },
396
+ { id: "gpt-4o", name: "GPT-4o" },
397
+ { id: "gpt-3.5", name: "GPT-3.5" },
398
+
399
+ // Google
400
+ { id: "gemini-pro", name: "Gemini Pro" },
401
+ { id: "gemini-ultra", name: "Gemini Ultra" },
402
+ { id: "bard", name: "Bard" },
403
+
404
+ // Anthropic
405
+ { id: "claude-3-opus", name: "Claude 3 Opus" },
406
+ { id: "claude-3-sonnet", name: "Claude 3 Sonnet" },
407
+ { id: "claude-3-haiku", name: "Claude 3 Haiku" },
408
+ { id: "claude-2", name: "Claude 2" },
409
+
410
+ // Meta
411
+ { id: "llama-3", name: "Llama 3" },
412
+ { id: "llama-2", name: "Llama 2" },
413
+
414
+ // Others
415
+ { id: "mistral", name: "Mistral" },
416
+ { id: "copilot", name: "Copilot" },
417
+ { id: "perplexity", name: "Perplexity" }
418
+ ];
419
+
420
+ // Initialiser avec des données par défaut si la base est vide
421
+ if (!this.load()) {
422
+ this.prompts = [
423
+ {
424
+ id: 1,
425
+ title: "Générer des idées de contenu",
426
+ content: "Génère 10 idées de contenu originales pour un blog sur [thème]. Les idées doivent être engageantes et adaptées à un public de [démographie].",
427
+ category: "creative",
428
+ tags: ["marketing", "copywriting"],
429
+ ai: ["gpt-4", "gemini-pro"],
430
+ createdAt: new Date('2023-05-15'),
431
+ rating: 4
432
+ },
433
+ {
434
+ id: 2,
435
+ title: "Optimiser le code Python",
436
+ content: "Analyse ce code Python et suggère des optimisations pour améliorer les performances : [coller le code]",
437
+ category: "technical",
438
+ tags: ["ia", "productivite"],
439
+ ai: ["gpt-4-turbo", "copilot"],
440
+ createdAt: new Date('2023-06-20'),
441
+ rating: 5
442
+ },
443
+ {
444
+ id: 3,
445
+ title: "Stratégie de croissance",
446
+ content: "Développe une stratégie de croissance en 5 étapes pour une startup dans le domaine de [industrie] avec un budget de [montant].",
447
+ category: "business",
448
+ tags: ["marketing", "business"],
449
+ ai: ["claude-3-sonnet", "gemini-pro"],
450
+ createdAt: new Date('2023-07-10'),
451
+ rating: 3
452
+ }
453
+ ];
454
+ this.save();
455
+ }
456
+ }
457
+
458
+ // Charger depuis localStorage
459
+ load() {
460
+ const data = localStorage.getItem(this.key);
461
+ if (data) {
462
+ try {
463
+ const parsed = JSON.parse(data);
464
+ this.prompts = parsed.prompts.map(p => ({
465
+ ...p,
466
+ createdAt: new Date(p.createdAt)
467
+ }));
468
+ return true;
469
+ } catch (e) {
470
+ console.error("Erreur de chargement des données", e);
471
+ return false;
472
+ }
473
+ }
474
+ return false;
475
+ }
476
+
477
+ // Sauvegarder dans localStorage
478
+ save() {
479
+ const data = {
480
+ prompts: this.prompts,
481
+ availableAIs: this.availableAIs
482
+ };
483
+ localStorage.setItem(this.key, JSON.stringify(data));
484
+ }
485
+
486
+ // Ajouter un prompt
487
+ addPrompt(prompt) {
488
+ prompt.id = this.prompts.length > 0 ? Math.max(...this.prompts.map(p => p.id)) + 1 : 1;
489
+ prompt.createdAt = new Date();
490
+ this.prompts.unshift(prompt);
491
+ this.save();
492
+ return prompt;
493
+ }
494
+
495
+ // Mettre à jour un prompt
496
+ updatePrompt(id, updatedPrompt) {
497
+ const index = this.prompts.findIndex(p => p.id === id);
498
+ if (index !== -1) {
499
+ this.prompts[index] = {
500
+ ...this.prompts[index],
501
+ ...updatedPrompt
502
+ };
503
+ this.save();
504
+ return this.prompts[index];
505
+ }
506
+ return null;
507
+ }
508
+
509
+ // Supprimer un prompt
510
+ deletePrompt(id) {
511
+ const index = this.prompts.findIndex(p => p.id === id);
512
+ if (index !== -1) {
513
+ this.prompts.splice(index, 1);
514
+ this.save();
515
+ return true;
516
+ }
517
+ return false;
518
+ }
519
+
520
+ // Obtenir tous les prompts
521
+ getAllPrompts() {
522
+ return [...this.prompts];
523
+ }
524
+
525
+ // Obtenir un prompt par ID
526
+ getPromptById(id) {
527
+ return this.prompts.find(p => p.id === id);
528
+ }
529
+
530
+ // Filtrer les prompts
531
+ filterPrompts(filterFn) {
532
+ return this.prompts.filter(filterFn);
533
+ }
534
+
535
+ // Ajouter une nouvelle IA
536
+ addAI(ai) {
537
+ if (!this.availableAIs.some(a => a.id === ai.id)) {
538
+ this.availableAIs.push(ai);
539
+ this.save();
540
+ }
541
+ return ai;
542
+ }
543
+
544
+ // Obtenir le nom d'une IA
545
+ getAIName(aiId) {
546
+ const ai = this.availableAIs.find(a => a.id === aiId);
547
+ return ai ? ai.name : aiId;
548
+ }
549
+ }
550
+
551
+ // ==============================================
552
+ // Application principale
553
+ // ==============================================
554
+
555
+ // Initialiser la base de données
556
+ const db = new PromptDatabase();
557
+
558
+ // DOM Elements
559
+ const promptsContainer = document.getElementById('promptsContainer');
560
+ const addPromptBtn = document.getElementById('addPromptBtn');
561
+ const promptModal = document.getElementById('promptModal');
562
+ const viewPromptModal = document.getElementById('viewPromptModal');
563
+ const closeModalBtn = document.getElementById('closeModalBtn');
564
+ const closeViewModalBtn = document.getElementById('closeViewModalBtn');
565
+ const cancelPromptBtn = document.getElementById('cancelPromptBtn');
566
+ const promptForm = document.getElementById('promptForm');
567
+ const listViewBtn = document.getElementById('listViewBtn');
568
+ const gridViewBtn = document.getElementById('gridViewBtn');
569
+ const categoryBtns = document.querySelectorAll('.category-btn');
570
+ const sortBtns = document.querySelectorAll('.sort-btn');
571
+ const tags = document.querySelectorAll('.tag');
572
+ const modalTitle = document.getElementById('modalTitle');
573
+ const promptIdInput = document.getElementById('promptId');
574
+ const promptTitleInput = document.getElementById('promptTitle');
575
+ const promptContentInput = document.getElementById('promptContent');
576
+ const promptTagsInput = document.getElementById('promptTags');
577
+ const promptRatingInput = document.getElementById('promptRating');
578
+ const editRating = document.getElementById('editRating');
579
+ const selectedAIList = document.getElementById('selectedAIList');
580
+ const aiSearch = document.getElementById('aiSearch');
581
+ const aiDropdown = document.getElementById('aiDropdown');
582
+ const addNewAI = document.getElementById('addNewAI');
583
+ const viewPromptTitle = document.getElementById('viewPromptTitle');
584
+ const viewPromptContent = document.getElementById('viewPromptContent');
585
+ const viewPromptCategory = document.getElementById('viewPromptCategory');
586
+ const viewPromptAI = document.getElementById('viewPromptAI');
587
+ const viewPromptTags = document.getElementById('viewPromptTags');
588
+ const viewPromptRating = document.getElementById('viewPromptRating');
589
+ const viewPromptDate = document.getElementById('viewPromptDate');
590
+ const editPromptBtn = document.getElementById('editPromptBtn');
591
+ const copyPromptBtn = document.getElementById('copyPromptBtn');
592
+ const selectedAIFilters = document.getElementById('selectedAIFilters');
593
+ const filterDropdownItems = document.querySelectorAll('.filter-dropdown-item');
594
+
595
+ // Current view state
596
+ let currentView = 'grid';
597
+ let currentCategory = 'all';
598
+ let currentTag = null;
599
+ let currentAI = null;
600
+ let currentSort = 'date-desc';
601
+ let currentPromptId = null;
602
+ let selectedAIs = [];
603
+ let isEditing = false;
604
+
605
+ // Initialize the app
606
+ function init() {
607
+ renderPrompts();
608
+ setupEventListeners();
609
+ updateViewButtons();
610
+ updateActiveFilters();
611
+ renderAIDropdown();
612
+ }
613
+
614
+ // Set up event listeners
615
+ function setupEventListeners() {
616
+ // Modal controls
617
+ addPromptBtn.addEventListener('click', () => {
618
+ isEditing = false;
619
+ modalTitle.textContent = "Ajouter un nouveau prompt";
620
+ promptForm.reset();
621
+ selectedAIs = [];
622
+ renderSelectedAIs();
623
+ resetRatingStars(editRating);
624
+ promptRatingInput.value = "0";
625
+ promptModal.classList.remove('hidden');
626
+ });
627
+
628
+ closeModalBtn.addEventListener('click', () => {
629
+ promptModal.classList.add('hidden');
630
+ });
631
+
632
+ closeViewModalBtn.addEventListener('click', () => {
633
+ viewPromptModal.classList.add('hidden');
634
+ });
635
+
636
+ cancelPromptBtn.addEventListener('click', () => {
637
+ promptModal.classList.add('hidden');
638
+ });
639
+
640
+ // Form submission
641
+ promptForm.addEventListener('submit', (e) => {
642
+ e.preventDefault();
643
+ savePrompt();
644
+ });
645
+
646
+ // View toggle
647
+ listViewBtn.addEventListener('click', () => {
648
+ currentView = 'list';
649
+ renderPrompts();
650
+ updateViewButtons();
651
+ });
652
+
653
+ gridViewBtn.addEventListener('click', () => {
654
+ currentView = 'grid';
655
+ renderPrompts();
656
+ updateViewButtons();
657
+ });
658
+
659
+ // Category filters
660
+ categoryBtns.forEach(btn => {
661
+ btn.addEventListener('click', () => {
662
+ currentCategory = btn.dataset.category;
663
+ currentTag = null;
664
+ currentAI = null;
665
+ renderPrompts();
666
+ updateActiveFilters();
667
+ });
668
+ });
669
+
670
+ // Sort buttons
671
+ sortBtns.forEach(btn => {
672
+ btn.addEventListener('click', () => {
673
+ currentSort = btn.dataset.sort;
674
+ renderPrompts();
675
+ updateActiveFilters();
676
+ });
677
+ });
678
+
679
+ // Tag filters
680
+ tags.forEach(tag => {
681
+ tag.addEventListener('click', () => {
682
+ currentTag = tag.dataset.tag;
683
+ currentCategory = 'all';
684
+ currentAI = null;
685
+ renderPrompts();
686
+ updateActiveFilters();
687
+ });
688
+ });
689
+
690
+ // AI filter dropdown items
691
+ filterDropdownItems.forEach(item => {
692
+ item.addEventListener('click', (e) => {
693
+ e.stopPropagation();
694
+ currentAI = item.dataset.ai;
695
+ currentCategory = 'all';
696
+ currentTag = null;
697
+ renderPrompts();
698
+ updateActiveFilters();
699
+
700
+ // Add selected AI to filter chips
701
+ selectedAIFilters.innerHTML = '';
702
+ if (currentAI) {
703
+ const ai = db.availableAIs.find(a => a.id === currentAI) || { id: currentAI, name: currentAI };
704
+ const chip = document.createElement('span');
705
+ chip.className = 'px-3 py-1 bg-pastel-blue rounded-full text-sm flex items-center';
706
+ chip.innerHTML = `
707
+ ${ai.name}
708
+ <button class="ml-2 text-xs" data-ai-id="${ai.id}">
709
+ <i class="fas fa-times"></i>
710
+ </button>
711
+ `;
712
+ selectedAIFilters.appendChild(chip);
713
+
714
+ // Add remove event
715
+ const removeBtn = chip.querySelector('button');
716
+ removeBtn.addEventListener('click', (e) => {
717
+ e.stopPropagation();
718
+ currentAI = null;
719
+ selectedAIFilters.innerHTML = '';
720
+ renderPrompts();
721
+ updateActiveFilters();
722
+ });
723
+ }
724
+ });
725
+ });
726
+
727
+ // AI selection
728
+ aiSearch.addEventListener('input', () => {
729
+ renderAIDropdown();
730
+ });
731
+
732
+ aiSearch.addEventListener('focus', () => {
733
+ document.querySelector('.ai-select-container').classList.add('open');
734
+ renderAIDropdown();
735
+ });
736
+
737
+ document.addEventListener('click', (e) => {
738
+ if (!e.target.closest('.ai-select-container')) {
739
+ document.querySelector('.ai-select-container').classList.remove('open');
740
+ }
741
+ });
742
+
743
+ // Edit prompt button
744
+ editPromptBtn.addEventListener('click', () => {
745
+ if (currentPromptId) {
746
+ editPrompt(currentPromptId);
747
+ }
748
+ });
749
+
750
+ // Copy prompt button
751
+ copyPromptBtn.addEventListener('click', () => {
752
+ if (currentPromptId) {
753
+ const prompt = db.getPromptById(currentPromptId);
754
+ if (prompt) {
755
+ navigator.clipboard.writeText(prompt.content)
756
+ .then(() => {
757
+ // Show copied notification
758
+ const copyBtn = copyPromptBtn;
759
+ const originalText = copyBtn.innerHTML;
760
+ copyBtn.innerHTML = '<i class="fas fa-check mr-2"></i> Copié!';
761
+ setTimeout(() => {
762
+ copyBtn.innerHTML = originalText;
763
+ }, 2000);
764
+ })
765
+ .catch(err => {
766
+ console.error('Failed to copy text: ', err);
767
+ });
768
+ }
769
+ }
770
+ });
771
+
772
+ // Rating stars in edit modal
773
+ setupRatingStars(editRating);
774
+ }
775
+
776
+ // Update active filter buttons with more visible border
777
+ function updateActiveFilters() {
778
+ // Category buttons
779
+ categoryBtns.forEach(btn => {
780
+ if (btn.dataset.category === currentCategory) {
781
+ btn.classList.add('active-filter');
782
+ } else {
783
+ btn.classList.remove('active-filter');
784
+ }
785
+ });
786
+
787
+ // Sort buttons
788
+ sortBtns.forEach(btn => {
789
+ if (btn.dataset.sort === currentSort) {
790
+ btn.classList.add('active-filter');
791
+ } else {
792
+ btn.classList.remove('active-filter');
793
+ }
794
+ });
795
+
796
+ // Tag filters
797
+ tags.forEach(tag => {
798
+ if (tag.dataset.tag === currentTag) {
799
+ tag.classList.add('active-filter');
800
+ } else {
801
+ tag.classList.remove('active-filter');
802
+ }
803
+ });
804
+ }
805
+
806
+ // Update view toggle buttons
807
+ function updateViewButtons() {
808
+ if (currentView === 'list') {
809
+ listViewBtn.classList.add('bg-pastel-purple', 'text-white');
810
+ gridViewBtn.classList.remove('bg-pastel-purple', 'text-white');
811
+ } else {
812
+ gridViewBtn.classList.add('bg-pastel-purple', 'text-white');
813
+ listViewBtn.classList.remove('bg-pastel-purple', 'text-white');
814
+ }
815
+ }
816
+
817
+ // Save or update prompt
818
+ function savePrompt() {
819
+ const title = promptTitleInput.value;
820
+ const content = promptContentInput.value;
821
+ const category = document.querySelector('input[name="category"]:checked').value;
822
+
823
+ // Get tags
824
+ const tags = promptTagsInput.value
825
+ .split(',')
826
+ .map(tag => tag.trim())
827
+ .filter(tag => tag.length > 0);
828
+
829
+ // Get rating
830
+ const rating = parseInt(promptRatingInput.value) || 0;
831
+
832
+ if (isEditing) {
833
+ // Update existing prompt
834
+ const updatedPrompt = {
835
+ title,
836
+ content,
837
+ category,
838
+ tags,
839
+ ai: selectedAIs,
840
+ rating
841
+ };
842
+
843
+ db.updatePrompt(currentPromptId, updatedPrompt);
844
+ } else {
845
+ // Create new prompt
846
+ const newPrompt = {
847
+ title,
848
+ content,
849
+ category,
850
+ tags,
851
+ ai: selectedAIs,
852
+ rating
853
+ };
854
+
855
+ db.addPrompt(newPrompt);
856
+ }
857
+
858
+ renderPrompts();
859
+ promptModal.classList.add('hidden');
860
+ if (isEditing) {
861
+ viewPromptModal.classList.add('hidden');
862
+ }
863
+ }
864
+
865
+ // Edit prompt
866
+ function editPrompt(id) {
867
+ const prompt = db.getPromptById(id);
868
+ if (prompt) {
869
+ isEditing = true;
870
+ currentPromptId = id;
871
+ modalTitle.textContent = "Modifier le prompt";
872
+
873
+ // Fill form with prompt data
874
+ promptIdInput.value = prompt.id;
875
+ promptTitleInput.value = prompt.title;
876
+ promptContentInput.value = prompt.content;
877
+ document.querySelector(`input[name="category"][value="${prompt.category}"]`).checked = true;
878
+ promptTagsInput.value = prompt.tags.join(', ');
879
+ promptRatingInput.value = prompt.rating;
880
+
881
+ // Set selected AIs
882
+ selectedAIs = [...prompt.ai];
883
+ renderSelectedAIs();
884
+
885
+ // Set rating
886
+ setRatingStars(editRating, prompt.rating);
887
+
888
+ promptModal.classList.remove('hidden');
889
+ viewPromptModal.classList.add('hidden');
890
+ }
891
+ }
892
+
893
+ // View prompt details
894
+ function viewPrompt(id) {
895
+ const prompt = db.getPromptById(id);
896
+ if (prompt) {
897
+ currentPromptId = id;
898
+
899
+ // Fill view modal with prompt data
900
+ viewPromptTitle.textContent = prompt.title;
901
+ viewPromptContent.textContent = prompt.content;
902
+ viewPromptCategory.textContent = getCategoryName(prompt.category);
903
+
904
+ // Display AI
905
+ viewPromptAI.innerHTML = '';
906
+ prompt.ai.forEach(ai => {
907
+ const aiElement = document.createElement('span');
908
+ aiElement.className = 'px-3 py-1 bg-pastel-blue rounded-full text-sm';
909
+ aiElement.textContent = db.getAIName(ai);
910
+ viewPromptAI.appendChild(aiElement);
911
+ });
912
+
913
+ // Display tags
914
+ viewPromptTags.innerHTML = '';
915
+ prompt.tags.forEach(tag => {
916
+ const tagElement = document.createElement('span');
917
+ tagElement.className = 'px-3 py-1 bg-pastel-mint rounded-full text-sm';
918
+ tagElement.textContent = tag;
919
+ viewPromptTags.appendChild(tagElement);
920
+ });
921
+
922
+ // Display rating
923
+ viewPromptRating.innerHTML = '';
924
+ for (let i = 1; i <= 5; i++) {
925
+ const star = document.createElement('i');
926
+ star.className = i <= prompt.rating ? 'fas fa-star text-pastel-yellow' : 'far fa-star text-pastel-yellow';
927
+ viewPromptRating.appendChild(star);
928
+ }
929
+
930
+ // Display date
931
+ viewPromptDate.textContent = formatDate(prompt.createdAt);
932
+
933
+ viewPromptModal.classList.remove('hidden');
934
+ }
935
+ }
936
+
937
+ // Filter prompts based on current filters
938
+ function filterPrompts() {
939
+ let filteredPrompts = db.getAllPrompts();
940
+
941
+ // Category filter
942
+ if (currentCategory !== 'all') {
943
+ filteredPrompts = filteredPrompts.filter(prompt => prompt.category === currentCategory);
944
+ }
945
+
946
+ // Tag filter
947
+ if (currentTag) {
948
+ filteredPrompts = filteredPrompts.filter(prompt => prompt.tags.includes(currentTag));
949
+ }
950
+
951
+ // AI filter
952
+ if (currentAI) {
953
+ filteredPrompts = filteredPrompts.filter(prompt => prompt.ai.includes(currentAI));
954
+ }
955
+
956
+ return filteredPrompts;
957
+ }
958
+
959
+ // Sort prompts
960
+ function sortPrompts(promptsToSort) {
961
+ const sortedPrompts = [...promptsToSort];
962
+
963
+ switch(currentSort) {
964
+ case 'date-desc':
965
+ sortedPrompts.sort((a, b) => b.createdAt - a.createdAt);
966
+ break;
967
+ case 'rating-desc':
968
+ sortedPrompts.sort((a, b) => b.rating - a.rating);
969
+ break;
970
+ default:
971
+ sortedPrompts.sort((a, b) => b.createdAt - a.createdAt);
972
+ }
973
+
974
+ return sortedPrompts;
975
+ }
976
+
977
+ // Render prompts to the DOM
978
+ function renderPrompts() {
979
+ let filteredPrompts = filterPrompts();
980
+ filteredPrompts = sortPrompts(filteredPrompts);
981
+
982
+ if (currentView === 'list') {
983
+ renderListView(filteredPrompts);
984
+ } else {
985
+ renderGridView(filteredPrompts);
986
+ }
987
+ }
988
+
989
+ // Render prompts in list view
990
+ function renderListView(promptsToRender) {
991
+ promptsContainer.innerHTML = '';
992
+ promptsContainer.classList.remove('grid-cols-1', 'md:grid-cols-2', 'lg:grid-cols-3');
993
+ promptsContainer.classList.add('space-y-4');
994
+
995
+ promptsToRender.forEach(prompt => {
996
+ const promptElement = document.createElement('div');
997
+ promptElement.className = 'bg-white rounded-2xl p-6 shadow-md transition-all prompt-card hover:shadow-lg fade-in cursor-pointer';
998
+ promptElement.dataset.id = prompt.id;
999
+ promptElement.innerHTML = `
1000
+ <div class="flex justify-between items-start mb-4">
1001
+ <h3 class="text-xl font-semibold text-gray-800">${prompt.title}</h3>
1002
+ <div class="flex items-center">
1003
+ <button class="copy-btn mr-4 p-2 bg-pastel-green text-white rounded-full hover:bg-pastel-mint transition-all" data-prompt-id="${prompt.id}">
1004
+ <i class="fas fa-copy"></i>
1005
+ </button>
1006
+ <div class="star-rating" data-prompt-id="${prompt.id}">
1007
+ ${renderRatingStars(prompt.rating)}
1008
+ </div>
1009
+ </div>
1010
+ </div>
1011
+ <p class="text-gray-600 mb-4">${prompt.content}</p>
1012
+ <div class="flex flex-wrap gap-2 mb-4">
1013
+ ${prompt.ai.map(ai => `
1014
+ <span class="px-3 py-1 bg-pastel-blue rounded-full text-xs">${db.getAIName(ai)}</span>
1015
+ `).join('')}
1016
+ </div>
1017
+ <div class="flex justify-between items-center">
1018
+ <div class="flex flex-wrap gap-2">
1019
+ ${prompt.tags.map(tag => `
1020
+ <span class="px-3 py-1 bg-pastel-mint rounded-full text-xs">${tag}</span>
1021
+ `).join('')}
1022
+ </div>
1023
+ <span class="text-xs text-gray-500">${formatDate(prompt.createdAt)}</span>
1024
+ </div>
1025
+ `;
1026
+ promptsContainer.appendChild(promptElement);
1027
+
1028
+ // Add click event to view prompt
1029
+ promptElement.addEventListener('click', () => {
1030
+ viewPrompt(prompt.id);
1031
+ });
1032
+
1033
+ // Add click event to copy button
1034
+ const copyBtn = promptElement.querySelector('.copy-btn');
1035
+ copyBtn.addEventListener('click', (e) => {
1036
+ e.stopPropagation();
1037
+ navigator.clipboard.writeText(prompt.content)
1038
+ .then(() => {
1039
+ // Show copied notification
1040
+ const icon = copyBtn.querySelector('i');
1041
+ icon.classList.remove('fa-copy');
1042
+ icon.classList.add('fa-check');
1043
+ setTimeout(() => {
1044
+ icon.classList.remove('fa-check');
1045
+ icon.classList.add('fa-copy');
1046
+ }, 2000);
1047
+ })
1048
+ .catch(err => {
1049
+ console.error('Failed to copy text: ', err);
1050
+ });
1051
+ });
1052
+ });
1053
+
1054
+ // Add event listeners to rating stars
1055
+ setupRatingStars();
1056
+ }
1057
+
1058
+ // Render prompts in grid view
1059
+ function renderGridView(promptsToRender) {
1060
+ promptsContainer.innerHTML = '';
1061
+ promptsContainer.classList.remove('space-y-4');
1062
+ promptsContainer.classList.add('grid-cols-1', 'md:grid-cols-2', 'lg:grid-cols-3');
1063
+
1064
+ promptsToRender.forEach(prompt => {
1065
+ const promptElement = document.createElement('div');
1066
+ promptElement.className = 'bg-white rounded-2xl p-6 shadow-md transition-all prompt-card hover:shadow-lg fade-in cursor-pointer';
1067
+ promptElement.dataset.id = prompt.id;
1068
+ promptElement.innerHTML = `
1069
+ <div class="flex justify-between items-start mb-4">
1070
+ <h3 class="text-lg font-semibold text-gray-800">${prompt.title}</h3>
1071
+ <div class="flex items-center">
1072
+ <button class="copy-btn mr-2 p-2 bg-pastel-green text-white rounded-full hover:bg-pastel-mint transition-all" data-prompt-id="${prompt.id}">
1073
+ <i class="fas fa-copy text-sm"></i>
1074
+ </button>
1075
+ <div class="star-rating" data-prompt-id="${prompt.id}">
1076
+ ${renderRatingStars(prompt.rating, true)}
1077
+ </div>
1078
+ </div>
1079
+ </div>
1080
+ <p class="text-gray-600 mb-4 text-sm line-clamp-3">${prompt.content}</p>
1081
+ <div class="flex flex-wrap gap-2 mb-4">
1082
+ ${prompt.ai.map(ai => `
1083
+ <span class="px-2 py-1 bg-pastel-blue rounded-full text-xs">${db.getAIName(ai)}</span>
1084
+ `).join('')}
1085
+ </div>
1086
+ <div class="flex justify-between items-center">
1087
+ <div class="flex flex-wrap gap-2">
1088
+ ${prompt.tags.map(tag => `
1089
+ <span class="px-2 py-1 bg-pastel-mint rounded-full text-xs">${tag}</span>
1090
+ `).join('')}
1091
+ </div>
1092
+ <span class="text-xs text-gray-500">${formatDate(prompt.createdAt)}</span>
1093
+ </div>
1094
+ `;
1095
+ promptsContainer.appendChild(promptElement);
1096
+
1097
+ // Add click event to view prompt
1098
+ promptElement.addEventListener('click', () => {
1099
+ viewPrompt(prompt.id);
1100
+ });
1101
+
1102
+ // Add click event to copy button
1103
+ const copyBtn = promptElement.querySelector('.copy-btn');
1104
+ copyBtn.addEventListener('click', (e) => {
1105
+ e.stopPropagation();
1106
+ navigator.clipboard.writeText(prompt.content)
1107
+ .then(() => {
1108
+ // Show copied notification
1109
+ const icon = copyBtn.querySelector('i');
1110
+ icon.classList.remove('fa-copy');
1111
+ icon.classList.add('fa-check');
1112
+ setTimeout(() => {
1113
+ icon.classList.remove('fa-check');
1114
+ icon.classList.add('fa-copy');
1115
+ }, 2000);
1116
+ })
1117
+ .catch(err => {
1118
+ console.error('Failed to copy text: ', err);
1119
+ });
1120
+ });
1121
+ });
1122
+
1123
+ // Add event listeners to rating stars
1124
+ setupRatingStars();
1125
+ }
1126
+
1127
+ // Setup rating stars event listeners for a specific container
1128
+ function setupRatingStars(container = null) {
1129
+ const containers = container ? [container] : document.querySelectorAll('.star-rating');
1130
+
1131
+ containers.forEach(ratingContainer => {
1132
+ const promptId = parseInt(ratingContainer.dataset.promptId);
1133
+ const stars = ratingContainer.querySelectorAll('.star');
1134
+
1135
+ stars.forEach((star, index) => {
1136
+ star.addEventListener('click', (e) => {
1137
+ e.stopPropagation();
1138
+ // Update rating in the data
1139
+ const prompt = db.getPromptById(promptId);
1140
+ if (prompt) {
1141
+ prompt.rating = index + 1;
1142
+ db.updatePrompt(promptId, { rating: prompt.rating });
1143
+ renderPrompts();
1144
+ }
1145
+ });
1146
+ });
1147
+ });
1148
+ }
1149
+
1150
+ // Set rating stars
1151
+ function setRatingStars(container, rating) {
1152
+ container.innerHTML = '';
1153
+ for (let i = 1; i <= 5; i++) {
1154
+ const star = document.createElement('i');
1155
+ star.className = i <= rating ? 'fas fa-star star text-pastel-yellow' : 'far fa-star star text-pastel-yellow';
1156
+ star.dataset.rating = i;
1157
+ container.appendChild(star);
1158
+ }
1159
+ setupRatingStars(container);
1160
+
1161
+ // Update hidden input value
1162
+ if (container.id === 'editRating') {
1163
+ promptRatingInput.value = rating;
1164
+ }
1165
+ }
1166
+
1167
+ // Reset rating stars
1168
+ function resetRatingStars(container) {
1169
+ container.innerHTML = '';
1170
+ for (let i = 1; i <= 5; i++) {
1171
+ const star = document.createElement('i');
1172
+ star.className = 'far fa-star star text-pastel-yellow';
1173
+ star.dataset.rating = i;
1174
+ container.appendChild(star);
1175
+ }
1176
+ setupRatingStars(container);
1177
+
1178
+ // Reset hidden input value
1179
+ if (container.id === 'editRating') {
1180
+ promptRatingInput.value = "0";
1181
+ }
1182
+ }
1183
+
1184
+ // Render rating stars
1185
+ function renderRatingStars(rating, small = false) {
1186
+ let stars = '';
1187
+ for (let i = 1; i <= 5; i++) {
1188
+ if (i <= rating) {
1189
+ stars += `<i class="fas fa-star star ${small ? 'text-sm' : ''} text-pastel-yellow" data-rating="${i}"></i>`;
1190
+ } else {
1191
+ stars += `<i class="far fa-star star ${small ? 'text-sm' : ''} text-pastel-yellow" data-rating="${i}"></i>`;
1192
+ }
1193
+ }
1194
+ return stars;
1195
+ }
1196
+
1197
+ // Render AI dropdown
1198
+ function renderAIDropdown() {
1199
+ const searchTerm = aiSearch.value.toLowerCase();
1200
+ aiDropdown.innerHTML = '';
1201
+
1202
+ // Filter AIs based on search term
1203
+ const filteredAIs = db.availableAIs.filter(ai =>
1204
+ ai.name.toLowerCase().includes(searchTerm) ||
1205
+ ai.id.toLowerCase().includes(searchTerm)
1206
+ );
1207
+
1208
+ // Show matching AIs
1209
+ filteredAIs.forEach(ai => {
1210
+ if (!selectedAIs.includes(ai.id)) {
1211
+ const aiElement = document.createElement('div');
1212
+ aiElement.className = 'px-4 py-2 hover:bg-gray-100 cursor-pointer';
1213
+ aiElement.textContent = ai.name;
1214
+ aiElement.dataset.aiId = ai.id;
1215
+ aiElement.addEventListener('click', () => {
1216
+ if (!selectedAIs.includes(ai.id)) {
1217
+ selectedAIs.push(ai.id);
1218
+ renderSelectedAIs();
1219
+ renderAIDropdown();
1220
+ }
1221
+ });
1222
+ aiDropdown.appendChild(aiElement);
1223
+ }
1224
+ });
1225
+
1226
+ // Show "Add new" option if search term doesn't match any existing AI
1227
+ if (searchTerm && !filteredAIs.some(ai =>
1228
+ ai.name.toLowerCase() === searchTerm ||
1229
+ ai.id.toLowerCase() === searchTerm
1230
+ )) {
1231
+ addNewAI.classList.remove('hidden');
1232
+ addNewAI.textContent = `Ajouter "${searchTerm}" comme nouvelle IA`;
1233
+ addNewAI.onclick = () => {
1234
+ const newAI = {
1235
+ id: searchTerm.toLowerCase().replace(/\s+/g, '-'),
1236
+ name: searchTerm
1237
+ };
1238
+ db.addAI(newAI);
1239
+ selectedAIs.push(newAI.id);
1240
+ renderSelectedAIs();
1241
+ aiSearch.value = '';
1242
+ renderAIDropdown();
1243
+ addNewAI.classList.add('hidden');
1244
+ };
1245
+ } else {
1246
+ addNewAI.classList.add('hidden');
1247
+ }
1248
+ }
1249
+
1250
+ // Render selected AIs
1251
+ function renderSelectedAIs() {
1252
+ selectedAIList.innerHTML = '';
1253
+
1254
+ selectedAIs.forEach(aiId => {
1255
+ const ai = db.availableAIs.find(a => a.id === aiId) || { id: aiId, name: aiId };
1256
+ const aiElement = document.createElement('span');
1257
+ aiElement.className = 'inline-flex items-center px-3 py-1 bg-pastel-blue rounded-full text-sm mb-2';
1258
+ aiElement.innerHTML = `
1259
+ ${ai.name}
1260
+ <button class="ml-2 text-xs" data-ai-id="${ai.id}">
1261
+ <i class="fas fa-times"></i>
1262
+ </button>
1263
+ `;
1264
+ selectedAIList.appendChild(aiElement);
1265
+
1266
+ // Add remove event
1267
+ const removeBtn = aiElement.querySelector('button');
1268
+ removeBtn.addEventListener('click', (e) => {
1269
+ e.stopPropagation();
1270
+ selectedAIs = selectedAIs.filter(id => id !== ai.id);
1271
+ renderSelectedAIs();
1272
+ renderAIDropdown();
1273
+ });
1274
+ });
1275
+ }
1276
+
1277
+ // Get category name from code
1278
+ function getCategoryName(categoryCode) {
1279
+ const categories = {
1280
+ 'creative': 'Créatif',
1281
+ 'technical': 'Technique',
1282
+ 'business': 'Business'
1283
+ };
1284
+ return categories[categoryCode] || categoryCode;
1285
+ }
1286
+
1287
+ // Format date
1288
+ function formatDate(date) {
1289
+ return date.toLocaleDateString('fr-FR', {
1290
+ day: '2-digit',
1291
+ month: '2-digit',
1292
+ year: 'numeric',
1293
+ hour: '2-digit',
1294
+ minute: '2-digit'
1295
+ });
1296
+ }
1297
+
1298
+ // Initialize the application
1299
+ document.addEventListener('DOMContentLoaded', init);
1300
+ </script>
1301
+ <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=Diquels/memory" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
1302
+ </html>