Abmacode12 commited on
Commit
6feb262
·
verified ·
1 Parent(s): 9a9a78f

import React, { useState } from 'react';

Browse files

import { Plus, Search, Library, Share2, Menu, X, Code2, Settings, LogOut, Home, FolderOpen, MessageSquare, Send, ChevronRight, Star, Clock, Zap, Copy, Download, Eye } from 'lucide-react';

export default function EspaceCodage() {
const [sidebarOpen, setSidebarOpen] = useState(true);
const [currentView, setCurrentView] = useState('home');
const [userInput, setUserInput] = useState('');
const [chatActive, setChatActive] = useState(false);
const [messages, setMessages] = useState([]);
const [generatedCode, setGeneratedCode] = useState(null);
const [selectedProject, setSelectedProject] = useState(null);
const [projects, setProjects] = useState([
{ id: 1, name: 'Portfolio Pro', status: 'active', timestamp: '2 jours', code: '' },
{ id: 2, name: 'E-shop Mode', status: 'active', timestamp: '5 jours', code: '' },
{ id: 3, name: 'App SaaS', status: 'archived', timestamp: '10 jours', code: '' }
]);

// Rosalinda - IA intelligente pour générer du code
const rosalinda = async (userText) => {
try {
// Appel à l'API Claude pour générer du code complet
const response = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "claude-sonnet-4-20250514",
max_tokens: 2000,
system: `Tu es Rosalinda, une IA senior full-stack spécialisée dans la génération de code complet et professionnel.

Tu dois :
1. Comprendre exactement ce que l'utilisateur demande
2. Générer du code HTML/CSS/JavaScript complet et fonctionnel
3. Générer du code React moderne si demandé
4. Expliquer ton code clairement en français

Format de réponse :
- D'abord une explication courte
- Ensuite le code complet dans un bloc \`\`\`language
- Toujours du code prêt à l'emploi, sans placeholders

Sois créatif, professionnel et produis du vrai code !`,
messages: [
{ role: "user", content: userText }
],
})
});

const data = await response.json();
return data.content[0]?.text || "Erreur de génération";
} catch (error) {
return `Je vais générer du code pour: ${userText}. Voici une solution professionnelle !`;
}
};

const handleUserMessage = async (text) => {
if (!text.trim()) return;

// Ajouter le message de l'utilisateur
const newMessages = [...messages, {
id: Date.now(),
user: 'Vous',
type: 'user',
text: text,
time: new Date().toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })
}];
setMessages(newMessages);

// Rosalinda génère une réponse intelligente
let rosalindaResponse = '';

// Appel à Rosalinda pour générer du code ou répondre
if (text.toLowerCase().includes('site') ||
text.toLowerCase().includes('code') ||
text.toLowerCase().includes('html') ||
text.toLowerCase().includes('app') ||
text.toLowerCase().includes('portfolio') ||
text.toLowerCase().includes('e-shop') ||
text.toLowerCase().includes('landing')) {

rosalindaResponse = await rosalinda(text);

// Extraire le code généré si présent
const codeMatch = rosalindaResponse.match(/```(?:html|jsx?|css|javascript)?\n([\s\S]*?)```/);
if (codeMatch) {
setGeneratedCode({
language: text.includes('react') ? 'jsx' : 'html',
code: codeMatch[1],
description: text
});
}
} else {
// Réponse standard si pas de demande de code
rosalindaResponse = await rosalinda(`Réponds brièvement (2-3 phrases max) en français à: ${text}`);
}

// Ajouter la réponse de Rosalinda
setTimeout(() => {
setMessages(prev => [...prev, {
id: Date.now() + 1,
user: 'Rosalinda',
type: 'assistant',
text: rosalindaResponse,
time: new Date().toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })
}]);
}, 500);

setUserInput('');
};

const copyCode = (code) => {
navigator.clipboard.writeText(code);
alert('Code copié ! ✓');
};

const downloadCode = (code, filename = 'code.html') => {
const element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(code));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
};

const saveProjectCode = () => {
if (generatedCode && selectedProject) {
const updatedProjects = projects.map(p =>
p.id === selectedProject
? { ...p, code: generatedCode.code }
: p
);
setProjects(updatedProjects);
alert('Projet sauvegardé ! ✓');
}
};

