Update index.html
Browse files- index.html +101 -127
index.html
CHANGED
@@ -5,6 +5,7 @@
|
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
<title>Speedy Chat</title>
|
7 |
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
|
|
|
8 |
<style>
|
9 |
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Arabic:wght@100;200;300;400;500;600;700&display=swap');
|
10 |
@import url('https://fonts.googleapis.com/css2?family=Noto+Kufi+Arabic:wght@100;200;300;400;500;600;700;800;900&display=swap');
|
@@ -51,95 +52,51 @@
|
|
51 |
.dark-mode .bot-message {
|
52 |
background-color: #363636;
|
53 |
}
|
54 |
-
|
55 |
-
.message-input:focus {
|
56 |
-
outline: none;
|
57 |
-
box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
|
58 |
-
}
|
59 |
|
60 |
-
.
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
text-align: center;
|
65 |
-
margin: 1.5rem 0;
|
66 |
-
letter-spacing: -0.02em;
|
67 |
}
|
68 |
|
69 |
-
.message {
|
70 |
-
|
71 |
-
|
72 |
-
|
|
|
|
|
|
|
|
|
|
|
73 |
}
|
74 |
|
75 |
-
.message
|
76 |
-
|
77 |
-
line-height: 1.7;
|
78 |
}
|
79 |
|
80 |
-
.
|
81 |
-
|
82 |
-
opacity: 0;
|
83 |
-
transform: translateY(10px);
|
84 |
-
animation: typeIn 0.1s ease forwards;
|
85 |
}
|
86 |
|
87 |
-
.
|
88 |
-
|
89 |
-
background-
|
90 |
-
|
91 |
-
|
92 |
-
|
|
|
|
|
93 |
}
|
94 |
|
95 |
-
|
96 |
-
|
97 |
-
.style-select {
|
98 |
-
width: 40px;
|
99 |
-
overflow: hidden;
|
100 |
-
white-space: nowrap;
|
101 |
-
padding-right: 0;
|
102 |
-
background-position: center;
|
103 |
-
}
|
104 |
-
|
105 |
-
.style-select option {
|
106 |
-
padding: 8px;
|
107 |
-
}
|
108 |
}
|
109 |
|
110 |
-
|
111 |
-
to {
|
112 |
-
opacity: 1;
|
113 |
-
transform: translateY(0);
|
114 |
-
}
|
115 |
-
}
|
116 |
-
|
117 |
-
@keyframes fadeIn {
|
118 |
-
to {
|
119 |
-
opacity: 1;
|
120 |
-
transform: translateY(0);
|
121 |
-
}
|
122 |
-
}
|
123 |
</style>
|
124 |
</head>
|
125 |
<body class="text-lg light-mode">
|
126 |
-
|
127 |
-
<div class="flex items-center px-4 py-2">
|
128 |
-
<div class="flex items-center flex-1">
|
129 |
-
<span class="text-2xl font-bold text-indigo-600">Speedy</span>
|
130 |
-
</div>
|
131 |
-
<button id="darkModeToggle" class="text-gray-500 hover:bg-gray-50 p-2 rounded-full transition-colors mr-2">
|
132 |
-
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
133 |
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"></path>
|
134 |
-
</svg>
|
135 |
-
</button>
|
136 |
-
<button id="clearChat" class="text-gray-500 hover:bg-gray-50 p-2 rounded-full transition-colors">
|
137 |
-
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
138 |
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
139 |
-
</svg>
|
140 |
-
</button>
|
141 |
-
</div>
|
142 |
-
</header>
|
143 |
|
144 |
<main class="pt-24 pb-24">
|
145 |
<div class="max-w-3xl mx-auto px-4">
|
@@ -163,41 +120,17 @@
|
|
163 |
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 10l7-7m0 0l7 7m-7-7v18"></path>
|
164 |
</svg>
|
165 |
</button>
|
166 |
-
<
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
</a>
|
171 |
-
<select id="styleSelect" class="style-select bg-gray-50 border border-gray-200 text-gray-600 text-sm rounded-lg pl-8 pr-2 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-200">
|
172 |
-
<option value="short">⚡ ردود قصيرة</option>
|
173 |
-
<option value="normal" selected>◯ عادي</option>
|
174 |
-
<option value="long">↔ ردود مفصلة</option>
|
175 |
-
</select>
|
176 |
</div>
|
177 |
</div>
|
178 |
</div>
|
179 |
</footer>
|
180 |
|
181 |
<script>
|
182 |
-
|
183 |
-
const messagesContainer = document.getElementById('messagesContainer');
|
184 |
-
const messageInput = document.getElementById('messageInput');
|
185 |
-
const sendButton = document.getElementById('sendMessage');
|
186 |
-
const clearButton = document.getElementById('clearChat');
|
187 |
-
const styleSelect = document.getElementById('styleSelect');
|
188 |
-
const darkModeToggle = document.getElementById('darkModeToggle');
|
189 |
-
let chatHistory = [];
|
190 |
-
let currentStyle = 'normal';
|
191 |
-
|
192 |
-
// Dark mode toggle
|
193 |
-
darkModeToggle.addEventListener('click', () => {
|
194 |
-
document.body.classList.toggle('dark-mode');
|
195 |
-
document.body.classList.toggle('light-mode');
|
196 |
-
});
|
197 |
-
|
198 |
-
styleSelect.addEventListener('change', (e) => {
|
199 |
-
currentStyle = e.target.value;
|
200 |
-
});
|
201 |
|
202 |
function createUserMessage(text) {
|
203 |
let prefix = '';
|
@@ -208,51 +141,66 @@
|
|
208 |
}
|
209 |
|
210 |
return `
|
211 |
-
<div class="message flex
|
212 |
-
<div class="
|
213 |
-
<div class="
|
214 |
-
<
|
|
|
|
|
215 |
</div>
|
216 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
217 |
</div>
|
218 |
`;
|
219 |
}
|
220 |
|
221 |
function createBotMessage(text, messageId) {
|
222 |
return `
|
223 |
-
<div class="message flex
|
224 |
-
<div class="flex
|
225 |
-
<
|
226 |
-
|
227 |
-
|
228 |
-
<div class="
|
229 |
-
<
|
|
|
|
|
230 |
</div>
|
231 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
232 |
</div>
|
233 |
`;
|
234 |
}
|
235 |
|
236 |
-
|
237 |
-
|
238 |
-
element.innerHTML = '';
|
239 |
-
const words = text.split(' ');
|
240 |
-
|
241 |
-
for (let i = 0; i < words.length; i++) {
|
242 |
-
const span = document.createElement('span');
|
243 |
-
span.textContent = words[i] + ' ';
|
244 |
-
span.className = 'typing-animation';
|
245 |
-
element.appendChild(span);
|
246 |
-
await new Promise(resolve => setTimeout(resolve, 50));
|
247 |
-
}
|
248 |
-
}
|
249 |
|
250 |
async function sendMessage() {
|
251 |
const message = messageInput.value.trim();
|
252 |
-
if (!message) return;
|
253 |
|
254 |
messageInput.value = '';
|
255 |
adjustTextareaHeight();
|
|
|
|
|
256 |
|
257 |
const messageId = 'msg-' + Date.now();
|
258 |
let actualMessage = message;
|
@@ -286,10 +234,36 @@
|
|
286 |
});
|
287 |
} catch (error) {
|
288 |
document.getElementById(messageId).textContent = 'عذراً، حدث خطأ في المعالجة.';
|
|
|
|
|
|
|
289 |
}
|
290 |
scrollToBottom();
|
291 |
}
|
292 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
293 |
function scrollToBottom() {
|
294 |
window.scrollTo({
|
295 |
top: document.documentElement.scrollHeight,
|
|
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
<title>Speedy Chat</title>
|
7 |
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
|
8 |
+
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
9 |
<style>
|
10 |
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Arabic:wght@100;200;300;400;500;600;700&display=swap');
|
11 |
@import url('https://fonts.googleapis.com/css2?family=Noto+Kufi+Arabic:wght@100;200;300;400;500;600;700;800;900&display=swap');
|
|
|
52 |
.dark-mode .bot-message {
|
53 |
background-color: #363636;
|
54 |
}
|
|
|
|
|
|
|
|
|
|
|
55 |
|
56 |
+
.message-actions {
|
57 |
+
display: flex;
|
58 |
+
gap: 0.5rem;
|
59 |
+
margin-top: 0.5rem;
|
|
|
|
|
|
|
60 |
}
|
61 |
|
62 |
+
.message-action-button {
|
63 |
+
padding: 0.25rem 0.75rem;
|
64 |
+
border-radius: 0.375rem;
|
65 |
+
font-size: 0.875rem;
|
66 |
+
display: flex;
|
67 |
+
align-items: center;
|
68 |
+
gap: 0.25rem;
|
69 |
+
transition: all 0.2s;
|
70 |
+
color: #6B7280;
|
71 |
}
|
72 |
|
73 |
+
.message-action-button:hover {
|
74 |
+
background-color: #F3F4F6;
|
|
|
75 |
}
|
76 |
|
77 |
+
.dark-mode .message-action-button:hover {
|
78 |
+
background-color: #404040;
|
|
|
|
|
|
|
79 |
}
|
80 |
|
81 |
+
.stop-generating {
|
82 |
+
display: none;
|
83 |
+
background-color: #EF4444;
|
84 |
+
color: white;
|
85 |
+
padding: 0.5rem 1rem;
|
86 |
+
border-radius: 0.375rem;
|
87 |
+
font-weight: 500;
|
88 |
+
transition: all 0.2s;
|
89 |
}
|
90 |
|
91 |
+
.stop-generating:hover {
|
92 |
+
background-color: #DC2626;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
}
|
94 |
|
95 |
+
/* ... (باقي الأنماط كما هي) ... */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
</style>
|
97 |
</head>
|
98 |
<body class="text-lg light-mode">
|
99 |
+
<!-- ... (الهيدر كما هو) ... -->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
|
101 |
<main class="pt-24 pb-24">
|
102 |
<div class="max-w-3xl mx-auto px-4">
|
|
|
120 |
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 10l7-7m0 0l7 7m-7-7v18"></path>
|
121 |
</svg>
|
122 |
</button>
|
123 |
+
<button id="stopGenerating" class="stop-generating">
|
124 |
+
إيقاف التوليد
|
125 |
+
</button>
|
126 |
+
<!-- ... (باقي الأزرار كما هي) ... -->
|
|
|
|
|
|
|
|
|
|
|
|
|
127 |
</div>
|
128 |
</div>
|
129 |
</div>
|
130 |
</footer>
|
131 |
|
132 |
<script>
|
133 |
+
// ... (التعريفات الأساسية كما هي) ...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
134 |
|
135 |
function createUserMessage(text) {
|
136 |
let prefix = '';
|
|
|
141 |
}
|
142 |
|
143 |
return `
|
144 |
+
<div class="message flex flex-col">
|
145 |
+
<div class="flex justify-end">
|
146 |
+
<div class="max-w-[80%]">
|
147 |
+
<div class="bg-indigo-500 text-white rounded-lg p-4 shadow-sm">
|
148 |
+
<p class="text-lg">${text}</p>
|
149 |
+
</div>
|
150 |
</div>
|
151 |
</div>
|
152 |
+
<div class="message-actions justify-end">
|
153 |
+
<button class="message-action-button">
|
154 |
+
<i class="far fa-thumbs-up"></i>
|
155 |
+
أعجبني
|
156 |
+
</button>
|
157 |
+
<button class="message-action-button">
|
158 |
+
<i class="far fa-thumbs-down"></i>
|
159 |
+
لم يعجبني
|
160 |
+
</button>
|
161 |
+
</div>
|
162 |
</div>
|
163 |
`;
|
164 |
}
|
165 |
|
166 |
function createBotMessage(text, messageId) {
|
167 |
return `
|
168 |
+
<div class="message flex flex-col">
|
169 |
+
<div class="flex justify-start">
|
170 |
+
<div class="flex-shrink-0 w-10 h-10 rounded-full overflow-hidden shadow-sm mt-1">
|
171 |
+
<img src="https://ufastpro.com/wp-content/uploads/2024/12/3.png" alt="Bot Avatar" class="w-full h-full object-cover">
|
172 |
+
</div>
|
173 |
+
<div class="max-w-[80%] mr-3">
|
174 |
+
<div class="bot-message bg-white rounded-lg p-4 shadow-sm">
|
175 |
+
<p id="${messageId}" class="text-gray-700"></p>
|
176 |
+
</div>
|
177 |
</div>
|
178 |
</div>
|
179 |
+
<div class="message-actions mr-13">
|
180 |
+
<button class="message-action-button copy-message">
|
181 |
+
<i class="far fa-copy"></i>
|
182 |
+
نسخ
|
183 |
+
</button>
|
184 |
+
<button class="message-action-button regenerate">
|
185 |
+
<i class="fas fa-redo"></i>
|
186 |
+
إعادة التوليد
|
187 |
+
</button>
|
188 |
+
</div>
|
189 |
</div>
|
190 |
`;
|
191 |
}
|
192 |
|
193 |
+
let isGenerating = false;
|
194 |
+
const stopGenerating = document.getElementById('stopGenerating');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
195 |
|
196 |
async function sendMessage() {
|
197 |
const message = messageInput.value.trim();
|
198 |
+
if (!message || isGenerating) return;
|
199 |
|
200 |
messageInput.value = '';
|
201 |
adjustTextareaHeight();
|
202 |
+
isGenerating = true;
|
203 |
+
stopGenerating.style.display = 'block';
|
204 |
|
205 |
const messageId = 'msg-' + Date.now();
|
206 |
let actualMessage = message;
|
|
|
234 |
});
|
235 |
} catch (error) {
|
236 |
document.getElementById(messageId).textContent = 'عذراً، حدث خطأ في المعالجة.';
|
237 |
+
} finally {
|
238 |
+
isGenerating = false;
|
239 |
+
stopGenerating.style.display = 'none';
|
240 |
}
|
241 |
scrollToBottom();
|
242 |
}
|
243 |
|
244 |
+
// إضافة مستمعي الأحداث للأزرار الجديدة
|
245 |
+
document.addEventListener('click', function(e) {
|
246 |
+
if (e.target.closest('.copy-message')) {
|
247 |
+
const messageText = e.target.closest('.message').querySelector('.bot-message p').textContent;
|
248 |
+
navigator.clipboard.writeText(messageText);
|
249 |
+
// يمكن إضافة إشعار هنا للتأكيد على النسخ
|
250 |
+
}
|
251 |
+
|
252 |
+
if (e.target.closest('.regenerate')) {
|
253 |
+
const message = chatHistory[chatHistory.length - 1].human;
|
254 |
+
messageInput.value = message;
|
255 |
+
sendMessage();
|
256 |
+
}
|
257 |
+
});
|
258 |
+
|
259 |
+
stopGenerating.addEventListener('click', () => {
|
260 |
+
isGenerating = false;
|
261 |
+
stopGenerating.style.display = 'none';
|
262 |
+
// هنا يمكن إضافة منطق لإيقاف التوليد الفعلي
|
263 |
+
});
|
264 |
+
|
265 |
+
// ... (باقي الكود كما هو) ...
|
266 |
+
|
267 |
function scrollToBottom() {
|
268 |
window.scrollTo({
|
269 |
top: document.documentElement.scrollHeight,
|