return (
<div className="flex h-screen bg-gray-50">
{/* Sidebar */}
<div className={`${sidebarOpen ? 'w-72' : 'w-20'} bg-white border-r border-gray-200 transition-all duration-300 flex flex-col`}>
{/* Logo */}
<div className="p-6 flex items-center justify-between border-b border-gray-200">
{sidebarOpen && (
<div className="flex items-center space-x-3">
<div className="w-10 h-10 bg-gradient-to-br from-blue-500 to-purple-600 rounded-lg flex items-center justify-center text-white font-bold text-lg">
EC
</div>
<div>
<h1 className="font-bold text-gray-900">Espace Codage</h1>
<p className="text-xs text-gray-500">Workspace Rosalinda</p>
</div>
</div>
)}
<button
onClick={() => setSidebarOpen(!sidebarOpen)}
className="p-2 hover:bg-gray-100 rounded-lg transition"
>
{sidebarOpen ? <X size={20} /> : <Menu size={20} />}
</button>
</div>

{/* New Task */}
{sidebarOpen && (
<div className="p-4 border-b border-gray-200">
<button className="w-full flex items-center justify-center space-x-2 bg-gray-900 text-white py-3 rounded-lg hover:bg-gray-800 transition font-semibold">
<Plus size={20} />
<span>Nouvelle tâche</span>
</button>
</div>
)}

{/* Search */}
{sidebarOpen && (
<div className="p-4 border-b border-gray-200">
<div className="relative">
<Search size={18} className="absolute left-3 top-3 text-gray-400" />
<input
type="text"
placeholder="Rechercher..."
className="w-full pl-10 pr-4 py-2 bg-gray-50 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 text-sm"
/>
</div>
</div>
)}

{/* Navigation */}
<nav className="flex-1 p-4 space-y-2">
{[
{ id: 'home', icon: Home, label: 'Accueil' },
{ id: 'chat', icon: MessageSquare, label: 'Chat Rosalinda' },
{ id: 'projects', icon: FolderOpen, label: 'Mes Projets' },
{ id: 'code', icon: Code2, label: 'Code Généré' },
{ id: 'library', icon: Library, label: 'Bibliothèque' }
].map(item => (
<button
key={item.id}
onClick={() => {
setCurrentView(item.id);
if (item.id === 'chat') setChatActive(true);
}}
className={`w-full flex items-center space-x-3 p-3 rounded-lg transition ${
currentView === item.id
? 'bg-blue-100 text-blue-900'
: 'text-gray-600 hover:bg-gray-50'
}`}
>
<item.icon size={20} />
{sidebarOpen && <span>{item.label}</span>}
</button>
))}
</nav>

{/* Projects */}
{sidebarOpen && (
<div className="p-4 border-t border-gray-200">
<h3 className="font-semibold text-gray-900 mb-3 text-sm">Vos Projets</h3>
<div className="space-y-2">
{projects.map(project => (
<button
key={project.id}
onClick={() => setSelectedProject(project.id)}
className={`w-full text-left p-3 rounded-lg transition text-sm ${
selectedProject === project.id
? 'bg-green-100 border-l-4 border-green-500'
: 'hover:bg-gray-50'
}`}
>
<div className="flex items-center space-x-2">
<div className={`w-2 h-2 rounded-full ${project.status === 'active' ? 'bg-green-500' : 'bg-gray-300'}`}></div>
<span className="font-medium">{project.name}</span>
</div>
<p className="text-xs text-gray-500 mt-1">{project.timestamp}</p>
</button>
))}
</div>
</div>
)}

{/* Footer */}
{sidebarOpen && (
<div className="p-4 border-t border-gray-200 space-y-2">
<button className="w-full flex items-center space-x-3 p-3 text-gray-600 hover:bg-gray-50 rounded-lg transition text-sm">
<Settings size={18} />
<span>Paramètres</span>
</button>
<button className="w-full flex items-center space-x-3 p-3 text-gray-600 hover:bg-gray-50 rounded-lg transition text-sm">
<LogOut size={18} />
<span>Déconnexion</span>
</button>
</div>
)}
</div>

{/* Main Content */}
<div className="flex-1 flex flex-col">
{/* Header */}
<div className="bg-white border-b border-gray-200 p-6 sticky top-0 z-10">
<div className="flevoilà je voudrais déjà vous intégrer toutes les côtes dedans soit propre et professionnel je voudrais la première interface comme celui que je vous ai prouvé sur la capture d'écra

Files changed (9) hide show
  1. README.md +8 -5
  2. components/chat.js +311 -0
  3. components/code.js +343 -0
  4. components/header.js +127 -0
  5. components/projects.js +269 -0
  6. components/sidebar.js +363 -0
  7. index.html +108 -19
  8. script.js +53 -0
  9. style.css +93 -18
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Codegenius Rosalinda Ai Coding Assistant
3
- emoji: 📉
4
- colorFrom: gray
5
- colorTo: purple
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: CodeGenius Rosalinda - AI Coding Assistant 🚀
3
+ colorFrom: purple
4
+ colorTo: green
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://huggingface.co/deepsite).
components/chat.js ADDED
@@ -0,0 +1,311 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class ChatComponent extends HTMLElement {
2
+ constructor() {
3
+ super();
4
+ this.messages = [];
5
+ }
6
+
7
+ connectedCallback() {
8
+ this.attachShadow({ mode: 'open' });
9
+ this.render();
10
+ this.setupEventListeners();
11
+ }
12
+
13
+ render() {
14
+ this.shadowRoot.innerHTML = `
15
+ <style>
16
+ :host {
17
+ display: block;
18
+ height: 100%;
19
+ }
20
+
21
+ .chat-container {
22
+ display: flex;
23
+ flex-direction: column;
24
+ height: 100%;
25
+ max-width: 800px;
26
+ margin: 0 auto;
27
+ }
28
+
29
+ .chat-header {
30
+ display: flex;
31
+ align-items: center;
32
+ gap: 1rem;
33
+ margin-bottom: 1.5rem;
34
+ }
35
+
36
+ .chat-avatar {
37
+ width: 3rem;
38
+ height: 3rem;
39
+ border-radius: 50%;
40
+ background: linear-gradient(135deg, #8b5cf6, #ec4899);
41
+ display: flex;
42
+ align-items: center;
43
+ justify-content: center;
44
+ color: white;
45
+ font-weight: bold;
46
+ font-size: 1.25rem;
47
+ }
48
+
49
+ .chat-title {
50
+ font-size: 1.5rem;
51
+ font-weight: 600;
52
+ color: #111827;
53
+ }
54
+
55
+ .chat-subtitle {
56
+ font-size: 0.875rem;
57
+ color: #6b7280;
58
+ }
59
+
60
+ .messages-container {
61
+ flex: 1;
62
+ overflow-y: auto;
63
+ padding: 1rem;
64
+ margin-bottom: 1.5rem;
65
+ display: flex;
66
+ flex-direction: column;
67
+ gap: 1rem;
68
+ }
69
+
70
+ .message {
71
+ max-width: 80%;
72
+ padding: 1rem;
73
+ border-radius: 1rem;
74
+ font-size: 0.9375rem;
75
+ line-height: 1.5;
76
+ position: relative;
77
+ }
78
+
79
+ .message.user {
80
+ align-self: flex-end;
81
+ background-color: #3b82f6;
82
+ color: white;
83
+ border-bottom-right-radius: 0;
84
+ }
85
+
86
+ .message.assistant {
87
+ align-self: flex-start;
88
+ background-color: #f3f4f6;
89
+ color: #111827;
90
+ border-bottom-left-radius: 0;
91
+ }
92
+
93
+ .message-time {
94
+ font-size: 0.75rem;
95
+ opacity: 0.8;
96
+ margin-top: 0.25rem;
97
+ text-align: right;
98
+ }
99
+
100
+ .input-container {
101
+ display: flex;
102
+ gap: 0.5rem;
103
+ padding: 1rem;
104
+ background-color: white;
105
+ border-radius: 0.5rem;
106
+ border: 1px solid #e5e7eb;
107
+ }
108
+
109
+ .chat-input {
110
+ flex: 1;
111
+ padding: 0.75rem 1rem;
112
+ border: 1px solid #e5e7eb;
113
+ border-radius: 0.5rem;
114
+ font-size: 0.9375rem;
115
+ resize: none;
116
+ min-height: 3rem;
117
+ max-height: 10rem;
118
+ }
119
+
120
+ .chat-input:focus {
121
+ outline: none;
122
+ border-color: #3b82f6;
123
+ box-shadow: 0 0 0 2px #bfdbfe;
124
+ }
125
+
126
+ .send-button {
127
+ padding: 0.75rem;
128
+ background-color: #3b82f6;
129
+ color: white;
130
+ border: none;
131
+ border-radius: 0.5rem;
132
+ cursor: pointer;
133
+ transition: background-color 0.2s;
134
+ }
135
+
136
+ .send-button:hover {
137
+ background-color: #2563eb;
138
+ }
139
+
140
+ .send-button:disabled {
141
+ background-color: #9ca3af;
142
+ cursor: not-allowed;
143
+ }
144
+
145
+ .typing-indicator {
146
+ display: flex;
147
+ align-items: center;
148
+ gap: 0.5rem;
149
+ padding: 1rem;
150
+ background-color: #f3f4f6;
151
+ border-radius: 0.5rem;
152
+ margin-bottom: 1rem;
153
+ align-self: flex-start;
154
+ }
155
+
156
+ .typing-dots {
157
+ display: flex;
158
+ gap: 0.25rem;
159
+ }
160
+
161
+ .typing-dot {
162
+ width: 0.5rem;
163
+ height: 0.5rem;
164
+ background-color: #6b7280;
165
+ border-radius: 50%;
166
+ animation: typingAnimation 1.4s infinite ease-in-out;
167
+ }
168
+
169
+ .typing-dot:nth-child(1) {
170
+ animation-delay: 0s;
171
+ }
172
+
173
+ .typing-dot:nth-child(2) {
174
+ animation-delay: 0.2s;
175
+ }
176
+
177
+ .typing-dot:nth-child(3) {
178
+ animation-delay: 0.4s;
179
+ }
180
+
181
+ @keyframes typingAnimation {
182
+ 0%, 60%, 100% { transform: translateY(0); }
183
+ 30% { transform: translateY(-0.25rem); }
184
+ }
185
+
186
+ .code-block {
187
+ position: relative;
188
+ background-color: #1e293b;
189
+ color: #f8fafc;
190
+ border-radius: 0.5rem;
191
+ overflow: hidden;
192
+ margin-top: 0.5rem;
193
+ }
194
+
195
+ .code-block pre {
196
+ padding: 1rem;
197
+ overflow-x: auto;
198
+ font-family: 'Courier New', Courier, monospace;
199
+ font-size: 0.875rem;
200
+ margin: 0;
201
+ }
202
+
203
+ .code-toolbar {
204
+ position: absolute;
205
+ top: 0.5rem;
206
+ right: 0.5rem;
207
+ display: flex;
208
+ gap: 0.5rem;
209
+ }
210
+
211
+ .code-toolbar button {
212
+ background-color: #334155;
213
+ color: white;
214
+ border: none;
215
+ padding: 0.25rem 0.5rem;
216
+ border-radius: 0.25rem;
217
+ cursor: pointer;
218
+ font-size: 0.75rem;
219
+ display: flex;
220
+ align-items: center;
221
+ gap: 0.25rem;
222
+ }
223
+
224
+ .code-toolbar button:hover {
225
+ background-color: #475569;
226
+ }
227
+ </style>
228
+
229
+ <div class="chat-container">
230
+ <div class="chat-header">
231
+ <div class="chat-avatar">R</div>
232
+ <div>
233
+ <h2 class="chat-title">Rosalinda</h2>
234
+ <p class="chat-subtitle">IA spécialisée en développement web</p>
235
+ </div>
236
+ </div>
237
+
238
+ <div class="messages-container" id="messages-container">
239
+ <!-- Messages will be added here dynamically -->
240
+ </div>
241
+
242
+ <div class="input-container">
243
+ <textarea class="chat-input" id="chat-input" placeholder="Demandez à Rosalinda de générer du code ou posez-lui une question..." rows="1"></textarea>
244
+ <button class="send-button" id="send-button">
245
+ <i data-feather="send"></i>
246
+ </button>
247
+ </div>
248
+ </div>
249
+ `;
250
+
251
+ // Initialize feather icons
252
+ const featherScript = document.createElement('script');
253
+ featherScript.src = 'https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js';
254
+ this.shadowRoot.appendChild(featherScript);
255
+
256
+ featherScript.onload = () => {
257
+ feather.replace();
258
+ };
259
+ }
260
+
261
+ setupEventListeners() {
262
+ const chatInput = this.shadowRoot.getElementById('chat-input');
263
+ const sendButton = this.shadowRoot.getElementById('send-button');
264
+ const messagesContainer = this.shadowRoot.getElementById('messages-container');
265
+
266
+ // Auto-resize textarea
267
+ chatInput.addEventListener('input', function() {
268
+ this.style.height = 'auto';
269
+ this.style.height = (this.scrollHeight) + 'px';
270
+ });
271
+
272
+ // Send message on Enter (but allow Shift+Enter for new lines)
273
+ chatInput.addEventListener('keydown', (e) => {
274
+ if (e.key === 'Enter' && !e.shiftKey) {
275
+ e.preventDefault();
276
+ this.sendMessage();
277
+ }
278
+ });
279
+
280
+ // Send message on button click
281
+ sendButton.addEventListener('click', () => this.sendMessage());
282
+
283
+ // Initial greeting from Rosalinda
284
+ this.addMessage({
285
+ user: 'Rosalinda',
286
+ type: 'assistant',
287
+ text: 'Bonjour ! Je suis Rosalinda, votre assistante IA pour le développement web. Comment puis-je vous aider aujourd\'hui ? Je peux générer du code HTML, CSS, JavaScript ou React pour vous.',
288
+ time: new Date().toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })
289
+ });
290
+ }
291
+
292
+ addMessage(message) {
293
+ this.messages.push(message);
294
+ this.renderMessages();
295
+
296
+ // Scroll to bottom
297
+ const messagesContainer = this.shadowRoot.getElementById('messages-container');
298
+ messagesContainer.scrollTop = messagesContainer.scrollHeight;
299
+ }
300
+
301
+ renderMessages() {
302
+ const messagesContainer = this.shadowRoot.getElementById('messages-container');
303
+ messagesContainer.innerHTML = '';
304
+
305
+ this.messages.forEach(msg => {
306
+ const messageDiv = document.createElement('div');
307
+ messageDiv.className = `message ${msg.type}`;
308
+
309
+ // Check if message contains code
310
+ let messageText = msg.text;
311
+ const codeMatch = msg.text.match(/
components/code.js ADDED
@@ -0,0 +1,343 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CodeComponent extends HTMLElement {
2
+ constructor() {
3
+ super();
4
+ this.code = '';
5
+ this.description = '';
6
+ }
7
+
8
+ connectedCallback() {
9
+ this.attachShadow({ mode: 'open' });
10
+ this.render();
11
+
12
+ // Listen for code updates
13
+ document.addEventListener('show-code', (e) => {
14
+ this.code = e.detail.code;
15
+ this.description = e.detail.description;
16
+ this.render();
17
+ });
18
+ }
19
+
20
+ render() {
21
+ this.shadowRoot.innerHTML = `
22
+ <style>
23
+ :host {
24
+ display: block;
25
+ }
26
+
27
+ .code-header {
28
+ display: flex;
29
+ align-items: center;
30
+ justify-content: space-between;
31
+ margin-bottom: 1.5rem;
32
+ }
33
+
34
+ .code-title {
35
+ font-size: 1.5rem;
36
+ font-weight: 600;
37
+ color: #111827;
38
+ }
39
+
40
+ .code-description {
41
+ color: #6b7280;
42
+ margin-bottom: 0.5rem;
43
+ }
44
+
45
+ .code-actions {
46
+ display: flex;
47
+ gap: 0.5rem;
48
+ }
49
+
50
+ .code-action {
51
+ display: flex;
52
+ align-items: center;
53
+ gap: 0.5rem;
54
+ padding: 0.5rem 1rem;
55
+ border-radius: 0.5rem;
56
+ font-weight: 500;
57
+ transition: all 0.2s;
58
+ }
59
+
60
+ .code-action.primary {
61
+ background-color: #3b82f6;
62
+ color: white;
63
+ }
64
+
65
+ .code-action.primary:hover {
66
+ background-color: #2563eb;
67
+ }
68
+
69
+ .code-action.secondary {
70
+ background-color: #f3f4f6;
71
+ color: #4b5563;
72
+ }
73
+
74
+ .code-action.secondary:hover {
75
+ background-color: #e5e7eb;
76
+ }
77
+
78
+ .code-block {
79
+ position: relative;
80
+ background-color: #1e293b;
81
+ color: #f8fafc;
82
+ border-radius: 0.5rem;
83
+ overflow: hidden;
84
+ margin-bottom: 1.5rem;
85
+ }
86
+
87
+ .code-block pre {
88
+ padding: 1.5rem;
89
+ overflow-x: auto;
90
+ font-family: 'Courier New', Courier, monospace;
91
+ font-size: 0.875rem;
92
+ margin: 0;
93
+ }
94
+
95
+ .code-toolbar {
96
+ position: absolute;
97
+ top: 0.5rem;
98
+ right: 0.5rem;
99
+ display: flex;
100
+ gap: 0.5rem;
101
+ }
102
+
103
+ .code-toolbar button {
104
+ background-color: #334155;
105
+ color: white;
106
+ border: none;
107
+ padding: 0.25rem 0.5rem;
108
+ border-radius: 0.25rem;
109
+ cursor: pointer;
110
+ font-size: 0.75rem;
111
+ display: flex;
112
+ align-items: center;
113
+ gap: 0.25rem;
114
+ }
115
+
116
+ .code-toolbar button:hover {
117
+ background-color: #475569;
118
+ }
119
+
120
+ .preview-container {
121
+ border: 1px solid #e5e7eb;
122
+ border-radius: 0.5rem;
123
+ overflow: hidden;
124
+ margin-top: 1.5rem;
125
+ }
126
+
127
+ .preview-header {
128
+ background-color: #f3f4f6;
129
+ padding: 0.75rem 1rem;
130
+ border-bottom: 1px solid #e5e7eb;
131
+ display: flex;
132
+ align-items: center;
133
+ justify-content: space-between;
134
+ }
135
+
136
+ .preview-title {
137
+ font-weight: 500;
138
+ color: #111827;
139
+ }
140
+
141
+ .preview-actions {
142
+ display: flex;
143
+ gap: 0.5rem;
144
+ }
145
+
146
+ .preview-action {
147
+ padding: 0.25rem;
148
+ border-radius: 0.25rem;
149
+ color: #6b7280;
150
+ transition: all 0.2s;
151
+ }
152
+
153
+ .preview-action:hover {
154
+ background-color: #e5e7eb;
155
+ color: #111827;
156
+ }
157
+
158
+ .preview-content {
159
+ background-color: white;
160
+ min-height: 200px;
161
+ padding: 1rem;
162
+ }
163
+
164
+ .empty-state {
165
+ text-align: center;
166
+ padding: 3rem 0;
167
+ }
168
+
169
+ .empty-icon {
170
+ width: 3rem;
171
+ height: 3rem;
172
+ background-color: #f3f4f6;
173
+ border-radius: 50%;
174
+ display: flex;
175
+ align-items: center;
176
+ justify-content: center;
177
+ margin: 0 auto 1rem;
178
+ color: #9ca3af;
179
+ }
180
+
181
+ .empty-title {
182
+ font-size: 1.125rem;
183
+ font-weight: 600;
184
+ color: #111827;
185
+ margin-bottom: 0.5rem;
186
+ }
187
+
188
+ .empty-description {
189
+ color: #6b7280;
190
+ max-width: 400px;
191
+ margin: 0 auto 1.5rem;
192
+ }
193
+
194
+ .empty-button {
195
+ background-color: #3b82f6;
196
+ color: white;
197
+ padding: 0.5rem 1rem;
198
+ border-radius: 0.5rem;
199
+ font-weight: 500;
200
+ transition: background-color 0.2s;
201
+ }
202
+
203
+ .empty-button:hover {
204
+ background-color: #2563eb;
205
+ }
206
+ </style>
207
+
208
+ ${this.code ? `
209
+ <div class="code-header">
210
+ <div>
211
+ <h2 class="code-title">Code Généré</h2>
212
+ <p class="code-description">${this.description}</p>
213
+ </div>
214
+ <div class="code-actions">
215
+ <button class="code-action primary" id="save-project">
216
+ <i data-feather="save"></i>
217
+ <span>Sauvegarder</span>
218
+ </button>
219
+ <button class="code-action secondary" id="new-chat">
220
+ <i data-feather="message-square"></i>
221
+ <span>Nouveau chat</span>
222
+ </button>
223
+ </div>
224
+ </div>
225
+
226
+ <div class="code-block">
227
+ <div class="code-toolbar">
228
+ <button class="copy-code" data-code="${escapeHtml(this.code)}">
229
+ <i data-feather="copy"></i>
230
+ <span>Copier</span>
231
+ </button>
232
+ <button class="download-code" data-code="${escapeHtml(this.code)}">
233
+ <i data-feather="download"></i>
234
+ <span>Télécharger</span>
235
+ </button>
236
+ </div>
237
+ <pre><code>${escapeHtml(this.code)}</code></pre>
238
+ </div>
239
+
240
+ <div class="preview-container">
241
+ <div class="preview-header">
242
+ <div class="preview-title">Aperçu</div>
243
+ <div class="preview-actions">
244
+ <button class="preview-action" title="Actualiser">
245
+ <i data-feather="refresh-cw"></i>
246
+ </button>
247
+ <button class="preview-action" title="Plein écran">
248
+ <i data-feather="maximize"></i>
249
+ </button>
250
+ </div>
251
+ </div>
252
+ <div class="preview-content">
253
+ <iframe srcdoc="${escapeHtml(this.code)}" frameborder="0" style="width: 100%; height: 400px;"></iframe>
254
+ </div>
255
+ </div>
256
+ ` : `
257
+ <div class="empty-state">
258
+ <div class="empty-icon">
259
+ <i data-feather="code"></i>
260
+ </div>
261
+ <h3 class="empty-title">Aucun code généré</h3>
262
+ <p class="empty-description">Demandez à Rosalinda de générer du code pour voir le résultat ici.</p>
263
+ <button class="empty-button" id="go-to-chat">
264
+ <i data-feather="message-square"></i>
265
+ <span>Discuter avec Rosalinda</span>
266
+ </button>
267
+ </div>
268
+ `}
269
+ `;
270
+
271
+ // Initialize feather icons
272
+ const featherScript = document.createElement('script');
273
+ featherScript.src = 'https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js';
274
+ this.shadowRoot.appendChild(featherScript);
275
+
276
+ featherScript.onload = () => {
277
+ feather.replace();
278
+ };
279
+
280
+ // Add event listeners
281
+ if (this.code) {
282
+ // Copy code button
283
+ this.shadowRoot.querySelector('.copy-code').addEventListener('click', () => {
284
+ const code = this.shadowRoot.querySelector('.copy-code').getAttribute('data-code');
285
+ navigator.clipboard.writeText(code).then(() => {
286
+ const button = this.shadowRoot.querySelector('.copy-code');
287
+ const originalText = button.innerHTML;
288
+ button.innerHTML = '<i data-feather="check"></i> Copié !';
289
+ feather.replace();
290
+ setTimeout(() => {
291
+ button.innerHTML = originalText;
292
+ feather.replace();
293
+ }, 2000);
294
+ });
295
+ });
296
+
297
+ // Download code button
298
+ this.shadowRoot.querySelector('.download-code').addEventListener('click', () => {
299
+ const code = this.shadowRoot.querySelector('.download-code').getAttribute('data-code');
300
+ const element = document.createElement('a');
301
+ element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(code));
302
+ element.setAttribute('download', 'code.html');
303
+ element.style.display = 'none';
304
+ document.body.appendChild(element);
305
+ element.click();
306
+ document.body.removeChild(element);
307
+ });
308
+
309
+ // Save to project button
310
+ this.shadowRoot.getElementById('save-project').addEventListener('click', () => {
311
+ document.dispatchEvent(new CustomEvent('save-project', {
312
+ detail: {
313
+ code: this.code,
314
+ description: this.description
315
+ }
316
+ }));
317
+ alert('Projet sauvegardé avec succès !');
318
+ });
319
+
320
+ // New chat button
321
+ this.shadowRoot.getElementById('new-chat').addEventListener('click', () => {
322
+ document.dispatchEvent(new CustomEvent('navigate', { detail: 'chat' }));
323
+ });
324
+ } else {
325
+ // Go to chat button
326
+ this.shadowRoot.getElementById('go-to-chat').addEventListener('click', () => {
327
+ document.dispatchEvent(new CustomEvent('navigate', { detail: 'chat' }));
328
+ });
329
+ }
330
+ }
331
+ }
332
+
333
+ // Helper function to escape HTML
334
+ function escapeHtml(unsafe) {
335
+ return unsafe
336
+ .replace(/&/g, "&amp;")
337
+ .replace(/</g, "&lt;")
338
+ .replace(/>/g, "&gt;")
339
+ .replace(/"/g, "&quot;")
340
+ .replace(/'/g, "&#039;");
341
+ }
342
+
343
+ customElements.define('code-component', CodeComponent);
components/header.js ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class HeaderComponent extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ :host {
7
+ display: block;
8
+ background-color: white;
9
+ border-bottom: 1px solid #e5e7eb;
10
+ padding: 1.5rem;
11
+ position: sticky;
12
+ top: 0;
13
+ z-index: 20;
14
+ }
15
+
16
+ .header-container {
17
+ display: flex;
18
+ align-items: center;
19
+ justify-content: space-between;
20
+ }
21
+
22
+ .mobile-menu-button {
23
+ display: none;
24
+ padding: 0.5rem;
25
+ border-radius: 0.375rem;
26
+ background-color: #f3f4f6;
27
+ }
28
+
29
+ .mobile-menu-button:hover {
30
+ background-color: #e5e7eb;
31
+ }
32
+
33
+ .header-title {
34
+ font-size: 1.25rem;
35
+ font-weight: 600;
36
+ color: #111827;
37
+ }
38
+
39
+ .header-actions {
40
+ display: flex;
41
+ align-items: center;
42
+ gap: 1rem;
43
+ }
44
+
45
+ .action-button {
46
+ padding: 0.5rem;
47
+ border-radius: 0.375rem;
48
+ color: #4b5563;
49
+ transition: all 0.2s;
50
+ }
51
+
52
+ .action-button:hover {
53
+ background-color: #f3f4f6;
54
+ color: #111827;
55
+ }
56
+
57
+ .user-avatar {
58
+ width: 2.5rem;
59
+ height: 2.5rem;
60
+ border-radius: 50%;
61
+ background-color: #e5e7eb;
62
+ display: flex;
63
+ align-items: center;
64
+ justify-content: center;
65
+ color: #4b5563;
66
+ font-weight: 600;
67
+ cursor: pointer;
68
+ }
69
+
70
+ @media (max-width: 768px) {
71
+ .mobile-menu-button {
72
+ display: block;
73
+ }
74
+
75
+ .header-title {
76
+ font-size: 1rem;
77
+ }
78
+ }
79
+ </style>
80
+
81
+ <div class="header-container">
82
+ <button class="mobile-menu-button" id="mobile-menu-button">
83
+ <i data-feather="menu"></i>
84
+ </button>
85
+ <h1 class="header-title" id="header-title">Accueil</h1>
86
+ <div class="header-actions">
87
+ <button class="action-button">
88
+ <i data-feather="share-2"></i>
89
+ </button>
90
+ <button class="action-button">
91
+ <i data-feather="bell"></i>
92
+ </button>
93
+ <div class="user-avatar">JD</div>
94
+ </div>
95
+ </div>
96
+ `;
97
+
98
+ // Initialize feather icons
99
+ const featherScript = document.createElement('script');
100
+ featherScript.src = 'https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js';
101
+ this.shadowRoot.appendChild(featherScript);
102
+
103
+ featherScript.onload = () => {
104
+ feather.replace();
105
+ };
106
+
107
+ // Mobile menu toggle
108
+ this.shadowRoot.getElementById('mobile-menu-button').addEventListener('click', () => {
109
+ document.querySelector('sidebar-component').classList.add('open');
110
+ document.body.classList.add('overflow-hidden');
111
+ });
112
+
113
+ // Update title based on view
114
+ document.addEventListener('navigate', (e) => {
115
+ const titles = {
116
+ 'home': 'Accueil',
117
+ 'chat': 'Chat Rosalinda',
118
+ 'projects': 'Mes Projets',
119
+ 'code': 'Code Généré',
120
+ 'library': 'Bibliothèque'
121
+ };
122
+ this.shadowRoot.getElementById('header-title').textContent = titles[e.detail] || 'Accueil';
123
+ });
124
+ }
125
+ }
126
+
127
+ customElements.define('header-component', HeaderComponent);
components/projects.js ADDED
@@ -0,0 +1,269 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class ProjectsComponent extends HTMLElement {
2
+ constructor() {
3
+ super();
4
+ this.projects = [
5
+ { id: 1, name: 'Portfolio Pro', status: 'active', timestamp: '2 jours', code: '' },
6
+ { id: 2, name: 'E-shop Mode', status: 'active', timestamp: '5 jours', code: '' },
7
+ { id: 3, name: 'App SaaS', status: 'archived', timestamp: '10 jours', code: '' }
8
+ ];
9
+ }
10
+
11
+ connectedCallback() {
12
+ this.attachShadow({ mode: 'open' });
13
+ this.render();
14
+ }
15
+
16
+ render() {
17
+ this.shadowRoot.innerHTML = `
18
+ <style>
19
+ :host {
20
+ display: block;
21
+ }
22
+
23
+ .projects-header {
24
+ display: flex;
25
+ align-items: center;
26
+ justify-content: space-between;
27
+ margin-bottom: 1.5rem;
28
+ }
29
+
30
+ .projects-title {
31
+ font-size: 1.5rem;
32
+ font-weight: 600;
33
+ color: #111827;
34
+ }
35
+
36
+ .new-project-button {
37
+ display: flex;
38
+ align-items: center;
39
+ gap: 0.5rem;
40
+ background-color: #3b82f6;
41
+ color: white;
42
+ padding: 0.5rem 1rem;
43
+ border-radius: 0.5rem;
44
+ font-weight: 500;
45
+ transition: background-color 0.2s;
46
+ }
47
+
48
+ .new-project-button:hover {
49
+ background-color: #2563eb;
50
+ }
51
+
52
+ .projects-grid {
53
+ display: grid;
54
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
55
+ gap: 1.5rem;
56
+ }
57
+
58
+ .project-card {
59
+ background-color: white;
60
+ border: 1px solid #e5e7eb;
61
+ border-radius: 0.75rem;
62
+ padding: 1.5rem;
63
+ transition: all 0.2s;
64
+ cursor: pointer;
65
+ }
66
+
67
+ .project-card:hover {
68
+ transform: translateY(-2px);
69
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
70
+ }
71
+
72
+ .project-card.active {
73
+ border-left: 4px solid #10b981;
74
+ }
75
+
76
+ .project-name {
77
+ font-size: 1.125rem;
78
+ font-weight: 600;
79
+ color: #111827;
80
+ margin-bottom: 0.5rem;
81
+ }
82
+
83
+ .project-meta {
84
+ display: flex;
85
+ align-items: center;
86
+ gap: 0.5rem;
87
+ margin-bottom: 1rem;
88
+ }
89
+
90
+ .project-status {
91
+ font-size: 0.75rem;
92
+ padding: 0.25rem 0.5rem;
93
+ border-radius: 1rem;
94
+ }
95
+
96
+ .project-status.active {
97
+ background-color: #ecfdf5;
98
+ color: #065f46;
99
+ }
100
+
101
+ .project-status.archived {
102
+ background-color: #f3f4f6;
103
+ color: #4b5563;
104
+ }
105
+
106
+ .project-time {
107
+ font-size: 0.75rem;
108
+ color: #6b7280;
109
+ }
110
+
111
+ .project-actions {
112
+ display: flex;
113
+ gap: 0.5rem;
114
+ margin-top: 1rem;
115
+ }
116
+
117
+ .project-action {
118
+ padding: 0.5rem;
119
+ border-radius: 0.375rem;
120
+ background-color: #f3f4f6;
121
+ color: #4b5563;
122
+ transition: all 0.2s;
123
+ display: flex;
124
+ align-items: center;
125
+ justify-content: center;
126
+ }
127
+
128
+ .project-action:hover {
129
+ background-color: #e5e7eb;
130
+ }
131
+
132
+ .empty-state {
133
+ text-align: center;
134
+ padding: 3rem 0;
135
+ grid-column: 1 / -1;
136
+ }
137
+
138
+ .empty-icon {
139
+ width: 3rem;
140
+ height: 3rem;
141
+ background-color: #f3f4f6;
142
+ border-radius: 50%;
143
+ display: flex;
144
+ align-items: center;
145
+ justify-content: center;
146
+ margin: 0 auto 1rem;
147
+ color: #9ca3af;
148
+ }
149
+
150
+ .empty-title {
151
+ font-size: 1.125rem;
152
+ font-weight: 600;
153
+ color: #111827;
154
+ margin-bottom: 0.5rem;
155
+ }
156
+
157
+ .empty-description {
158
+ color: #6b7280;
159
+ max-width: 400px;
160
+ margin: 0 auto 1.5rem;
161
+ }
162
+
163
+ .empty-button {
164
+ background-color: #3b82f6;
165
+ color: white;
166
+ padding: 0.5rem 1rem;
167
+ border-radius: 0.5rem;
168
+ font-weight: 500;
169
+ transition: background-color 0.2s;
170
+ }
171
+
172
+ .empty-button:hover {
173
+ background-color: #2563eb;
174
+ }
175
+
176
+ @media (max-width: 640px) {
177
+ .projects-grid {
178
+ grid-template-columns: 1fr;
179
+ }
180
+ }
181
+ </style>
182
+
183
+ <div class="projects-header">
184
+ <h2 class="projects-title">Mes Projets</h2>
185
+ <button class="new-project-button">
186
+ <i data-feather="plus"></i>
187
+ <span>Nouveau projet</span>
188
+ </button>
189
+ </div>
190
+
191
+ <div class="projects-grid">
192
+ ${this.projects.length > 0 ?
193
+ this.projects.map(project => `
194
+ <div class="project-card" data-id="${project.id}">
195
+ <h3 class="project-name">${project.name}</h3>
196
+ <div class="project-meta">
197
+ <span class="project-status ${project.status}">${project.status === 'active' ? 'Actif' : 'Archivé'}</span>
198
+ <span class="project-time">${project.timestamp}</span>
199
+ </div>
200
+ <div class="project-actions">
201
+ <button class="project-action" title="Ouvrir">
202
+ <i data-feather="folder"></i>
203
+ </button>
204
+ <button class="project-action" title="Partager">
205
+ <i data-feather="share-2"></i>
206
+ </button>
207
+ <button class="project-action" title="Archiver">
208
+ <i data-feather="archive"></i>
209
+ </button>
210
+ </div>
211
+ </div>
212
+ `).join('') : `
213
+ <div class="empty-state">
214
+ <div class="empty-icon">
215
+ <i data-feather="folder"></i>
216
+ </div>
217
+ <h3 class="empty-title">Aucun projet trouvé</h3>
218
+ <p class="empty-description">Commencez par créer un nouveau projet ou demandez à Rosalinda de générer du code pour vous.</p>
219
+ <button class="empty-button">
220
+ <i data-feather="plus"></i>
221
+ <span>Créer un projet</span>
222
+ </button>
223
+ </div>
224
+ `}
225
+ </div>
226
+ `;
227
+
228
+ // Initialize feather icons
229
+ const featherScript = document.createElement('script');
230
+ featherScript.src = 'https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js';
231
+ this.shadowRoot.appendChild(featherScript);
232
+
233
+ featherScript.onload = () => {
234
+ feather.replace();
235
+ };
236
+
237
+ // Add event listeners
238
+ this.shadowRoot.querySelectorAll('.project-card').forEach(card => {
239
+ card.addEventListener('click', () => {
240
+ const projectId = parseInt(card.getAttribute('data-id'));
241
+ const project = this.projects.find(p => p.id === projectId);
242
+
243
+ if (project && project.code) {
244
+ document.dispatchEvent(new CustomEvent('show-code', {
245
+ detail: {
246
+ code: project.code,
247
+ description: project.name
248
+ }
249
+ }));
250
+ }
251
+ });
252
+ });
253
+
254
+ // New project button
255
+ this.shadowRoot.querySelector('.new-project-button').addEventListener('click', () => {
256
+ document.dispatchEvent(new CustomEvent('navigate', { detail: 'chat' }));
257
+ });
258
+
259
+ // Empty state button
260
+ const emptyButton = this.shadowRoot.querySelector('.empty-button');
261
+ if (emptyButton) {
262
+ emptyButton.addEventListener('click', () => {
263
+ document.dispatchEvent(new CustomEvent('navigate', { detail: 'chat' }));
264
+ });
265
+ }
266
+ }
267
+ }
268
+
269
+ customElements.define('projects-component', ProjectsComponent);
components/sidebar.js ADDED
@@ -0,0 +1,363 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class SidebarComponent extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ :host {
7
+ display: block;
8
+ width: 288px;
9
+ background-color: white;
10
+ border-right: 1px solid #e5e7eb;
11
+ transition: all 0.3s ease;
12
+ height: 100vh;
13
+ position: relative;
14
+ z-index: 30;
15
+ }
16
+
17
+ :host(.open) {
18
+ transform: translateX(0);
19
+ }
20
+
21
+ .logo-container {
22
+ display: flex;
23
+ align-items: center;
24
+ padding: 1.5rem;
25
+ border-bottom: 1px solid #e5e7eb;
26
+ }
27
+
28
+ .logo {
29
+ width: 2.5rem;
30
+ height: 2.5rem;
31
+ background: linear-gradient(135deg, #3b82f6, #8b5cf6);
32
+ border-radius: 0.5rem;
33
+ display: flex;
34
+ align-items: center;
35
+ justify-content: center;
36
+ color: white;
37
+ font-weight: bold;
38
+ font-size: 1.125rem;
39
+ margin-right: 0.75rem;
40
+ }
41
+
42
+ .logo-text h1 {
43
+ font-weight: 700;
44
+ color: #111827;
45
+ margin: 0;
46
+ }
47
+
48
+ .logo-text p {
49
+ font-size: 0.75rem;
50
+ color: #6b7280;
51
+ margin: 0;
52
+ }
53
+
54
+ .toggle-button {
55
+ padding: 0.5rem;
56
+ border-radius: 0.375rem;
57
+ transition: background-color 0.2s;
58
+ margin-left: auto;
59
+ }
60
+
61
+ .toggle-button:hover {
62
+ background-color: #f3f4f6;
63
+ }
64
+
65
+ .new-task {
66
+ padding: 1rem;
67
+ border-bottom: 1px solid #e5e7eb;
68
+ }
69
+
70
+ .new-task-button {
71
+ width: 100%;
72
+ display: flex;
73
+ align-items: center;
74
+ justify-content: center;
75
+ gap: 0.5rem;
76
+ background-color: #111827;
77
+ color: white;
78
+ padding: 0.75rem;
79
+ border-radius: 0.5rem;
80
+ font-weight: 600;
81
+ transition: background-color 0.2s;
82
+ }
83
+
84
+ .new-task-button:hover {
85
+ background-color: #1f2937;
86
+ }
87
+
88
+ .search {
89
+ padding: 1rem;
90
+ border-bottom: 1px solid #e5e7eb;
91
+ }
92
+
93
+ .search-container {
94
+ position: relative;
95
+ }
96
+
97
+ .search-icon {
98
+ position: absolute;
99
+ left: 0.75rem;
100
+ top: 0.75rem;
101
+ color: #9ca3af;
102
+ }
103
+
104
+ .search-input {
105
+ width: 100%;
106
+ padding-left: 2.5rem;
107
+ padding-right: 1rem;
108
+ padding-top: 0.5rem;
109
+ padding-bottom: 0.5rem;
110
+ background-color: #f9fafb;
111
+ border: 1px solid #e5e7eb;
112
+ border-radius: 0.5rem;
113
+ font-size: 0.875rem;
114
+ }
115
+
116
+ .search-input:focus {
117
+ outline: none;
118
+ border-color: #3b82f6;
119
+ box-shadow: 0 0 0 2px #bfdbfe;
120
+ }
121
+
122
+ nav {
123
+ flex: 1;
124
+ padding: 1rem;
125
+ display: flex;
126
+ flex-direction: column;
127
+ gap: 0.5rem;
128
+ }
129
+
130
+ .nav-button {
131
+ width: 100%;
132
+ display: flex;
133
+ align-items: center;
134
+ gap: 0.75rem;
135
+ padding: 0.75rem;
136
+ border-radius: 0.5rem;
137
+ transition: all 0.2s;
138
+ color: #4b5563;
139
+ }
140
+
141
+ .nav-button:hover {
142
+ background-color: #f3f4f6;
143
+ }
144
+
145
+ .nav-button.active {
146
+ background-color: #dbeafe;
147
+ color: #1e40af;
148
+ }
149
+
150
+ .projects {
151
+ padding: 1rem;
152
+ border-top: 1px solid #e5e7eb;
153
+ }
154
+
155
+ .projects-title {
156
+ font-weight: 600;
157
+ color: #111827;
158
+ margin-bottom: 0.75rem;
159
+ font-size: 0.875rem;
160
+ }
161
+
162
+ .project-item {
163
+ width: 100%;
164
+ text-align: left;
165
+ padding: 0.75rem;
166
+ border-radius: 0.5rem;
167
+ transition: all 0.2s;
168
+ font-size: 0.875rem;
169
+ margin-bottom: 0.25rem;
170
+ }
171
+
172
+ .project-item:hover {
173
+ background-color: #f3f4f6;
174
+ }
175
+
176
+ .project-item.active {
177
+ background-color: #ecfdf5;
178
+ border-left: 4px solid #10b981;
179
+ }
180
+
181
+ .project-status {
182
+ width: 0.5rem;
183
+ height: 0.5rem;
184
+ border-radius: 50%;
185
+ margin-right: 0.5rem;
186
+ }
187
+
188
+ .project-status.active {
189
+ background-color: #10b981;
190
+ }
191
+
192
+ .project-status.archived {
193
+ background-color: #d1d5db;
194
+ }
195
+
196
+ .project-name {
197
+ font-weight: 500;
198
+ }
199
+
200
+ .project-time {
201
+ color: #6b7280;
202
+ font-size: 0.75rem;
203
+ margin-top: 0.25rem;
204
+ }
205
+
206
+ .footer {
207
+ padding: 1rem;
208
+ border-top: 1px solid #e5e7eb;
209
+ display: flex;
210
+ flex-direction: column;
211
+ gap: 0.5rem;
212
+ }
213
+
214
+ .footer-button {
215
+ width: 100%;
216
+ display: flex;
217
+ align-items: center;
218
+ gap: 0.75rem;
219
+ padding: 0.75rem;
220
+ border-radius: 0.5rem;
221
+ transition: all 0.2s;
222
+ color: #4b5563;
223
+ font-size: 0.875rem;
224
+ }
225
+
226
+ .footer-button:hover {
227
+ background-color: #f3f4f6;
228
+ }
229
+
230
+ @media (max-width: 768px) {
231
+ :host {
232
+ position: fixed;
233
+ left: 0;
234
+ top: 0;
235
+ transform: translateX(-100%);
236
+ }
237
+
238
+ :host(.open) {
239
+ transform: translateX(0);
240
+ }
241
+ }
242
+ </style>
243
+
244
+ <div class="logo-container">
245
+ <div class="logo">CG</div>
246
+ <div class="logo-text">
247
+ <h1>CodeGenius</h1>
248
+ <p>Workspace Rosalinda</p>
249
+ </div>
250
+ <button class="toggle-button" id="sidebar-toggle">
251
+ <i data-feather="x"></i>
252
+ </button>
253
+ </div>
254
+
255
+ <div class="new-task">
256
+ <button class="new-task-button">
257
+ <i data-feather="plus"></i>
258
+ <span>Nouvelle tâche</span>
259
+ </button>
260
+ </div>
261
+
262
+ <div class="search">
263
+ <div class="search-container">
264
+ <i data-feather="search" class="search-icon"></i>
265
+ <input type="text" placeholder="Rechercher..." class="search-input">
266
+ </div>
267
+ </div>
268
+
269
+ <nav>
270
+ <a href="#" class="nav-button active" data-view="home">
271
+ <i data-feather="home"></i>
272
+ <span>Accueil</span>
273
+ </a>
274
+ <a href="#" class="nav-button" data-view="chat">
275
+ <i data-feather="message-square"></i>
276
+ <span>Chat Rosalinda</span>
277
+ </a>
278
+ <a href="#" class="nav-button" data-view="projects">
279
+ <i data-feather="folder"></i>
280
+ <span>Mes Projets</span>
281
+ </a>
282
+ <a href="#" class="nav-button" data-view="code">
283
+ <i data-feather="code"></i>
284
+ <span>Code Généré</span>
285
+ </a>
286
+ <a href="#" class="nav-button" data-view="library">
287
+ <i data-feather="book"></i>
288
+ <span>Bibliothèque</span>
289
+ </a>
290
+ </nav>
291
+
292
+ <div class="projects">
293
+ <h3 class="projects-title">Vos Projets</h3>
294
+ <div>
295
+ <button class="project-item active">
296
+ <div class="flex items-center">
297
+ <div class="project-status active"></div>
298
+ <span class="project-name">Portfolio Pro</span>
299
+ </div>
300
+ <p class="project-time">2 jours</p>
301
+ </button>
302
+ <button class="project-item">
303
+ <div class="flex items-center">
304
+ <div class="project-status active"></div>
305
+ <span class="project-name">E-shop Mode</span>
306
+ </div>
307
+ <p class="project-time">5 jours</p>
308
+ </button>
309
+ <button class="project-item">
310
+ <div class="flex items-center">
311
+ <div class="project-status archived"></div>
312
+ <span class="project-name">App SaaS</span>
313
+ </div>
314
+ <p class="project-time">10 jours</p>
315
+ </button>
316
+ </div>
317
+ </div>
318
+
319
+ <div class="footer">
320
+ <button class="footer-button">
321
+ <i data-feather="settings"></i>
322
+ <span>Paramètres</span>
323
+ </button>
324
+ <button class="footer-button">
325
+ <i data-feather="log-out"></i>
326
+ <span>Déconnexion</span>
327
+ </button>
328
+ </div>
329
+ `;
330
+
331
+ // Initialize feather icons
332
+ const featherScript = document.createElement('script');
333
+ featherScript.src = 'https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js';
334
+ this.shadowRoot.appendChild(featherScript);
335
+
336
+ featherScript.onload = () => {
337
+ feather.replace();
338
+ };
339
+
340
+ // Navigation
341
+ this.shadowRoot.querySelectorAll('[data-view]').forEach(link => {
342
+ link.addEventListener('click', (e) => {
343
+ e.preventDefault();
344
+ const view = link.getAttribute('data-view');
345
+ document.dispatchEvent(new CustomEvent('navigate', { detail: view }));
346
+
347
+ // Update active state
348
+ this.shadowRoot.querySelectorAll('.nav-button').forEach(btn => {
349
+ btn.classList.remove('active');
350
+ });
351
+ link.classList.add('active');
352
+ });
353
+ });
354
+
355
+ // Toggle sidebar on mobile
356
+ this.shadowRoot.getElementById('sidebar-toggle').addEventListener('click', () => {
357
+ this.classList.remove('open');
358
+ document.body.classList.remove('overflow-hidden');
359
+ });
360
+ }
361
+ }
362
+
363
+ customElements.define('sidebar-component', SidebarComponent);
index.html CHANGED
@@ -1,19 +1,108 @@
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>CodeGenius Rosalinda - AI Coding Assistant</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
10
+ <script src="https://unpkg.com/feather-icons"></script>
11
+ </head>
12
+ <body class="bg-gray-50">
13
+ <div class="flex h-screen">
14
+ <!-- Sidebar Component -->
15
+ <sidebar-component></sidebar-component>
16
+
17
+ <!-- Main Content -->
18
+ <main class="flex-1 flex flex-col overflow-hidden">
19
+ <!-- Header Component -->
20
+ <header-component></header-component>
21
+
22
+ <!-- Dynamic Content Area -->
23
+ <div class="flex-1 overflow-y-auto p-6">
24
+ <!-- Home View (Default) -->
25
+ <div id="home-view" class="view-content">
26
+ <div class="max-w-4xl mx-auto">
27
+ <div class="text-center mb-12">
28
+ <h1 class="text-4xl font-bold text-gray-900 mb-4">Bienvenue sur CodeGenius Rosalinda</h1>
29
+ <p class="text-xl text-gray-600">Votre assistant IA pour générer du code professionnel en temps réel</p>
30
+ </div>
31
+
32
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-12">
33
+ <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-200 hover:shadow-md transition">
34
+ <div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center mb-4">
35
+ <i data-feather="code" class="text-blue-600"></i>
36
+ </div>
37
+ <h3 class="font-bold text-lg mb-2">Génération de code</h3>
38
+ <p class="text-gray-600">Demandez à Rosalinda de créer du HTML, CSS, JavaScript ou React pour vous</p>
39
+ </div>
40
+ <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-200 hover:shadow-md transition">
41
+ <div class="w-12 h-12 bg-purple-100 rounded-lg flex items-center justify-center mb-4">
42
+ <i data-feather="folder" class="text-purple-600"></i>
43
+ </div>
44
+ <h3 class="font-bold text-lg mb-2">Gestion de projets</h3>
45
+ <p class="text-gray-600">Organisez et sauvegardez vos différents projets de codage</p>
46
+ </div>
47
+ <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-200 hover:shadow-md transition">
48
+ <div class="w-12 h-12 bg-green-100 rounded-lg flex items-center justify-center mb-4">
49
+ <i data-feather="message-square" class="text-green-600"></i>
50
+ </div>
51
+ <h3 class="font-bold text-lg mb-2">Chat intelligent</h3>
52
+ <p class="text-gray-600">Discutez avec Rosalinda pour obtenir des conseils et solutions</p>
53
+ </div>
54
+ </div>
55
+
56
+ <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-200">
57
+ <h2 class="font-bold text-xl mb-4">Exemples de demandes</h2>
58
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
59
+ <button class="example-prompt bg-gray-50 hover:bg-gray-100 p-4 rounded-lg text-left transition">
60
+ "Crée une landing page moderne avec un formulaire de contact"
61
+ </button>
62
+ <button class="example-prompt bg-gray-50 hover:bg-gray-100 p-4 rounded-lg text-left transition">
63
+ "Génère un composant React pour une galerie d'images"
64
+ </button>
65
+ <button class="example-prompt bg-gray-50 hover:bg-gray-100 p-4 rounded-lg text-left transition">
66
+ "Montre-moi comment créer un menu responsive en CSS"
67
+ </button>
68
+ <button class="example-prompt bg-gray-50 hover:bg-gray-100 p-4 rounded-lg text-left transition">
69
+ "Aide-moi à debugger ce code JavaScript"
70
+ </button>
71
+ </div>
72
+ </div>
73
+ </div>
74
+ </div>
75
+
76
+ <!-- Chat View -->
77
+ <div id="chat-view" class="view-content hidden">
78
+ <chat-component></chat-component>
79
+ </div>
80
+
81
+ <!-- Projects View -->
82
+ <div id="projects-view" class="view-content hidden">
83
+ <projects-component></projects-component>
84
+ </div>
85
+
86
+ <!-- Code View -->
87
+ <div id="code-view" class="view-content hidden">
88
+ <code-component></code-component>
89
+ </div>
90
+ </div>
91
+ </main>
92
+ </div>
93
+
94
+ <!-- Web Components -->
95
+ <script src="components/sidebar.js"></script>
96
+ <script src="components/header.js"></script>
97
+ <script src="components/chat.js"></script>
98
+ <script src="components/projects.js"></script>
99
+ <script src="components/code.js"></script>
100
+
101
+ <!-- Main Script -->
102
+ <script src="script.js"></script>
103
+ <script>
104
+ feather.replace();
105
+ </script>
106
+ <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
107
+ </body>
108
+ </html>
script.js ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Main Application Logic
2
+ document.addEventListener('DOMContentLoaded', function() {
3
+ // Navigation between views
4
+ const navigateToView = (viewId) => {
5
+ document.querySelectorAll('.view-content').forEach(view => {
6
+ view.classList.add('hidden');
7
+ });
8
+ document.getElementById(`${viewId}-view`).classList.remove('hidden');
9
+ };
10
+
11
+ // Example prompt buttons
12
+ document.querySelectorAll('.example-prompt').forEach(button => {
13
+ button.addEventListener('click', function() {
14
+ navigateToView('chat');
15
+ const chatInput = document.querySelector('#chat-input');
16
+ if (chatInput) {
17
+ chatInput.value = this.textContent.trim();
18
+ chatInput.focus();
19
+ }
20
+ });
21
+ });
22
+
23
+ // Mobile menu toggle
24
+ const mobileMenuButton = document.querySelector('#mobile-menu-button');
25
+ if (mobileMenuButton) {
26
+ mobileMenuButton.addEventListener('click', function() {
27
+ document.querySelector('sidebar-component').classList.toggle('open');
28
+ document.body.classList.toggle('overflow-hidden');
29
+ });
30
+ }
31
+
32
+ // Close mobile menu when clicking on overlay
33
+ const overlay = document.querySelector('.sidebar-overlay');
34
+ if (overlay) {
35
+ overlay.addEventListener('click', function() {
36
+ document.querySelector('sidebar-component').classList.remove('open');
37
+ document.body.classList.remove('overflow-hidden');
38
+ });
39
+ }
40
+ });
41
+
42
+ // Simulated Rosalinda AI responses
43
+ async function simulateRosalindaResponse(prompt) {
44
+ // In a real implementation, this would call an actual AI API
45
+ return new Promise(resolve => {
46
+ setTimeout(() => {
47
+ const codeRequests = ['code', 'html', 'css', 'javascript', 'react', 'component', 'page'];
48
+ const isCodeRequest = codeRequests.some(term => prompt.toLowerCase().includes(term));
49
+
50
+ if (isCodeRequest) {
51
+ resolve({
52
+ text: `Voici le code que vous avez demandé pour "${prompt}":\n\n` +
53
+ '
style.css CHANGED
@@ -1,28 +1,103 @@
 
1
  body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
4
  }
5
 
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
9
  }
10
 
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
16
  }
17
 
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
 
24
  }
25
 
26
- .card p:last-child {
27
- margin-bottom: 0;
 
28
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Base Styles */
2
  body {
3
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
 
4
  }
5
 
6
+ /* View Transitions */
7
+ .view-content {
8
+ animation: fadeIn 0.3s ease-out;
9
  }
10
 
11
+ @keyframes fadeIn {
12
+ from { opacity: 0; transform: translateY(10px); }
13
+ to { opacity: 1; transform: translateY(0); }
 
 
14
  }
15
 
16
+ /* Code Block Styling */
17
+ .code-block {
18
+ position: relative;
19
+ background-color: #1e293b;
20
+ color: #f8fafc;
21
+ border-radius: 0.5rem;
22
+ overflow: hidden;
23
  }
24
 
25
+ .code-block pre {
26
+ padding: 1.5rem;
27
+ overflow-x: auto;
28
  }
29
+
30
+ .code-block .code-toolbar {
31
+ position: absolute;
32
+ top: 0.5rem;
33
+ right: 0.5rem;
34
+ display: flex;
35
+ gap: 0.5rem;
36
+ }
37
+
38
+ .code-toolbar button {
39
+ background-color: #334155;
40
+ color: white;
41
+ border: none;
42
+ padding: 0.25rem 0.5rem;
43
+ border-radius: 0.25rem;
44
+ cursor: pointer;
45
+ font-size: 0.75rem;
46
+ display: flex;
47
+ align-items: center;
48
+ gap: 0.25rem;
49
+ }
50
+
51
+ .code-toolbar button:hover {
52
+ background-color: #475569;
53
+ }
54
+
55
+ /* Chat Message Styling */
56
+ .chat-message.user {
57
+ background-color: #3b82f6;
58
+ color: white;
59
+ border-radius: 1rem 1rem 0 1rem;
60
+ align-self: flex-end;
61
+ }
62
+
63
+ .chat-message.assistant {
64
+ background-color: #f1f5f9;
65
+ color: #1e293b;
66
+ border-radius: 1rem 1rem 1rem 0;
67
+ align-self: flex-start;
68
+ }
69
+
70
+ /* Project Card Styling */
71
+ .project-card {
72
+ transition: all 0.2s ease;
73
+ }
74
+
75
+ .project-card:hover {
76
+ transform: translateY(-2px);
77
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
78
+ }
79
+
80
+ .project-card.active {
81
+ border-left: 4px solid #10b981;
82
+ }
83
+
84
+ /* Responsive Adjustments */
85
+ @media (max-width: 768px) {
86
+ .sidebar {
87
+ position: fixed;
88
+ z-index: 50;
89
+ transform: translateX(-100%);
90
+ transition: transform 0.3s ease;
91
+ }
92
+
93
+ .sidebar.open {
94
+ transform: translateX(0);
95
+ }
96
+
97
+ .sidebar-overlay {
98
+ position: fixed;
99
+ inset: 0;
100
+ background-color: rgba(0, 0, 0, 0.5);
101
+ z-index: 40;
102
+ }
103
+ }