humanvprojectceo commited on
Commit
20b03c2
·
verified ·
1 Parent(s): 0e14eed

Update cafe.html

Browse files
Files changed (1) hide show
  1. cafe.html +786 -298
cafe.html CHANGED
@@ -3,122 +3,561 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6
- <title>Cafe AI - پنل مدیریت</title>
 
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
- <link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;700;800&display=swap" rel="stylesheet">
 
10
  <script src="https://cdn.tailwindcss.com"></script>
11
- <!-- Markdown parser -->
12
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
 
13
  <script>
14
  tailwind.config = {
15
  theme: {
16
  extend: {
17
  fontFamily: {
18
  sans: ['Vazirmatn', 'sans-serif'],
 
19
  },
20
  colors: {
21
- tabriz: {
22
- 900: '#0a1628',
23
- 800: '#0f1f38',
24
- 700: '#152b48',
25
- 600: '#1c3a5e',
26
- 500: '#254a75',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  },
28
- turquoise: {
29
- DEFAULT: '#0891b2',
30
- light: '#22d3ee',
31
- glow: '#67e8f9',
 
32
  },
33
- gold: {
34
- DEFAULT: '#d4af37',
35
- light: '#f0d060',
36
- dark: '#b8960f',
 
 
 
 
 
 
 
37
  },
38
- brass: '#c5a880',
39
- emeraldMuted: '#10b981',
40
  },
41
  boxShadow: {
42
- 'turquoise-glow': '0 0 30px rgba(8, 145, 178, 0.2)',
43
- 'gold-glow': '0 0 30px rgba(212, 175, 55, 0.25)',
44
- 'inner-soft': 'inset 0 2px 6px rgba(0,0,0,0.3)',
 
 
 
 
 
 
 
 
45
  },
46
- backgroundImage: {
47
- 'persian-geo': "url(\"data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M30 0L60 30L30 60L0 30Z' fill='none' stroke='%230891b2' stroke-width='0.4' opacity='0.08'/%3E%3Ccircle cx='30' cy='30' r='10' fill='none' stroke='%23d4af37' stroke-width='0.4' opacity='0.06'/%3E%3Cpath d='M30 10L40 30L30 50L20 30Z' fill='none' stroke='%23d4af37' stroke-width='0.3' opacity='0.05'/%3E%3C/svg%3E\")",
 
 
 
 
 
 
 
 
 
 
 
48
  },
49
  }
50
  }
51
  }
52
  </script>
 
53
  <style>
 
 
 
 
 
 
54
  body {
55
- background-color: #0a1628;
56
- color: #e2e8f0;
57
  -webkit-tap-highlight-color: transparent;
 
58
  }
59
- ::-webkit-scrollbar {
60
- width: 5px;
61
- height: 5px;
 
62
  }
63
- ::-webkit-scrollbar-track {
64
- background: #0a1628;
 
65
  }
 
 
 
 
 
 
 
 
 
66
  ::-webkit-scrollbar-thumb {
67
- background: #254a75;
68
  border-radius: 4px;
69
  }
 
 
70
  .glass-card {
71
- background: rgba(15, 31, 56, 0.65);
72
- backdrop-filter: blur(16px);
73
- border: 1px solid rgba(8, 145, 178, 0.12);
74
- box-shadow: 0 10px 30px -10px rgba(0,0,0,0.5);
 
 
 
 
75
  }
76
  .glass-card:hover {
77
- border-color: rgba(212, 175, 55, 0.25);
78
- box-shadow: 0 10px 40px -8px rgba(212, 175, 55, 0.15);
79
- }
80
- /* Markdown rendered content styles */
81
- .chat-markdown p { margin-bottom: 0.3em; }
82
- .chat-markdown ul { list-style-type: disc; padding-right: 1.2em; margin: 0.2em 0; }
83
- .chat-markdown ol { list-style-type: decimal; padding-right: 1.2em; margin: 0.2em 0; }
84
- .chat-markdown li { margin-bottom: 0.1em; }
85
- .chat-markdown strong { color: #f0d060; }
86
- .chat-markdown em { color: #22d3ee; }
87
- .chat-markdown code { background: rgba(8,145,178,0.15); padding: 0.1em 0.3em; border-radius: 4px; font-size: 0.9em; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  </style>
89
  </head>
90
- <body class="min-h-screen flex flex-col font-sans selection:bg-gold selection:text-black overflow-x-hidden bg-gradient-to-br from-tabriz-900 via-[#0c1426] to-[#0d1729] antialiased bg-persian-geo bg-repeat">
91
 
92
- <!-- Ambient light orbs (desktop) -->
93
- <div class="hidden lg:block absolute inset-0 overflow-hidden pointer-events-none z-0">
94
- <div class="absolute -top-1/4 -right-1/4 w-[700px] h-[700px] rounded-full bg-turquoise/5 blur-[160px]"></div>
95
- <div class="absolute -bottom-1/4 -left-1/4 w-[700px] h-[700px] rounded-full bg-gold/5 blur-[160px]"></div>
 
 
 
96
  </div>
97
 
98
  <!-- Header -->
99
- <header class="border-b border-tabriz-700/40 bg-tabriz-800/50 backdrop-blur-xl sticky top-0 z-50 px-4 py-3 md:px-8 shadow-lg">
100
- <div class="max-w-7xl mx-auto flex items-center justify-between">
101
  <div class="flex items-center gap-3">
102
- <div class="w-10 h-10 rounded-xl bg-gradient-to-br from-turquoise/20 to-gold/10 border border-turquoise/20 flex items-center justify-center shadow-turquoise-glow">
103
- <svg class="w-6 h-6 text-gold" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
104
- <path d="M17 8h1a4 4 0 1 1 0 8h-1" />
105
- <path d="M3 8h14v9a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4Z" />
106
- <line x1="6" y1="2" x2="6" y2="4" />
107
- <line x1="10" y1="2" x2="10" y2="4" />
108
- <line x1="14" y1="2" x2="14" y2="4" />
109
- </svg>
 
 
110
  </div>
111
  <div>
112
- <h1 class="text-sm font-extrabold text-white flex items-center gap-2">
113
- پنل مدیریت <span class="text-gold">Cafe AI</span>
 
 
114
  </h1>
115
- <p class="text-[10px] text-turquoise/70 font-medium">پایش برخط سفارشات و منوی هوشمند</p>
116
  </div>
117
  </div>
118
-
119
- <div class="flex items-center gap-3">
120
- <span class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-[10px] font-bold bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">
121
- <span class="w-1.5 h-1.5 rounded-full bg-emerald-400 animate-pulse"></span>
122
  نظارت زنده
123
  </span>
124
  </div>
@@ -127,189 +566,228 @@
127
 
128
  <!-- Main grid -->
129
  <main class="flex-1 max-w-7xl w-full mx-auto p-4 md:p-6 lg:p-8 grid grid-cols-1 lg:grid-cols-12 gap-6 z-10 relative">
130
-
131
  <!-- Right column: orders + current menu + menu upload (7/12) -->
132
  <section class="lg:col-span-7 flex flex-col gap-6">
133
-
134
- <!-- Live orders monitor -->
135
- <div class="glass-card rounded-3xl p-5 md:p-6 shadow-xl">
136
- <div class="flex items-center justify-between mb-4 border-b border-tabriz-700/40 pb-3">
137
- <div class="flex items-center gap-3">
138
- <div class="w-3 h-3 rounded-full bg-gold animate-pulse shadow-gold-glow"></div>
139
- <h2 class="text-sm md:text-base font-extrabold text-white flex items-center gap-2">
140
- <svg class="w-5 h-5 text-turquoise" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
141
- <path stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4" />
142
- </svg>
143
- سفارشات جدید آشپزخانه
144
- </h2>
145
- </div>
146
- <button onclick="fetchActiveOrders()" class="text-[10px] text-turquoise/70 hover:text-gold flex items-center gap-1.5 transition-all duration-300 bg-tabriz-800/30 hover:bg-tabriz-700/40 px-3 py-1.5 rounded-xl">
147
- <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
148
- <path stroke-linecap="round" stroke-linejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 1121.21 15H15" />
149
- </svg>
150
- بروزرسانی
151
- </button>
152
- </div>
153
- <div id="ordersContainer" class="space-y-4 max-h-[350px] overflow-y-auto pr-1">
154
- <div class="text-center py-12 text-xs text-turquoise/60">در حال بارگذاری لیست سفارشات جاری...</div>
155
- </div>
156
- </div>
157
 
158
- <!-- Current Menu (NEW) -->
159
- <div class="glass-card rounded-3xl p-5 md:p-6 space-y-4 shadow-xl">
160
- <div class="flex items-center justify-between border-b border-tabriz-700/40 pb-3">
161
- <h2 class="text-sm md:text-base font-extrabold text-white flex items-center gap-2">
162
- <svg class="w-5 h-5 text-gold" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
163
- <path stroke-linecap="round" stroke-linejoin="round" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4" />
164
- </svg>
165
- مدیریت منوی فعال
166
- </h2>
167
- <div class="flex gap-2">
168
- <button onclick="fetchCurrentMenu()" class="text-[10px] text-turquoise/70 hover:text-gold flex items-center gap-1 transition-all bg-tabriz-800/30 hover:bg-tabriz-700/40 px-3 py-1.5 rounded-xl">
 
 
 
 
 
 
 
 
 
169
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
170
- <path stroke-linecap="round" stroke-linejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 1121.21 15H15" />
171
  </svg>
172
- بازنشانی
173
- </button>
174
- <button onclick="addMenuItemRow()" class="px-4 py-1.5 bg-gradient-to-r from-turquoise to-cyan-600 hover:from-cyan-500 hover:to-turquoise rounded-xl text-[10px] font-extrabold text-white transition-all flex items-center gap-1 shadow-turquoise-glow">
175
- <span>+ افزودن دستی</span>
176
  </button>
177
  </div>
178
- </div>
179
- <p class="text-[11px] text-turquoise/70 leading-relaxed">
180
- لیست تمام اقلام منوی کافه. می‌توانید هر آیتم را ویرایش، حذف یا آیتم جدید اضافه کنید. تغییرات بلافاصله روی سامانه مشتریان اعمال می‌شود.
181
- </p>
182
- <div class="overflow-x-auto max-h-[400px] border border-tabriz-700/40 rounded-2xl bg-tabriz-900/30">
183
- <table class="min-w-full divide-y divide-tabriz-700/40 text-[11px]" id="currentMenuTable">
184
- <thead class="bg-tabriz-800/50 sticky top-0">
185
- <tr>
186
- <th class="px-3 py-2.5 text-right font-medium text-turquoise/90">نام محصول</th>
187
- <th class="px-3 py-2.5 text-right font-medium text-turquoise/90 hidden md:table-cell">توضیحات</th>
188
- <th class="px-3 py-2.5 text-right font-medium text-turquoise/90 w-20">قیمت</th>
189
- <th class="px-3 py-2.5 text-center font-medium text-turquoise/90 w-16">موجود</th>
190
- <th class="px-3 py-2.5 text-center font-medium text-turquoise/90 w-20">عملیات</th>
191
- </tr>
192
- </thead>
193
- <tbody id="menuTableBody" class="divide-y divide-tabriz-700/30">
194
- <!-- filled by JS -->
195
- </tbody>
196
- </table>
197
  </div>
198
  </div>
199
 
200
- <!-- Menu extraction & upload (existing) -->
201
- <div class="glass-card rounded-3xl p-5 md:p-6 space-y-4 shadow-xl">
202
- <h2 class="text-sm md:text-base font-extrabold text-white flex items-center gap-2 border-b border-tabriz-700/40 pb-3">
203
- <svg class="w-5 h-5 text-gold" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
204
- <path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
205
- </svg>
206
- استخراج خودکار ساختار منو با هوش مصنوعی
207
- </h2>
208
- <p class="text-[11px] text-turquoise/70 leading-relaxed">
209
- تصویر منو یا فاکتور جدید کافه را بارگذاری کنید. هوش مصنوعی نیلا متون و قیمت‌ها را استخراج کرده و جهت تایید نهایی برای شما ساختاربندی می‌کند.
210
- </p>
211
- <!-- Drag & drop zone -->
212
- <div id="dropZone"
213
- class="border-2 border-dashed border-tabriz-600/50 hover:border-gold/60 rounded-2xl p-6 md:p-8 text-center cursor-pointer transition-all bg-tabriz-900/40 hover:bg-tabriz-800/30 group"
214
- onclick="document.getElementById('menuFileInput').click()"
215
- ondragover="handleDragOver(event)"
216
- ondragleave="handleDragLeave(event)"
217
- ondrop="handleDrop(event)">
218
- <input type="file" id="menuFileInput" class="hidden" accept="image/*,application/pdf" onchange="uploadMenuFile(event)">
219
- <div class="flex flex-col items-center gap-3">
220
- <svg id="uploadIcon" class="w-10 h-10 text-turquoise/60 group-hover:text-gold transition-all duration-300" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
221
- <path stroke-linecap="round" stroke-linejoin="round" d="M9 13h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z" />
222
- </svg>
223
- <span class="text-xs md:text-sm text-white font-medium">فایل یا تصویر منو را به این بخش بکشید یا انتخاب کنید</span>
224
- <span class="text-[9px] text-turquoise/50 uppercase tracking-wider">فرمت‌های تصویری یا PDF</span>
 
 
225
  </div>
226
- </div>
227
- <div id="uploadLoader" class="hidden text-center py-6 bg-tabriz-900/60 rounded-2xl border border-turquoise/20 animate-pulse">
228
- <div class="inline-block animate-spin rounded-full h-7 w-7 border-t-2 border-b-2 border-gold mb-2"></div>
229
- <p class="text-[10px] text-gold font-extrabold">نیلا در حال ساختارسازی و آنالیز متون منوی جدید است...</p>
230
- </div>
231
- <div id="menuEditorContainer" class="hidden space-y-4 border-t border-tabriz-700/30 pt-4">
232
- <h3 class="text-xs font-bold text-gold flex items-center gap-1.5">
233
- <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
234
- <path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
235
- </svg>
236
- بازبینی اقلام منو پیش از انتشار زنده
237
- </h3>
238
- <div class="overflow-x-auto max-h-[250px] border border-tabriz-700/40 rounded-2xl bg-tabriz-900/30">
239
- <table class="min-w-full divide-y divide-tabriz-700/40 text-[11px]">
240
- <thead class="bg-tabriz-800/50">
241
  <tr>
242
- <th class="px-3 py-2.5 text-right font-medium text-turquoise/90">عنوان محصول</th>
243
- <th class="px-3 py-2.5 text-right font-medium text-turquoise/90">توضیحات کوتاه</th>
244
- <th class="px-3 py-2.5 text-right font-medium text-turquoise/90 w-24">قیمت (تومان)</th>
245
- <th class="px-3 py-2.5 text-center font-medium text-turquoise/90 w-16">عملیات</th>
 
246
  </tr>
247
  </thead>
248
- <tbody id="menuEditorTableBody" class="divide-y divide-tabriz-700/30">
249
- <!-- dynamic rows -->
250
  </tbody>
251
  </table>
252
  </div>
253
- <div class="flex justify-end gap-2">
254
- <button onclick="addEmptyMenuRow()" class="px-4 py-2 border border-turquoise/30 hover:border-gold/50 rounded-xl text-[10px] text-turquoise hover:text-gold transition-all duration-300 bg-tabriz-800/40">افزودن دستی محصول جدید</button>
255
- <button onclick="saveAndPublishMenu()" class="px-5 py-2.5 bg-gradient-to-r from-turquoise to-cyan-600 hover:from-cyan-500 hover:to-turquoise rounded-xl text-[11px] font-extrabold text-white transition-all duration-300 flex items-center gap-2 shadow-turquoise-glow">ثبت و همگام‌سازی زنده منو</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
256
  </div>
257
  </div>
258
  </div>
259
  </section>
260
 
261
  <!-- Left column: Admin chat assistant (5/12) -->
262
- <section class="lg:col-span-5 flex flex-col glass-card rounded-3xl h-[630px] overflow-hidden shadow-xl">
263
- <div class="px-5 py-4 border-b border-tabriz-700/40 flex items-center justify-between bg-tabriz-900/40">
 
 
264
  <div class="flex items-center gap-3">
265
- <div class="w-10 h-10 rounded-xl bg-turquoise/10 border border-turquoise/20 flex items-center justify-center shadow-turquoise-glow">
266
- <svg class="w-5 h-5 text-gold" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
267
  <path d="M12 2a10 10 0 0 1 10 10c0 5.523-4.477 10-10 10S2 17.523 2 12A10 10 0 0 1 12 2z"/>
268
- <path d="M12 8v4l3 3"/>
269
  </svg>
270
  </div>
271
  <div>
272
- <h3 class="text-xs font-extrabold text-white">دستیار هوشمند ادمین</h3>
273
- <p class="text-[9px] text-turquoise/70 font-medium">کنترل همگام موجودی و منو با زبان طبیعی</p>
 
 
 
274
  </div>
275
  </div>
276
  </div>
277
 
278
- <div id="chatMessages" class="flex-1 overflow-y-auto p-4 space-y-4">
279
  <div class="flex gap-2.5 max-w-[85%]">
280
- <div class="w-8 h-8 rounded-xl bg-turquoise/15 border border-turquoise/20 flex items-center justify-center flex-shrink-0">
281
- <span class="text-gold font-extrabold text-[10px] font-mono">AI</span>
282
  </div>
283
- <div class="bg-tabriz-900/60 border border-tabriz-700/30 text-zinc-200 text-xs rounded-2xl rounded-tr-none px-3.5 py-2.5 leading-relaxed shadow-inner-soft chat-markdown">
284
- سلام همکار گرامی! من نیلا هستم، دستیار مدیریت منوی Cafe AI. شما می‌توانید از همین‌جا اقلام منو را با گفتگوی ساده کنترل کنید؛ برای مثال بنویسید: "کروسان ساده تمام شد" یا "چای ماسالا را موجود کن" تا سریعاً تغییرات روی سیستم مشتریان نیز اعمال گردد.
285
  </div>
286
  </div>
287
  </div>
288
 
289
- <div id="chatLoader" class="hidden px-4 py-2.5 flex items-center justify-between bg-tabriz-800/60 text-[9px] text-turquoise/80 font-extrabold border-t border-tabriz-700/40">
290
- <div class="flex items-center gap-2">
291
- <div class="flex space-x-1 space-x-reverse">
292
- <span class="w-1.5 h-1.5 bg-gold rounded-full animate-bounce" style="animation-delay: 0.1s"></span>
293
- <span class="w-1.5 h-1.5 bg-gold rounded-full animate-bounce" style="animation-delay: 0.2s"></span>
294
- <span class="w-1.5 h-1.5 bg-gold rounded-full animate-bounce" style="animation-delay: 0.3s"></span>
295
  </div>
296
- <span>نیلا در حال پردازش و اعمال دستور مدیریت...</span>
297
  </div>
298
- <button onclick="stopAdminChat()" class="px-2.5 py-1.5 bg-rose-950/10 border border-rose-900/30 hover:bg-rose-900/40 rounded-lg text-[9px] text-rose-400 font-bold transition-all">توقف فرآیند</button>
 
 
299
  </div>
300
 
301
- <form id="chatForm" onsubmit="sendAdminMessage(event)" class="p-3 border-t border-tabriz-700/40 bg-tabriz-900/40 flex gap-2">
302
- <input type="text" id="chatInput" placeholder="تغییر وضعیت یا ویرایش منو را به صورت متنی بنویسید..." autocomplete="off" class="flex-1 bg-tabriz-800/70 border border-tabriz-600/40 text-xs text-white placeholder-turquoise/40 rounded-lg px-3.5 py-2.5 focus:outline-none focus:border-gold/50 transition-all duration-300">
303
- <button type="submit" id="sendBtn" class="bg-gradient-to-br from-gold to-amber-600 hover:from-amber-400 hover:to-gold text-tabriz-900 font-extrabold px-4 py-2.5 rounded-lg text-xs transition-all duration-300 flex items-center justify-center flex-shrink-0 shadow-gold-glow">
304
- <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
305
- <path stroke-linecap="round" stroke-linejoin="round" d="M14 5l7 7m0 0l-7 7m7-7H3" />
 
306
  </svg>
307
  </button>
308
  </form>
309
  </section>
310
  </main>
311
 
312
- <footer class="border-t border-tabriz-700/30 py-4 text-center text-[10px] text-turquoise/50 bg-tabriz-900/80 backdrop-blur">
313
  طراحی و توسعه توسط الگوریتم داده نسترن | با الهام از فرهنگ تبریز © ۲۰۲۶
314
  </footer>
315
 
@@ -318,7 +796,7 @@
318
  marked.setOptions({ sanitize: true, breaks: true });
319
 
320
  let chatHistory = [
321
- { role: 'model', content: 'سلام همکار گرامی! من نیلا هستم، دستیار مدیریت منوی Cafe AI. شما می‌توانید از همین‌جا اقلام منو را با گفتگوی ساده کنترل کنید؛ برای مثال بنویسید: "کروسان ساده تمام شد" یا "چای ماسالا را موجود کن" تا سریعاً تغییرات روی سیستم مشتریان نیز اعمال گردد.' }
322
  ];
323
  let abortController = null;
324
  let isGenerating = false;
@@ -329,7 +807,7 @@
329
  setInterval(fetchActiveOrders, 10000);
330
  });
331
 
332
- // ==================== Order functions (unchanged) ====================
333
  async function fetchActiveOrders() {
334
  const container = document.getElementById('ordersContainer');
335
  try {
@@ -338,11 +816,12 @@
338
  if (response.ok) {
339
  if (orders.length === 0) {
340
  container.innerHTML = `
341
- <div class="text-center py-16 text-turquoise/60 border border-dashed border-tabriz-600/50 rounded-2xl bg-tabriz-900/20">
342
- <svg class="w-8 h-8 text-turquoise/40 mx-auto mb-2" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
343
- <path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
344
  </svg>
345
- در حال حاضر سفارش معلق و فعالی در صف آشپزخانه نیست.
 
346
  </div>
347
  `;
348
  return;
@@ -352,27 +831,42 @@
352
  let itemsHtml = '';
353
  order.items.forEach(item => {
354
  itemsHtml += `
355
- <div class="flex items-center justify-between text-[11px] bg-tabriz-900/60 px-3 py-2 rounded-lg border border-tabriz-700/30">
356
- <span class="text-zinc-300 font-bold">${item.name}</span>
357
- <span class="text-gold bg-gold/10 px-2 py-0.5 rounded-md font-extrabold text-[10px]">تعداد: ${item.quantity}</span>
 
 
 
 
 
358
  </div>
359
  `;
360
  });
361
  const timeString = new Date(order.timestamp * 1000).toLocaleTimeString('fa-IR', { hour: '2-digit', minute: '2-digit' });
362
  const cardHtml = `
363
- <div class="border border-tabriz-700/30 hover:border-gold/30 rounded-2xl p-4 bg-tabriz-900/30 transition-all duration-300 flex flex-col md:flex-row justify-between items-start md:items-center gap-3">
364
  <div class="flex-1 space-y-2 w-full">
365
- <div class="flex items-center justify-between md:justify-start gap-3 w-full">
366
- <span class="text-xs font-bold text-white bg-turquoise/10 border border-turquoise/20 px-2.5 py-1 rounded-lg">میز شماره ${order.table}</span>
367
- <span class="text-[9px] text-turquoise/60 font-medium">زمان ثبت: ${timeString}</span>
 
 
 
 
 
 
 
 
 
 
368
  </div>
369
  <div class="grid grid-cols-1 sm:grid-cols-2 gap-1.5 mt-2">
370
  ${itemsHtml}
371
  </div>
372
  </div>
373
- <button onclick="completeOrder(${order.id})" class="w-full md:w-auto px-4 py-2.5 bg-tabriz-800/60 hover:bg-emerald-700 text-zinc-200 hover:text-white rounded-lg text-[10px] font-bold transition-all flex items-center justify-center gap-1.5 border border-tabriz-600/40 hover:border-emerald-600 flex-shrink-0 group">
374
- <svg class="w-3.5 h-3.5 text-zinc-400 group-hover:text-white transition-colors" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
375
- <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
376
  </svg>
377
  تحویل نهایی شد
378
  </button>
@@ -381,10 +875,10 @@
381
  container.insertAdjacentHTML('beforeend', cardHtml);
382
  });
383
  } else {
384
- container.innerHTML = `<div class="text-center py-6 text-rose-500 text-xs">خطا در دریافت لیست سفارشات آشپزخانه.</div>`;
385
  }
386
  } catch (err) {
387
- container.innerHTML = `<div class="text-center py-6 text-rose-500 text-xs">عدم برقراری ارتباط زنده با سرور: ${err.message}</div>`;
388
  }
389
  }
390
 
@@ -406,20 +900,20 @@
406
  }
407
  }
408
 
409
- // ==================== Menu CRUD (NEW) ====================
410
  async function fetchCurrentMenu() {
411
  const tbody = document.getElementById('menuTableBody');
412
- tbody.innerHTML = '<tr><td colspan="5" class="text-center py-8 text-turquoise/60">در حال بارگذاری منو...</td></tr>';
413
  try {
414
  const res = await fetch('/api/admin/menu');
415
  const menu = await res.json();
416
  if (res.ok && Array.isArray(menu)) {
417
  renderMenuTable(menu);
418
  } else {
419
- tbody.innerHTML = '<tr><td colspan="5" class="text-center py-8 text-rose-400">خطا در بارگذاری منو</td></tr>';
420
  }
421
  } catch (e) {
422
- tbody.innerHTML = '<tr><td colspan="5" class="text-center py-8 text-rose-400">عدم اتصال به سرور</td></tr>';
423
  }
424
  }
425
 
@@ -427,46 +921,48 @@
427
  const tbody = document.getElementById('menuTableBody');
428
  tbody.innerHTML = '';
429
  if (menu.length === 0) {
430
- tbody.innerHTML = '<tr><td colspan="5" class="text-center py-8 text-turquoise/60">منو خالی است. آیتم جدید اضافه کنید.</td></tr>';
431
  return;
432
  }
433
  menu.forEach(item => {
434
  const row = document.createElement('tr');
435
- row.className = 'hover:bg-tabriz-800/40 transition-colors menu-row';
436
  row.dataset.id = item.id;
437
  row.innerHTML = `
438
- <td class="px-2 py-1.5">
439
- <span class="view-mode font-bold text-white">${escapeHtml(item.name)}</span>
440
- <input type="text" class="edit-mode hidden w-full bg-tabriz-800/60 border border-tabriz-600/40 rounded px-2 py-1 text-white text-[11px]" value="${escapeHtml(item.name)}" data-field="name">
441
  </td>
442
- <td class="px-2 py-1.5 hidden md:table-cell">
443
- <span class="view-mode text-zinc-400 text-[10px]">${escapeHtml(item.description || '-')}</span>
444
- <input type="text" class="edit-mode hidden w-full bg-tabriz-800/60 border border-tabriz-600/40 rounded px-2 py-1 text-white text-[11px]" value="${escapeHtml(item.description || '')}" data-field="description">
445
  </td>
446
- <td class="px-2 py-1.5">
447
- <span class="view-mode text-gold font-medium">${escapeHtml(item.price || '-')}</span>
448
- <input type="text" class="edit-mode hidden w-full bg-tabriz-800/60 border border-tabriz-600/40 rounded px-2 py-1 text-white text-[11px]" value="${escapeHtml(item.price || '')}" data-field="price">
449
  </td>
450
- <td class="px-2 py-1.5 text-center">
451
- <span class="view-mode text-xs ${item.available ? 'text-emerald-400' : 'text-rose-400'}">${item.available ? 'بله' : 'خیر'}</span>
452
- <input type="checkbox" class="edit-mode hidden" data-field="available" ${item.available ? 'checked' : ''}>
 
 
453
  </td>
454
- <td class="px-2 py-1.5 text-center">
455
  <div class="view-mode flex gap-1 justify-center">
456
- <button onclick="editMenuItem(this)" class="p-1 text-turquoise/70 hover:text-gold transition-colors" title="ویرایش">
457
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
458
- <path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
459
  </svg>
460
  </button>
461
- <button onclick="deleteMenuItem(${item.id})" class="p-1 text-zinc-600 hover:text-rose-500 transition-colors" title="حذف">
462
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
463
- <path stroke-linecap="round" stroke-linejoin="round" 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" />
464
  </svg>
465
  </button>
466
  </div>
467
  <div class="edit-mode hidden flex gap-1 justify-center">
468
- <button onclick="saveMenuItem(this, ${item.id})" class="px-2 py-1 bg-emerald-500/20 border border-emerald-500/40 text-emerald-300 rounded text-[10px]">ذخیره</button>
469
- <button onclick="cancelEdit(this)" class="px-2 py-1 bg-zinc-800 border border-zinc-600 text-zinc-400 rounded text-[10px]">لغو</button>
470
  </div>
471
  </td>
472
  `;
@@ -491,9 +987,6 @@
491
  }
492
 
493
  function cancelEdit(btn) {
494
- const row = btn.closest('tr');
495
- // Reset fields to original (re-fetch from data attributes? we can just store original values in dataset)
496
- // Simple: reload menu
497
  fetchCurrentMenu();
498
  }
499
 
@@ -546,26 +1039,25 @@
546
  }
547
  }
548
 
549
- async function addMenuItemRow() {
550
- // Create a new empty row with inputs and a save button
551
  const tbody = document.getElementById('menuTableBody');
552
  const row = document.createElement('tr');
553
- row.className = 'bg-tabriz-800/40';
554
  row.innerHTML = `
555
- <td class="px-2 py-1.5">
556
- <input type="text" class="w-full bg-tabriz-800/60 border border-turquoise/40 rounded px-2 py-1 text-white text-[11px]" placeholder="نام محصول" data-field="name">
557
  </td>
558
- <td class="px-2 py-1.5 hidden md:table-cell">
559
- <input type="text" class="w-full bg-tabriz-800/60 border border-tabriz-600/40 rounded px-2 py-1 text-white text-[11px]" placeholder="توضیحات" data-field="description">
560
  </td>
561
- <td class="px-2 py-1.5">
562
- <input type="text" class="w-full bg-tabriz-800/60 border border-tabriz-600/40 rounded px-2 py-1 text-white text-[11px]" placeholder="قیمت" data-field="price">
563
  </td>
564
- <td class="px-2 py-1.5 text-center">
565
  <input type="checkbox" data-field="available" checked>
566
  </td>
567
- <td class="px-2 py-1.5 text-center">
568
- <button onclick="saveNewItem(this)" class="px-3 py-1 bg-emerald-500/20 border border-emerald-500/40 text-emerald-300 rounded text-[10px]">افزودن</button>
569
  </td>
570
  `;
571
  tbody.appendChild(row);
@@ -598,20 +1090,16 @@
598
  }
599
  }
600
 
601
- // ==================== Menu extraction (unchanged) ====================
602
  function handleDragOver(e) {
603
  e.preventDefault();
604
  const dropZone = document.getElementById('dropZone');
605
- const icon = document.getElementById('uploadIcon');
606
- dropZone.classList.add('border-gold', 'bg-gold/5');
607
- icon.classList.add('text-gold');
608
  }
609
  function handleDragLeave(e) {
610
  e.preventDefault();
611
  const dropZone = document.getElementById('dropZone');
612
- const icon = document.getElementById('uploadIcon');
613
- dropZone.classList.remove('border-gold', 'bg-gold/5');
614
- icon.classList.remove('text-gold');
615
  }
616
  function handleDrop(e) {
617
  e.preventDefault();
@@ -656,20 +1144,20 @@
656
  tbody.innerHTML = '';
657
  menuItems.forEach((item, index) => {
658
  const row = `
659
- <tr class="hover:bg-tabriz-800/40 transition-colors duration-200">
660
  <td class="px-2 py-2">
661
- <input type="text" class="menu-name w-full bg-tabriz-800/60 border border-tabriz-600/40 rounded-lg px-2.5 py-1.5 text-white focus:border-gold/50 focus:outline-none text-[11px]" value="${item.name || ''}">
662
  </td>
663
  <td class="px-2 py-2">
664
- <input type="text" class="menu-desc w-full bg-tabriz-800/60 border border-tabriz-600/40 rounded-lg px-2.5 py-1.5 text-white focus:border-gold/50 focus:outline-none text-[11px]" value="${item.description || ''}">
665
  </td>
666
  <td class="px-2 py-2">
667
- <input type="text" class="menu-price w-full bg-tabriz-800/60 border border-tabriz-600/40 rounded-lg px-2.5 py-1.5 text-white focus:border-gold/50 focus:outline-none text-[11px]" value="${item.price || ''}">
668
  </td>
669
  <td class="px-2 py-2 text-center">
670
- <button onclick="removeMenuRow(this)" class="p-1 text-zinc-600 hover:text-rose-500 transition-colors">
671
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
672
- <path stroke-linecap="round" stroke-linejoin="round" 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" />
673
  </svg>
674
  </button>
675
  </td>
@@ -681,20 +1169,20 @@
681
  function addEmptyMenuRow() {
682
  const tbody = document.getElementById('menuEditorTableBody');
683
  const row = `
684
- <tr class="hover:bg-tabriz-800/40 transition-colors duration-200">
685
  <td class="px-2 py-2">
686
- <input type="text" class="menu-name w-full bg-tabriz-800/60 border border-tabriz-600/40 rounded-lg px-2.5 py-1.5 text-white focus:border-gold/50 focus:outline-none text-[11px]" placeholder="مثال: لاته کارامل">
687
  </td>
688
  <td class="px-2 py-2">
689
- <input type="text" class="menu-desc w-full bg-tabriz-800/60 border border-tabriz-600/40 rounded-lg px-2.5 py-1.5 text-white focus:border-gold/50 focus:outline-none text-[11px]" placeholder="ترکیب اسپرسو دبل، سس کارامل و فوم شیر">
690
  </td>
691
  <td class="px-2 py-2">
692
- <input type="text" class="menu-price w-full bg-tabriz-800/60 border border-tabriz-600/40 rounded-lg px-2.5 py-1.5 text-white focus:border-gold/50 focus:outline-none text-[11px]" placeholder="۸۵,۰۰۰">
693
  </td>
694
  <td class="px-2 py-2 text-center">
695
- <button onclick="removeMenuRow(this)" class="p-1 text-zinc-600 hover:text-rose-500 transition-colors">
696
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
697
- <path stroke-linecap="round" stroke-linejoin="round" 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" />
698
  </svg>
699
  </button>
700
  </td>
@@ -729,10 +1217,10 @@
729
  });
730
  const data = await response.json();
731
  if (response.ok && data.success) {
732
- alert("منوی جدید با موفقیت ثبت و روی وب‌سایت همگام‌سازی شد!");
733
  document.getElementById('menuEditorContainer').classList.add('hidden');
734
- fetchCurrentMenu(); // refresh main menu table
735
- appendChatMessage('model', 'منوی زنده همگام‌سازی شد. سیستم سفارش‌گیری مشتریان اکنون بر مبنای آخرین لیست ویرایش‌شده کالیبره شده است.');
736
  } else {
737
  alert(data.error || 'بروز خطا در همگام‌سازی ساختار داده‌های جدید.');
738
  }
@@ -741,7 +1229,7 @@
741
  }
742
  }
743
 
744
- // ==================== Admin Chat (updated with Markdown) ====================
745
  async function sendAdminMessage(e) {
746
  e.preventDefault();
747
  if (isGenerating) return;
@@ -769,11 +1257,10 @@
769
  isGenerating = false;
770
 
771
  if (response.ok && data.success) {
772
- const botBubbleId = appendChatMessage('model', ''); // empty placeholder
773
  const botBubble = document.getElementById(botBubbleId);
774
  const textResponse = data.response;
775
  let i = 0;
776
- // Typewriter effect with plain text
777
  function typeText() {
778
  if (i < textResponse.length && !abortController.signal.aborted) {
779
  botBubble.textContent += textResponse.charAt(i);
@@ -781,11 +1268,9 @@
781
  document.getElementById('chatMessages').scrollTop = document.getElementById('chatMessages').scrollHeight;
782
  setTimeout(typeText, 6);
783
  } else {
784
- // Once done, replace with rendered Markdown
785
- botBubble.textContent = ''; // clear
786
  botBubble.innerHTML = marked.parse(textResponse);
787
  chatHistory.push({ role: 'model', content: textResponse });
788
- // After Nila might have changed menu, refresh the menu list
789
  fetchCurrentMenu();
790
  }
791
  }
@@ -797,7 +1282,7 @@
797
  toggleChatLoading(false);
798
  isGenerating = false;
799
  if (err.name !== 'AbortError') {
800
- appendChatMessage('model', 'عدم دریافت موفق پاسخ در بستر شبکه: ' + err.message);
801
  }
802
  }
803
  }
@@ -827,26 +1312,29 @@
827
 
828
  function appendChatMessage(role, content) {
829
  const container = document.getElementById('chatMessages');
830
- const bubbleId = 'bubble-admin-' + Date.now();
831
  let html = '';
832
 
833
  if (role === 'user') {
834
  html = `
835
  <div class="flex justify-end gap-2.5 max-w-[85%] mr-auto">
836
- <div class="bg-gold/10 border border-gold/25 text-white text-xs rounded-2xl rounded-tl-none px-3.5 py-2.5 leading-relaxed">
837
  ${escapeHtml(content)}
838
  </div>
 
 
 
 
 
839
  </div>
840
  `;
841
  } else {
842
- // For model, we use innerHTML with chat-markdown class
843
- // Note: content will be set later (initially empty for typewriter)
844
  html = `
845
  <div class="flex gap-2.5 max-w-[85%]">
846
- <div class="w-8 h-8 rounded-xl bg-turquoise/15 border border-turquoise/20 flex items-center justify-center flex-shrink-0">
847
- <span class="text-gold font-extrabold text-[10px] font-mono">AI</span>
848
  </div>
849
- <div id="${bubbleId}" class="bg-tabriz-900/60 border border-tabriz-700/30 text-zinc-200 text-xs rounded-2xl rounded-tr-none px-3.5 py-2.5 leading-relaxed shadow-inner-soft chat-markdown">
850
  ${content ? marked.parse(content) : ''}
851
  </div>
852
  </div>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6
+ <title>Cafe AI پنل مدیریت</title>
7
+
8
  <link rel="preconnect" href="https://fonts.googleapis.com">
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link href="https://fonts.googleapis.com/css2?family=Lalezar&family=Vazirmatn:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet">
11
+
12
  <script src="https://cdn.tailwindcss.com"></script>
 
13
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
14
+
15
  <script>
16
  tailwind.config = {
17
  theme: {
18
  extend: {
19
  fontFamily: {
20
  sans: ['Vazirmatn', 'sans-serif'],
21
+ display: ['Lalezar', 'serif'],
22
  },
23
  colors: {
24
+ bazaar: {
25
+ 950: '#1a0d07',
26
+ 900: '#2d1810',
27
+ 800: '#3d2418',
28
+ 700: '#5c3a2a',
29
+ 600: '#7a4e3a',
30
+ 500: '#9c6b4f',
31
+ 400: '#b8856a',
32
+ 300: '#d4a88c',
33
+ },
34
+ azure: {
35
+ 950: '#051a2e',
36
+ 900: '#0a2540',
37
+ 800: '#123a5e',
38
+ 700: '#1e4976',
39
+ 600: '#2d6ca8',
40
+ 500: '#3d8bc4',
41
+ 400: '#6ba7d4',
42
+ 300: '#a3c8e4',
43
+ },
44
+ turk: {
45
+ DEFAULT: '#0d9488',
46
+ light: '#2dd4bf',
47
+ glow: '#5eead4',
48
+ deep: '#134e4a',
49
+ },
50
+ rug: {
51
+ DEFAULT: '#8b1e3f',
52
+ light: '#c23d5f',
53
+ dark: '#5a1028',
54
+ glow: '#e85d7e',
55
  },
56
+ ochre: {
57
+ DEFAULT: '#c9a961',
58
+ light: '#e4c97a',
59
+ dark: '#9c7d3a',
60
+ pale: '#f0dca3',
61
  },
62
+ ivory: '#faf3e7',
63
+ cream: '#f5e6d3',
64
+ saffron: '#d97706',
65
+ emerald: {
66
+ DEFAULT: '#10b981',
67
+ light: '#34d399',
68
+ dark: '#065f46',
69
+ },
70
+ rose: {
71
+ DEFAULT: '#e11d48',
72
+ light: '#fb7185',
73
  },
 
 
74
  },
75
  boxShadow: {
76
+ 'carpet': '0 10px 40px -10px rgba(139, 30, 63, 0.35), 0 0 0 1px rgba(201, 169, 97, 0.15)',
77
+ 'mosque': '0 10px 40px -10px rgba(13, 148, 136, 0.4), 0 0 0 1px rgba(45, 212, 191, 0.2)',
78
+ 'bazaar-glow': '0 0 60px rgba(201, 169, 97, 0.25), inset 0 1px 0 rgba(244, 228, 163, 0.1)',
79
+ 'inner-soft': 'inset 0 2px 8px rgba(0,0,0,0.35)',
80
+ 'inner-gold': 'inset 0 0 20px rgba(201, 169, 97, 0.15)',
81
+ },
82
+ animation: {
83
+ 'float': 'float 6s ease-in-out infinite',
84
+ 'shimmer': 'shimmer 3s ease-in-out infinite',
85
+ 'pulse-glow': 'pulseGlow 2.5s ease-in-out infinite',
86
+ 'ping-slow': 'ping 2.5s cubic-bezier(0, 0, 0.2, 1) infinite',
87
  },
88
+ keyframes: {
89
+ float: {
90
+ '0%, 100%': { transform: 'translateY(0px)' },
91
+ '50%': { transform: 'translateY(-12px)' },
92
+ },
93
+ shimmer: {
94
+ '0%, 100%': { opacity: '0.7' },
95
+ '50%': { opacity: '1' },
96
+ },
97
+ pulseGlow: {
98
+ '0%, 100%': { boxShadow: '0 0 20px rgba(201, 169, 97, 0.3)' },
99
+ '50%': { boxShadow: '0 0 40px rgba(201, 169, 97, 0.6)' },
100
+ },
101
  },
102
  }
103
  }
104
  }
105
  </script>
106
+
107
  <style>
108
+ :root {
109
+ --pattern-url: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='80' viewBox='0 0 80 80'%3E%3Cg fill='none' stroke='%23c9a961' stroke-width='0.6' opacity='0.08'%3E%3Cpath d='M40 10 L50 20 L60 10 L70 20 L60 30 L70 40 L60 50 L70 60 L60 70 L50 60 L40 70 L30 60 L20 70 L10 60 L20 50 L10 40 L20 30 L10 20 L20 10 L30 20 Z'/%3E%3Ccircle cx='40' cy='40' r='12'/%3E%3Ccircle cx='40' cy='40' r='6'/%3E%3Cpath d='M40 28 L40 52 M28 40 L52 40'/%3E%3C/g%3E%3C/svg%3E");
110
+ }
111
+
112
+ html { scroll-behavior: smooth; }
113
+
114
  body {
115
+ background-color: #1a0d07;
116
+ color: #f5e6d3;
117
  -webkit-tap-highlight-color: transparent;
118
+ font-feature-settings: "ss01", "cv01";
119
  }
120
+
121
+ .bg-pattern {
122
+ background-image: var(--pattern-url);
123
+ background-size: 80px 80px;
124
  }
125
+
126
+ .bg-pattern-fine {
127
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 40 40'%3E%3Cg fill='none' stroke='%23c9a961' stroke-width='0.4' opacity='0.1'%3E%3Cpath d='M20 0 L20 40 M0 20 L40 20'/%3E%3Ccircle cx='20' cy='20' r='3'/%3E%3Ccircle cx='0' cy='0' r='2'/%3E%3Ccircle cx='40' cy='0' r='2'/%3E%3Ccircle cx='0' cy='40' r='2'/%3E%3Ccircle cx='40' cy='40' r='2'/%3E%3C/g%3E%3C/svg%3E");
128
  }
129
+
130
+ .bg-arch {
131
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200' viewBox='0 0 200 200'%3E%3Cg fill='none' stroke='%230d9488' stroke-width='0.5' opacity='0.06'%3E%3Cpath d='M100 20 Q 40 40, 40 100 Q 40 180, 100 180 Q 160 180, 160 100 Q 160 40, 100 20 Z'/%3E%3Cpath d='M100 50 Q 65 65, 65 100 Q 65 155, 100 155 Q 135 155, 135 100 Q 135 65, 100 50 Z'/%3E%3Cpath d='M100 80 Q 85 90, 85 100 Q 85 130, 100 130 Q 115 130, 115 100 Q 115 90, 100 80 Z'/%3E%3C/g%3E%3C/svg%3E");
132
+ background-size: 200px 200px;
133
+ }
134
+
135
+ /* Scrollbar */
136
+ ::-webkit-scrollbar { width: 6px; height: 6px; }
137
+ ::-webkit-scrollbar-track { background: #1a0d07; }
138
  ::-webkit-scrollbar-thumb {
139
+ background: linear-gradient(180deg, #c9a961, #8b1e3f);
140
  border-radius: 4px;
141
  }
142
+ ::-webkit-scrollbar-thumb:hover { background: linear-gradient(180deg, #e4c97a, #c23d5f); }
143
+
144
  .glass-card {
145
+ background: linear-gradient(135deg, rgba(45, 24, 16, 0.82) 0%, rgba(26, 13, 7, 0.78) 100%);
146
+ backdrop-filter: blur(20px);
147
+ -webkit-backdrop-filter: blur(20px);
148
+ border: 1px solid rgba(201, 169, 97, 0.18);
149
+ box-shadow:
150
+ 0 20px 50px -20px rgba(0, 0, 0, 0.6),
151
+ inset 0 1px 0 rgba(244, 228, 163, 0.08);
152
+ transition: all 0.4s ease;
153
  }
154
  .glass-card:hover {
155
+ border-color: rgba(201, 169, 97, 0.3);
156
+ box-shadow:
157
+ 0 25px 60px -20px rgba(0, 0, 0, 0.7),
158
+ 0 0 40px rgba(201, 169, 97, 0.1),
159
+ inset 0 1px 0 rgba(244, 228, 163, 0.12);
160
+ }
161
+
162
+ .glass-card-azure {
163
+ background: linear-gradient(135deg, rgba(10, 37, 64, 0.78) 0%, rgba(5, 26, 46, 0.82) 100%);
164
+ backdrop-filter: blur(20px);
165
+ -webkit-backdrop-filter: blur(20px);
166
+ border: 1px solid rgba(45, 212, 191, 0.2);
167
+ box-shadow:
168
+ 0 20px 50px -20px rgba(13, 148, 136, 0.2),
169
+ inset 0 1px 0 rgba(94, 234, 212, 0.1);
170
+ }
171
+
172
+ /* Ornament divider */
173
+ .ornament-divider {
174
+ position: relative;
175
+ text-align: center;
176
+ }
177
+ .ornament-divider::before,
178
+ .ornament-divider::after {
179
+ content: '';
180
+ position: absolute;
181
+ top: 50%;
182
+ width: 30%;
183
+ height: 1px;
184
+ background: linear-gradient(90deg, transparent, rgba(201, 169, 97, 0.5), transparent);
185
+ }
186
+ .ornament-divider::before { left: 0; }
187
+ .ornament-divider::after { right: 0; }
188
+
189
+ /* Arch shape */
190
+ .arch-shape {
191
+ border-radius: 50% 50% 1rem 1rem / 35% 35% 1rem 1rem;
192
+ }
193
+
194
+ /* Chat Markdown - پشتیبانی کامل */
195
+ .chat-markdown { line-height: 1.85; }
196
+ .chat-markdown > * + * { margin-top: 0.6em; }
197
+
198
+ .chat-markdown h1, .chat-markdown h2, .chat-markdown h3,
199
+ .chat-markdown h4, .chat-markdown h5, .chat-markdown h6 {
200
+ font-family: 'Lalezar', serif;
201
+ color: #e4c97a;
202
+ margin-top: 1em;
203
+ margin-bottom: 0.4em;
204
+ line-height: 1.3;
205
+ }
206
+ .chat-markdown h1 { font-size: 1.4em; }
207
+ .chat-markdown h2 { font-size: 1.25em; }
208
+ .chat-markdown h3 { font-size: 1.15em; color: #5eead4; }
209
+ .chat-markdown h4, .chat-markdown h5, .chat-markdown h6 { font-size: 1.05em; }
210
+
211
+ .chat-markdown p { margin-bottom: 0.5em; }
212
+
213
+ .chat-markdown ul, .chat-markdown ol {
214
+ padding-right: 1.4em;
215
+ margin: 0.4em 0;
216
+ }
217
+ .chat-markdown ul { list-style-type: '❋ '; }
218
+ .chat-markdown ol { list-style-type: persian; }
219
+ .chat-markdown li { margin-bottom: 0.3em; padding-right: 0.2em; }
220
+ .chat-markdown li::marker { color: #c9a961; }
221
+
222
+ .chat-markdown strong {
223
+ color: #f0dca3;
224
+ font-weight: 700;
225
+ text-shadow: 0 0 8px rgba(201, 169, 97, 0.3);
226
+ }
227
+ .chat-markdown em {
228
+ color: #5eead4;
229
+ font-style: italic;
230
+ }
231
+
232
+ .chat-markdown a {
233
+ color: #2dd4bf;
234
+ text-decoration: underline;
235
+ text-underline-offset: 3px;
236
+ transition: color 0.2s;
237
+ }
238
+ .chat-markdown a:hover { color: #5eead4; }
239
+
240
+ .chat-markdown code {
241
+ background: rgba(13, 148, 136, 0.18);
242
+ color: #5eead4;
243
+ padding: 0.15em 0.4em;
244
+ border-radius: 5px;
245
+ font-size: 0.88em;
246
+ border: 1px solid rgba(45, 212, 191, 0.2);
247
+ font-family: 'Courier New', monospace;
248
+ direction: ltr;
249
+ display: inline-block;
250
+ }
251
+
252
+ .chat-markdown pre {
253
+ background: rgba(5, 26, 46, 0.7);
254
+ border: 1px solid rgba(45, 212, 191, 0.25);
255
+ border-right: 3px solid #0d9488;
256
+ padding: 0.9em 1em;
257
+ border-radius: 8px;
258
+ overflow-x: auto;
259
+ margin: 0.6em 0;
260
+ direction: ltr;
261
+ text-align: left;
262
+ }
263
+ .chat-markdown pre code {
264
+ background: transparent;
265
+ border: none;
266
+ padding: 0;
267
+ color: #a3c8e4;
268
+ font-size: 0.85em;
269
+ }
270
+
271
+ .chat-markdown blockquote {
272
+ border-right: 3px solid #c9a961;
273
+ background: linear-gradient(90deg, rgba(201, 169, 97, 0.08), transparent);
274
+ padding: 0.5em 1em;
275
+ margin: 0.6em 0;
276
+ color: #f0dca3;
277
+ font-style: italic;
278
+ border-radius: 0 8px 8px 0;
279
+ }
280
+ .chat-markdown blockquote p { margin: 0; }
281
+
282
+ .chat-markdown hr {
283
+ border: none;
284
+ height: 1px;
285
+ background: linear-gradient(90deg, transparent, rgba(201, 169, 97, 0.5), transparent);
286
+ margin: 1em 0;
287
+ }
288
+
289
+ .chat-markdown table {
290
+ width: 100%;
291
+ border-collapse: collapse;
292
+ margin: 0.6em 0;
293
+ font-size: 0.92em;
294
+ background: rgba(45, 24, 16, 0.5);
295
+ border-radius: 8px;
296
+ overflow: hidden;
297
+ border: 1px solid rgba(201, 169, 97, 0.25);
298
+ }
299
+ .chat-markdown thead {
300
+ background: linear-gradient(90deg, rgba(139, 30, 63, 0.4), rgba(201, 169, 97, 0.2));
301
+ }
302
+ .chat-markdown th {
303
+ padding: 0.55em 0.8em;
304
+ text-align: right;
305
+ color: #e4c97a;
306
+ font-weight: 700;
307
+ border-bottom: 1px solid rgba(201, 169, 97, 0.3);
308
+ font-family: 'Lalezar', serif;
309
+ }
310
+ .chat-markdown td {
311
+ padding: 0.5em 0.8em;
312
+ border-bottom: 1px solid rgba(201, 169, 97, 0.1);
313
+ }
314
+ .chat-markdown tr:last-child td { border-bottom: none; }
315
+ .chat-markdown tr:hover td { background: rgba(201, 169, 97, 0.05); }
316
+
317
+ .chat-markdown img {
318
+ max-width: 100%;
319
+ border-radius: 10px;
320
+ border: 2px solid rgba(201, 169, 97, 0.3);
321
+ }
322
+
323
+ /* Typing dots */
324
+ .typing-dots span {
325
+ display: inline-block;
326
+ width: 6px;
327
+ height: 6px;
328
+ border-radius: 50%;
329
+ background: #c9a961;
330
+ animation: typing 1.4s infinite;
331
+ }
332
+ .typing-dots span:nth-child(2) { animation-delay: 0.2s; }
333
+ .typing-dots span:nth-child(3) { animation-delay: 0.4s; }
334
+ @keyframes typing {
335
+ 0%, 60%, 100% { transform: translateY(0); opacity: 0.5; }
336
+ 30% { transform: translateY(-8px); opacity: 1; }
337
+ }
338
+
339
+ /* Button styles */
340
+ .btn-primary {
341
+ background: linear-gradient(135deg, #c9a961 0%, #9c7d3a 100%);
342
+ color: #1a0d07;
343
+ font-weight: 800;
344
+ transition: all 0.3s ease;
345
+ box-shadow: 0 8px 20px -5px rgba(201, 169, 97, 0.4);
346
+ }
347
+ .btn-primary:hover {
348
+ background: linear-gradient(135deg, #e4c97a 0%, #c9a961 100%);
349
+ transform: translateY(-2px);
350
+ box-shadow: 0 12px 28px -5px rgba(201, 169, 97, 0.6);
351
+ }
352
+ .btn-primary:disabled {
353
+ opacity: 0.5;
354
+ cursor: not-allowed;
355
+ transform: none;
356
+ }
357
+
358
+ .btn-ghost {
359
+ background: rgba(201, 169, 97, 0.08);
360
+ color: #f0dca3;
361
+ border: 1px solid rgba(201, 169, 97, 0.2);
362
+ transition: all 0.3s ease;
363
+ }
364
+ .btn-ghost:hover {
365
+ background: rgba(201, 169, 97, 0.18);
366
+ border-color: rgba(201, 169, 97, 0.45);
367
+ }
368
+
369
+ .btn-rug {
370
+ background: linear-gradient(135deg, #8b1e3f 0%, #5a1028 100%);
371
+ color: #f5e6d3;
372
+ border: 1px solid rgba(201, 169, 97, 0.3);
373
+ transition: all 0.3s ease;
374
+ }
375
+ .btn-rug:hover {
376
+ background: linear-gradient(135deg, #c23d5f 0%, #8b1e3f 100%);
377
+ border-color: rgba(201, 169, 97, 0.6);
378
+ transform: translateY(-1px);
379
+ }
380
+
381
+ .btn-turk {
382
+ background: linear-gradient(135deg, #0d9488 0%, #134e4a 100%);
383
+ color: #f5e6d3;
384
+ border: 1px solid rgba(45, 212, 191, 0.3);
385
+ transition: all 0.3s ease;
386
+ box-shadow: 0 6px 16px -4px rgba(13, 148, 136, 0.4);
387
+ }
388
+ .btn-turk:hover {
389
+ background: linear-gradient(135deg, #2dd4bf 0%, #0d9488 100%);
390
+ border-color: rgba(94, 234, 212, 0.6);
391
+ transform: translateY(-1px);
392
+ }
393
+
394
+ /* Drop zone */
395
+ .drop-zone {
396
+ position: relative;
397
+ border: 2px dashed rgba(201, 169, 97, 0.3);
398
+ transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
399
+ }
400
+ .drop-zone:hover, .drop-zone.drag-over {
401
+ border-color: rgba(201, 169, 97, 0.7);
402
+ background: rgba(201, 169, 97, 0.06);
403
+ transform: scale(1.005);
404
+ }
405
+ .drop-zone::before {
406
+ content: '';
407
+ position: absolute;
408
+ inset: 6px;
409
+ border: 1px dashed rgba(201, 169, 97, 0.15);
410
+ border-radius: inherit;
411
+ pointer-events: none;
412
+ }
413
+
414
+ /* Order cards */
415
+ .order-card {
416
+ background: linear-gradient(135deg, rgba(45, 24, 16, 0.6), rgba(26, 13, 7, 0.5));
417
+ border: 1px solid rgba(201, 169, 97, 0.2);
418
+ transition: all 0.3s ease;
419
+ }
420
+ .order-card:hover {
421
+ border-color: rgba(201, 169, 97, 0.5);
422
+ box-shadow: 0 12px 30px -10px rgba(139, 30, 63, 0.3);
423
+ transform: translateY(-2px);
424
+ }
425
+
426
+ /* Table rows */
427
+ .menu-row {
428
+ transition: all 0.3s ease;
429
+ }
430
+ .menu-row:hover {
431
+ background: rgba(201, 169, 97, 0.05);
432
+ }
433
+
434
+ /* Input focus */
435
+ input:focus, textarea:focus, select:focus {
436
+ outline: none;
437
+ border-color: rgba(201, 169, 97, 0.6);
438
+ box-shadow: 0 0 0 3px rgba(201, 169, 97, 0.15);
439
+ }
440
+
441
+ /* Checkbox custom */
442
+ input[type="checkbox"] {
443
+ appearance: none;
444
+ width: 18px;
445
+ height: 18px;
446
+ border: 2px solid rgba(201, 169, 97, 0.4);
447
+ border-radius: 4px;
448
+ background: rgba(45, 24, 16, 0.5);
449
+ cursor: pointer;
450
+ position: relative;
451
+ transition: all 0.2s ease;
452
+ }
453
+ input[type="checkbox"]:checked {
454
+ background: linear-gradient(135deg, #0d9488, #134e4a);
455
+ border-color: #2dd4bf;
456
+ }
457
+ input[type="checkbox"]:checked::after {
458
+ content: '✓';
459
+ position: absolute;
460
+ top: 50%;
461
+ left: 50%;
462
+ transform: translate(-50%, -50%);
463
+ color: #f5e6d3;
464
+ font-size: 14px;
465
+ font-weight: bold;
466
+ }
467
+
468
+ /* Live indicator */
469
+ .live-dot {
470
+ display: inline-block;
471
+ width: 8px;
472
+ height: 8px;
473
+ border-radius: 50%;
474
+ background: #10b981;
475
+ box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.7);
476
+ animation: live-pulse 2s infinite;
477
+ }
478
+ @keyframes live-pulse {
479
+ 0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.7); }
480
+ 70% { box-shadow: 0 0 0 10px rgba(16, 185, 129, 0); }
481
+ 100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
482
+ }
483
+
484
+ /* Section title */
485
+ .section-title {
486
+ font-family: 'Lalezar', serif;
487
+ letter-spacing: 0.02em;
488
+ }
489
+
490
+ /* Badge */
491
+ .badge-live {
492
+ background: linear-gradient(135deg, rgba(16, 185, 129, 0.15), rgba(6, 95, 70, 0.2));
493
+ border: 1px solid rgba(52, 211, 153, 0.4);
494
+ color: #34d399;
495
+ }
496
+
497
+ .badge-table {
498
+ background: linear-gradient(135deg, rgba(201, 169, 97, 0.15), rgba(139, 30, 63, 0.15));
499
+ border: 1px solid rgba(201, 169, 97, 0.4);
500
+ color: #e4c97a;
501
+ }
502
+
503
+ /* Table styling */
504
+ .admin-table thead {
505
+ background: linear-gradient(90deg, rgba(139, 30, 63, 0.25), rgba(201, 169, 97, 0.15));
506
+ }
507
+ .admin-table th {
508
+ font-family: 'Lalezar', serif;
509
+ color: #e4c97a;
510
+ font-size: 11px;
511
+ }
512
+ .admin-table td, .admin-table th {
513
+ border-bottom: 1px solid rgba(201, 169, 97, 0.1);
514
+ }
515
+
516
+ /* Mobile optimizations */
517
+ @media (max-width: 640px) {
518
+ .chat-markdown { font-size: 0.92rem; }
519
+ }
520
  </style>
521
  </head>
522
+ <body class="min-h-screen flex flex-col font-sans selection:bg-ochre selection:text-bazaar-950 overflow-x-hidden antialiased">
523
 
524
+ <!-- Ambient Background -->
525
+ <div class="fixed inset-0 overflow-hidden pointer-events-none z-0">
526
+ <div class="absolute inset-0 bg-gradient-to-br from-bazaar-950 via-bazaar-900 to-azure-950"></div>
527
+ <div class="absolute inset-0 bg-pattern opacity-40"></div>
528
+ <div class="absolute -top-40 -right-40 w-[600px] h-[600px] rounded-full bg-rug/10 blur-[140px] animate-float"></div>
529
+ <div class="absolute -bottom-40 -left-40 w-[600px] h-[600px] rounded-full bg-turk/10 blur-[140px] animate-float" style="animation-delay: -3s;"></div>
530
+ <div class="absolute top-1/3 left-1/4 w-[400px] h-[400px] rounded-full bg-ochre/8 blur-[120px] animate-shimmer"></div>
531
  </div>
532
 
533
  <!-- Header -->
534
+ <header class="border-b border-ochre/20 bg-bazaar-900/70 backdrop-blur-2xl sticky top-0 z-50 px-4 py-3 md:px-8 shadow-lg">
535
+ <div class="max-w-7xl mx-auto flex items-center justify-between gap-4">
536
  <div class="flex items-center gap-3">
537
+ <div class="relative">
538
+ <div class="w-11 h-11 arch-shape bg-gradient-to-br from-rug via-rug-dark to-bazaar-900 border-2 border-ochre/50 flex items-center justify-center shadow-carpet">
539
+ <svg class="w-6 h-6 text-ochre-light" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
540
+ <path d="M17 8h1a4 4 0 1 1 0 8h-1" stroke-linecap="round"/>
541
+ <path d="M3 8h14v9a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4Z" stroke-linecap="round"/>
542
+ <line x1="6" y1="2" x2="6" y2="4" stroke-linecap="round"/>
543
+ <line x1="10" y1="2" x2="10" y2="4" stroke-linecap="round"/>
544
+ <line x1="14" y1="2" x2="14" y2="4" stroke-linecap="round"/>
545
+ </svg>
546
+ </div>
547
  </div>
548
  <div>
549
+ <h1 class="section-title text-base md:text-lg text-ochre-light tracking-wide flex items-center gap-2">
550
+ <span class="text-rug-light">Cafe AI</span>
551
+ <span class="text-cream/40">|</span>
552
+ <span class="text-cream">پنل مدیریت</span>
553
  </h1>
554
+ <p class="text-[10px] text-turk-light/80 font-medium mt-0.5">پایش برخط سفارشات و منوی هوشمند</p>
555
  </div>
556
  </div>
557
+
558
+ <div class="flex items-center gap-2">
559
+ <span class="badge-live inline-flex items-center gap-2 px-3 py-1.5 rounded-full text-[10px] font-bold">
560
+ <span class="live-dot"></span>
561
  نظارت زنده
562
  </span>
563
  </div>
 
566
 
567
  <!-- Main grid -->
568
  <main class="flex-1 max-w-7xl w-full mx-auto p-4 md:p-6 lg:p-8 grid grid-cols-1 lg:grid-cols-12 gap-6 z-10 relative">
569
+
570
  <!-- Right column: orders + current menu + menu upload (7/12) -->
571
  <section class="lg:col-span-7 flex flex-col gap-6">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
572
 
573
+ <!-- Live orders monitor -->
574
+ <div class="glass-card rounded-3xl p-5 md:p-6 shadow-xl relative overflow-hidden">
575
+ <div class="absolute inset-0 bg-pattern-fine opacity-20 pointer-events-none"></div>
576
+ <div class="relative">
577
+ <div class="flex items-center justify-between mb-4 border-b border-ochre/20 pb-3">
578
+ <div class="flex items-center gap-3">
579
+ <div class="w-9 h-9 rounded-xl bg-rug/20 border border-rug/40 flex items-center justify-center">
580
+ <svg class="w-5 h-5 text-rug-light" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
581
+ <path stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"/>
582
+ </svg>
583
+ </div>
584
+ <div>
585
+ <h2 class="section-title text-base md:text-lg text-ochre-light flex items-center gap-2">
586
+ سفارشات جدید آشپزخانه
587
+ <span class="w-2 h-2 rounded-full bg-rug-light animate-pulse"></span>
588
+ </h2>
589
+ <p class="text-[10px] text-cream/50 mt-0.5">لیست سفارشات در صف آماده‌سازی</p>
590
+ </div>
591
+ </div>
592
+ <button onclick="fetchActiveOrders()" class="btn-ghost text-[10px] flex items-center gap-1.5 px-3 py-1.5 rounded-xl">
593
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
594
+ <path stroke-linecap="round" stroke-linejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 1121.21 15H15"/>
595
  </svg>
596
+ بروزرسانی
 
 
 
597
  </button>
598
  </div>
599
+ <div id="ordersContainer" class="space-y-3 max-h-[400px] overflow-y-auto pr-1">
600
+ <div class="text-center py-12 text-xs text-ochre/60">در حال بارگذاری لیست سفارشات جاری...</div>
601
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
602
  </div>
603
  </div>
604
 
605
+ <!-- Current Menu -->
606
+ <div class="glass-card rounded-3xl p-5 md:p-6 space-y-4 shadow-xl relative overflow-hidden">
607
+ <div class="absolute inset-0 bg-arch opacity-15 pointer-events-none"></div>
608
+ <div class="relative">
609
+ <div class="flex items-center justify-between border-b border-ochre/20 pb-3 mb-3">
610
+ <div class="flex items-center gap-3">
611
+ <div class="w-9 h-9 rounded-xl bg-ochre/20 border border-ochre/40 flex items-center justify-center">
612
+ <svg class="w-5 h-5 text-ochre-light" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
613
+ <path stroke-linecap="round" stroke-linejoin="round" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4"/>
614
+ </svg>
615
+ </div>
616
+ <div>
617
+ <h2 class="section-title text-base md:text-lg text-ochre-light">مدیریت منوی فعال</h2>
618
+ <p class="text-[10px] text-cream/50 mt-0.5">کنترل و ویرایش اقلام قابل سفارش</p>
619
+ </div>
620
+ </div>
621
+ <div class="flex gap-2">
622
+ <button onclick="fetchCurrentMenu()" class="btn-ghost text-[10px] flex items-center gap-1 px-3 py-1.5 rounded-xl">
623
+ <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
624
+ <path stroke-linecap="round" stroke-linejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 1121.21 15H15"/>
625
+ </svg>
626
+ بازنشانی
627
+ </button>
628
+ <button onclick="addMenuItemRow()" class="btn-turk px-4 py-1.5 rounded-xl text-[10px] font-extrabold flex items-center gap-1">
629
+ <span>+ افزودن دستی</span>
630
+ </button>
631
+ </div>
632
  </div>
633
+ <p class="text-[11px] text-cream/70 leading-relaxed mb-4">
634
+ لیست تمام اقلام منوی کافه. می‌توانید هر آیتم را ویرایش، حذف یا آیتم جدید اضافه کنید. تغییرات بلافاصله روی سامانه مشتریان اعمال می‌شود.
635
+ </p>
636
+ <div class="overflow-x-auto max-h-[400px] border border-ochre/20 rounded-2xl bg-bazaar-950/50">
637
+ <table class="min-w-full admin-table text-[11px]" id="currentMenuTable">
638
+ <thead class="sticky top-0">
 
 
 
 
 
 
 
 
 
639
  <tr>
640
+ <th class="px-3 py-2.5 text-right">نام محصول</th>
641
+ <th class="px-3 py-2.5 text-right hidden md:table-cell">توضیحات</th>
642
+ <th class="px-3 py-2.5 text-right w-20">قیمت</th>
643
+ <th class="px-3 py-2.5 text-center w-16">موجود</th>
644
+ <th class="px-3 py-2.5 text-center w-24">عملیات</th>
645
  </tr>
646
  </thead>
647
+ <tbody id="menuTableBody" class="divide-y divide-ochre/10">
648
+ <!-- filled by JS -->
649
  </tbody>
650
  </table>
651
  </div>
652
+ </div>
653
+ </div>
654
+
655
+ <!-- Menu extraction & upload -->
656
+ <div class="glass-card rounded-3xl p-5 md:p-6 space-y-4 shadow-xl relative overflow-hidden">
657
+ <div class="absolute inset-0 bg-pattern-fine opacity-20 pointer-events-none"></div>
658
+ <div class="relative">
659
+ <div class="flex items-center gap-3 border-b border-ochre/20 pb-3 mb-3">
660
+ <div class="w-9 h-9 rounded-xl bg-turk/20 border border-turk/40 flex items-center justify-center">
661
+ <svg class="w-5 h-5 text-turk-light" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
662
+ <path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"/>
663
+ </svg>
664
+ </div>
665
+ <div>
666
+ <h2 class="section-title text-base md:text-lg text-ochre-light">استخراج خودکار منو با هوش مصنوعی</h2>
667
+ <p class="text-[10px] text-cream/50 mt-0.5">بارگذاری تصویر یا فایل PDF منو</p>
668
+ </div>
669
+ </div>
670
+ <p class="text-[11px] text-cream/70 leading-relaxed mb-4">
671
+ تصویر منو یا فاکتور جدید کافه را بارگذاری کنید. هوش مصنوعی نیلا متون و قیمت‌ها را استخراج کرده و جهت تایید نهایی ساختاربندی می‌کند.
672
+ </p>
673
+
674
+ <!-- Drag & drop zone -->
675
+ <div id="dropZone"
676
+ class="drop-zone rounded-2xl p-8 md:p-10 text-center cursor-pointer"
677
+ onclick="document.getElementById('menuFileInput').click()"
678
+ ondragover="handleDragOver(event)"
679
+ ondragleave="handleDragLeave(event)"
680
+ ondrop="handleDrop(event)">
681
+ <input type="file" id="menuFileInput" class="hidden" accept="image/*,application/pdf" onchange="uploadMenuFile(event)">
682
+ <div class="flex flex-col items-center gap-3">
683
+ <div class="w-16 h-16 rounded-2xl bg-gradient-to-br from-ochre/20 to-rug/15 border border-ochre/30 flex items-center justify-center">
684
+ <svg id="uploadIcon" class="w-8 h-8 text-ochre-light transition-all duration-300" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
685
+ <path stroke-linecap="round" stroke-linejoin="round" d="M9 13h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z"/>
686
+ </svg>
687
+ </div>
688
+ <span class="text-sm text-cream font-medium">فایل یا تصویر منو را بکشید یا انتخاب کنید</span>
689
+ <span class="text-[10px] text-ochre/60 uppercase tracking-widest">فرمت‌های تصویری یا PDF</span>
690
+ </div>
691
+ </div>
692
+
693
+ <div id="uploadLoader" class="hidden text-center py-6 bg-bazaar-950/70 rounded-2xl border border-turk/30 mt-4">
694
+ <div class="inline-block animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-ochre mb-2"></div>
695
+ <p class="text-[10px] text-ochre-light font-extrabold">نیلا در حال ساختارسازی و آنالیز متون منوی جدید...</p>
696
+ </div>
697
+
698
+ <div id="menuEditorContainer" class="hidden space-y-4 border-t border-ochre/15 pt-4 mt-4">
699
+ <h3 class="text-xs font-bold text-ochre-light flex items-center gap-1.5 section-title">
700
+ <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
701
+ <path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
702
+ </svg>
703
+ بازبینی اقلام منو پیش از انتشار زنده
704
+ </h3>
705
+ <div class="overflow-x-auto max-h-[250px] border border-ochre/20 rounded-2xl bg-bazaar-950/50">
706
+ <table class="min-w-full admin-table text-[11px]">
707
+ <thead>
708
+ <tr>
709
+ <th class="px-3 py-2.5 text-right">عنوان محصول</th>
710
+ <th class="px-3 py-2.5 text-right">توضیحات کوتاه</th>
711
+ <th class="px-3 py-2.5 text-right w-24">قیمت (تومان)</th>
712
+ <th class="px-3 py-2.5 text-center w-16">عملیات</th>
713
+ </tr>
714
+ </thead>
715
+ <tbody id="menuEditorTableBody" class="divide-y divide-ochre/10">
716
+ <!-- dynamic rows -->
717
+ </tbody>
718
+ </table>
719
+ </div>
720
+ <div class="flex justify-end gap-2 flex-wrap">
721
+ <button onclick="addEmptyMenuRow()" class="btn-ghost px-4 py-2 rounded-xl text-[10px]">
722
+ + افزودن دستی محصول جدید
723
+ </button>
724
+ <button onclick="saveAndPublishMenu()" class="btn-turk px-5 py-2.5 rounded-xl text-[11px] font-extrabold flex items-center gap-2">
725
+ ثبت و همگام‌سازی زنده منو
726
+ </button>
727
+ </div>
728
  </div>
729
  </div>
730
  </div>
731
  </section>
732
 
733
  <!-- Left column: Admin chat assistant (5/12) -->
734
+ <section class="lg:col-span-5 flex flex-col glass-card-azure rounded-3xl h-[800px] lg:h-auto overflow-hidden shadow-xl relative">
735
+ <div class="absolute inset-0 bg-arch opacity-15 pointer-events-none"></div>
736
+
737
+ <div class="relative px-5 py-4 border-b border-turk/25 flex items-center justify-between bg-gradient-to-l from-azure-950/60 to-azure-900/40">
738
  <div class="flex items-center gap-3">
739
+ <div class="w-11 h-11 rounded-xl bg-gradient-to-br from-turk/30 to-azure-700/30 border border-turk/40 flex items-center justify-center shadow-mosque">
740
+ <svg class="w-6 h-6 text-turk-glow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
741
  <path d="M12 2a10 10 0 0 1 10 10c0 5.523-4.477 10-10 10S2 17.523 2 12A10 10 0 0 1 12 2z"/>
742
+ <path d="M12 8v4l3 3" stroke-linecap="round"/>
743
  </svg>
744
  </div>
745
  <div>
746
+ <h3 class="section-title text-sm text-ochre-light tracking-wide">دستیار هوشمند ادمین</h3>
747
+ <p class="text-[10px] text-turk-light/80 font-medium flex items-center gap-1.5">
748
+ <span class="w-1.5 h-1.5 rounded-full bg-turk-light animate-pulse"></span>
749
+ کنترل همگام موجودی و منو با زبان طبیعی
750
+ </p>
751
  </div>
752
  </div>
753
  </div>
754
 
755
+ <div id="chatMessages" class="relative flex-1 overflow-y-auto p-4 space-y-4">
756
  <div class="flex gap-2.5 max-w-[85%]">
757
+ <div class="w-8 h-8 rounded-xl bg-gradient-to-br from-turk/20 to-azure-700/20 border border-turk/30 flex items-center justify-center flex-shrink-0">
758
+ <span class="text-ochre-light font-display text-[11px]">ن</span>
759
  </div>
760
+ <div class="bg-bazaar-950/70 border border-ochre/20 text-cream text-xs rounded-2xl rounded-tr-none px-3.5 py-2.5 leading-relaxed shadow-inner-soft chat-markdown">
761
+ سلام همکار گرامی! من <strong>نیلا</strong> هستم، دستیار مدیریت منوی <em>Cafe AI</em>. شما می‌توانید از همین‌جا اقلام منو را با گفتگوی ساده کنترل کنید؛ برای مثال بنویسید: «کروسان ساده تمام شد» یا «چای ماسالا را موجود کن» تا سریعاً تغییرات روی سیستم مشتریان نیز اعمال گردد.
762
  </div>
763
  </div>
764
  </div>
765
 
766
+ <div id="chatLoader" class="hidden relative px-4 py-3 flex items-center justify-between bg-azure-950/70 text-[10px] text-turk-light font-semibold border-t border-turk/20">
767
+ <div class="flex items-center gap-2.5">
768
+ <div class="typing-dots flex gap-1">
769
+ <span></span><span></span><span></span>
 
 
770
  </div>
771
+ <span>نیلا در حال پردازش دستور مدیریت...</span>
772
  </div>
773
+ <button onclick="stopAdminChat()" class="px-3 py-1.5 bg-rug-dark/40 border border-rug/40 hover:bg-rug/40 rounded-lg text-[10px] text-rug-light font-bold transition-all">
774
+ توقف
775
+ </button>
776
  </div>
777
 
778
+ <form id="chatForm" onsubmit="sendAdminMessage(event)" class="relative p-3 border-t border-turk/20 bg-bazaar-950/60 flex gap-2">
779
+ <input type="text" id="chatInput" placeholder="تغییر وضعیت یا ویرایش منو را متنی بنویسید..." autocomplete="off"
780
+ class="flex-1 bg-azure-950/60 border border-azure-700/40 text-xs text-cream placeholder-ochre/40 rounded-xl px-4 py-3 focus:outline-none focus:border-ochre/60 transition-all duration-300">
781
+ <button type="submit" id="sendBtn" class="btn-primary px-4 py-3 rounded-xl text-xs flex items-center justify-center flex-shrink-0">
782
+ <svg class="w-5 h-5 rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
783
+ <path stroke-linecap="round" stroke-linejoin="round" d="M14 5l7 7m0 0l-7 7m7-7H3"/>
784
  </svg>
785
  </button>
786
  </form>
787
  </section>
788
  </main>
789
 
790
+ <footer class="border-t border-ochre/15 py-4 text-center text-[10px] text-cream/40 bg-bazaar-950/60 backdrop-blur">
791
  طراحی و توسعه توسط الگوریتم داده نسترن | با الهام از فرهنگ تبریز © ۲۰۲۶
792
  </footer>
793
 
 
796
  marked.setOptions({ sanitize: true, breaks: true });
797
 
798
  let chatHistory = [
799
+ { role: 'model', content: 'سلام همکار گرامی! من نیلا هستم، دستیار مدیریت منوی Cafe AI. شما می‌توانید از همین‌جا اقلام منو را با گفتگوی ساده کنترل کنید؛ برای مثال بنویسید: «کروسان ساده تمام شد» یا «چای ماسالا را موجود کن» تا سریعاً تغییرات روی سیستم مشتریان نیز اعمال گردد.' }
800
  ];
801
  let abortController = null;
802
  let isGenerating = false;
 
807
  setInterval(fetchActiveOrders, 10000);
808
  });
809
 
810
+ // ==================== Order functions ====================
811
  async function fetchActiveOrders() {
812
  const container = document.getElementById('ordersContainer');
813
  try {
 
816
  if (response.ok) {
817
  if (orders.length === 0) {
818
  container.innerHTML = `
819
+ <div class="text-center py-16 text-ochre/60 border-2 border-dashed border-ochre/25 rounded-2xl bg-bazaar-950/30">
820
+ <svg class="w-10 h-10 text-ochre/40 mx-auto mb-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
821
+ <path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
822
  </svg>
823
+ <p class="text-sm font-medium">در حال حاضر سفارش معلقی در صف آشپزخانه نیست</p>
824
+ <p class="text-[10px] text-cream/40 mt-1">سفارشات جدید به صورت خودکار به‌روزرسانی می‌شوند</p>
825
  </div>
826
  `;
827
  return;
 
831
  let itemsHtml = '';
832
  order.items.forEach(item => {
833
  itemsHtml += `
834
+ <div class="flex items-center justify-between text-[11px] bg-bazaar-950/60 px-3 py-2 rounded-lg border border-ochre/20 group">
835
+ <span class="text-cream font-bold flex items-center gap-2">
836
+ <span class="w-1 h-5 bg-gradient-to-b from-rug to-ochre rounded-full"></span>
837
+ ${escapeHtml(item.name)}
838
+ </span>
839
+ <span class="text-ochre-light bg-ochre/10 px-2.5 py-0.5 rounded-md font-display text-[10px] border border-ochre/25">
840
+ ×${item.quantity}
841
+ </span>
842
  </div>
843
  `;
844
  });
845
  const timeString = new Date(order.timestamp * 1000).toLocaleTimeString('fa-IR', { hour: '2-digit', minute: '2-digit' });
846
  const cardHtml = `
847
+ <div class="order-card rounded-2xl p-4 flex flex-col md:flex-row justify-between items-start md:items-center gap-3">
848
  <div class="flex-1 space-y-2 w-full">
849
+ <div class="flex items-center justify-between md:justify-start gap-3 w-full flex-wrap">
850
+ <span class="badge-table text-xs font-bold px-3 py-1 rounded-lg flex items-center gap-1.5">
851
+ <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
852
+ <path stroke-linecap="round" stroke-linejoin="round" d="M3 10h18M3 14h18m-9-4v8m-7 0h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z"/>
853
+ </svg>
854
+ میز شماره ${order.table}
855
+ </span>
856
+ <span class="text-[10px] text-turk-light/70 font-medium flex items-center gap-1">
857
+ <svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
858
+ <path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>
859
+ </svg>
860
+ ${timeString}
861
+ </span>
862
  </div>
863
  <div class="grid grid-cols-1 sm:grid-cols-2 gap-1.5 mt-2">
864
  ${itemsHtml}
865
  </div>
866
  </div>
867
+ <button onclick="completeOrder(${order.id})" class="w-full md:w-auto btn-ghost hover:bg-emerald-dark/40 hover:border-emerald-light/50 hover:text-emerald-light px-4 py-2.5 rounded-xl text-[10px] font-bold flex items-center justify-center gap-1.5 flex-shrink-0 group">
868
+ <svg class="w-4 h-4 transition-transform group-hover:scale-110" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
869
+ <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
870
  </svg>
871
  تحویل نهایی شد
872
  </button>
 
875
  container.insertAdjacentHTML('beforeend', cardHtml);
876
  });
877
  } else {
878
+ container.innerHTML = `<div class="text-center py-6 text-rug-light text-xs">خطا در دریافت لیست سفارشات آشپزخانه.</div>`;
879
  }
880
  } catch (err) {
881
+ container.innerHTML = `<div class="text-center py-6 text-rug-light text-xs">عدم برقراری ارتباط زنده با سرور: ${escapeHtml(err.message)}</div>`;
882
  }
883
  }
884
 
 
900
  }
901
  }
902
 
903
+ // ==================== Menu CRUD ====================
904
  async function fetchCurrentMenu() {
905
  const tbody = document.getElementById('menuTableBody');
906
+ tbody.innerHTML = '<tr><td colspan="5" class="text-center py-8 text-ochre/60 text-xs">در حال بارگذاری منو...</td></tr>';
907
  try {
908
  const res = await fetch('/api/admin/menu');
909
  const menu = await res.json();
910
  if (res.ok && Array.isArray(menu)) {
911
  renderMenuTable(menu);
912
  } else {
913
+ tbody.innerHTML = '<tr><td colspan="5" class="text-center py-8 text-rug-light text-xs">خطا در بارگذاری منو</td></tr>';
914
  }
915
  } catch (e) {
916
+ tbody.innerHTML = '<tr><td colspan="5" class="text-center py-8 text-rug-light text-xs">عدم اتصال به سرور</td></tr>';
917
  }
918
  }
919
 
 
921
  const tbody = document.getElementById('menuTableBody');
922
  tbody.innerHTML = '';
923
  if (menu.length === 0) {
924
+ tbody.innerHTML = '<tr><td colspan="5" class="text-center py-8 text-ochre/60 text-xs">منو خالی است. آیتم جدید اضافه کنید.</td></tr>';
925
  return;
926
  }
927
  menu.forEach(item => {
928
  const row = document.createElement('tr');
929
+ row.className = 'menu-row';
930
  row.dataset.id = item.id;
931
  row.innerHTML = `
932
+ <td class="px-2 py-2">
933
+ <span class="view-mode font-bold text-cream">${escapeHtml(item.name)}</span>
934
+ <input type="text" class="edit-mode hidden w-full bg-azure-950/60 border border-azure-700/40 rounded px-2 py-1 text-cream text-[11px]" value="${escapeHtml(item.name)}" data-field="name">
935
  </td>
936
+ <td class="px-2 py-2 hidden md:table-cell">
937
+ <span class="view-mode text-cream/60 text-[10px]">${escapeHtml(item.description || '-')}</span>
938
+ <input type="text" class="edit-mode hidden w-full bg-azure-950/60 border border-azure-700/40 rounded px-2 py-1 text-cream text-[11px]" value="${escapeHtml(item.description || '')}" data-field="description">
939
  </td>
940
+ <td class="px-2 py-2">
941
+ <span class="view-mode text-ochre-light font-medium">${escapeHtml(item.price || '-')}</span>
942
+ <input type="text" class="edit-mode hidden w-full bg-azure-950/60 border border-azure-700/40 rounded px-2 py-1 text-cream text-[11px]" value="${escapeHtml(item.price || '')}" data-field="price">
943
  </td>
944
+ <td class="px-2 py-2 text-center">
945
+ <span class="view-mode text-[10px] ${item.available ? 'text-emerald-light' : 'text-rug-light'} font-bold">${item.available ? '✓ موجود' : '✗ ناموجود'}</span>
946
+ <div class="edit-mode hidden flex items-center justify-center">
947
+ <input type="checkbox" data-field="available" ${item.available ? 'checked' : ''}>
948
+ </div>
949
  </td>
950
+ <td class="px-2 py-2 text-center">
951
  <div class="view-mode flex gap-1 justify-center">
952
+ <button onclick="editMenuItem(this)" class="p-1.5 text-turk/70 hover:text-ochre-light transition-colors rounded-lg hover:bg-bazaar-800/50" title="ویرایش">
953
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
954
+ <path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
955
  </svg>
956
  </button>
957
+ <button onclick="deleteMenuItem(${item.id})" class="p-1.5 text-cream/30 hover:text-rug-light transition-colors rounded-lg hover:bg-bazaar-800/50" title="حذف">
958
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
959
+ <path stroke-linecap="round" stroke-linejoin="round" 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"/>
960
  </svg>
961
  </button>
962
  </div>
963
  <div class="edit-mode hidden flex gap-1 justify-center">
964
+ <button onclick="saveMenuItem(this, ${item.id})" class="px-2.5 py-1 bg-emerald-dark/40 border border-emerald-light/40 text-emerald-light rounded-md text-[10px] font-bold hover:bg-emerald-dark/60">ذخیره</button>
965
+ <button onclick="cancelEdit(this)" class="px-2.5 py-1 bg-bazaar-800 border border-ochre/20 text-cream/60 rounded-md text-[10px] hover:border-ochre/40">لغو</button>
966
  </div>
967
  </td>
968
  `;
 
987
  }
988
 
989
  function cancelEdit(btn) {
 
 
 
990
  fetchCurrentMenu();
991
  }
992
 
 
1039
  }
1040
  }
1041
 
1042
+ function addMenuItemRow() {
 
1043
  const tbody = document.getElementById('menuTableBody');
1044
  const row = document.createElement('tr');
1045
+ row.className = 'menu-row bg-bazaar-800/40';
1046
  row.innerHTML = `
1047
+ <td class="px-2 py-2">
1048
+ <input type="text" class="w-full bg-azure-950/60 border border-turk/40 rounded px-2 py-1 text-cream text-[11px]" placeholder="نام محصول" data-field="name">
1049
  </td>
1050
+ <td class="px-2 py-2 hidden md:table-cell">
1051
+ <input type="text" class="w-full bg-azure-950/60 border border-azure-700/40 rounded px-2 py-1 text-cream text-[11px]" placeholder="توضیحات" data-field="description">
1052
  </td>
1053
+ <td class="px-2 py-2">
1054
+ <input type="text" class="w-full bg-azure-950/60 border border-azure-700/40 rounded px-2 py-1 text-cream text-[11px]" placeholder="قیمت" data-field="price">
1055
  </td>
1056
+ <td class="px-2 py-2 text-center">
1057
  <input type="checkbox" data-field="available" checked>
1058
  </td>
1059
+ <td class="px-2 py-2 text-center">
1060
+ <button onclick="saveNewItem(this)" class="btn-turk px-3 py-1 rounded-md text-[10px]">افزودن</button>
1061
  </td>
1062
  `;
1063
  tbody.appendChild(row);
 
1090
  }
1091
  }
1092
 
1093
+ // ==================== Menu extraction ====================
1094
  function handleDragOver(e) {
1095
  e.preventDefault();
1096
  const dropZone = document.getElementById('dropZone');
1097
+ dropZone.classList.add('drag-over');
 
 
1098
  }
1099
  function handleDragLeave(e) {
1100
  e.preventDefault();
1101
  const dropZone = document.getElementById('dropZone');
1102
+ dropZone.classList.remove('drag-over');
 
 
1103
  }
1104
  function handleDrop(e) {
1105
  e.preventDefault();
 
1144
  tbody.innerHTML = '';
1145
  menuItems.forEach((item, index) => {
1146
  const row = `
1147
+ <tr class="menu-row">
1148
  <td class="px-2 py-2">
1149
+ <input type="text" class="menu-name w-full bg-azure-950/60 border border-azure-700/40 rounded-lg px-2.5 py-1.5 text-cream focus:border-ochre/50 text-[11px]" value="${escapeHtml(item.name || '')}">
1150
  </td>
1151
  <td class="px-2 py-2">
1152
+ <input type="text" class="menu-desc w-full bg-azure-950/60 border border-azure-700/40 rounded-lg px-2.5 py-1.5 text-cream focus:border-ochre/50 text-[11px]" value="${escapeHtml(item.description || '')}">
1153
  </td>
1154
  <td class="px-2 py-2">
1155
+ <input type="text" class="menu-price w-full bg-azure-950/60 border border-azure-700/40 rounded-lg px-2.5 py-1.5 text-cream focus:border-ochre/50 text-[11px]" value="${escapeHtml(item.price || '')}">
1156
  </td>
1157
  <td class="px-2 py-2 text-center">
1158
+ <button onclick="removeMenuRow(this)" class="p-1.5 text-cream/30 hover:text-rug-light transition-colors rounded-lg hover:bg-bazaar-800/50">
1159
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
1160
+ <path stroke-linecap="round" stroke-linejoin="round" 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"/>
1161
  </svg>
1162
  </button>
1163
  </td>
 
1169
  function addEmptyMenuRow() {
1170
  const tbody = document.getElementById('menuEditorTableBody');
1171
  const row = `
1172
+ <tr class="menu-row">
1173
  <td class="px-2 py-2">
1174
+ <input type="text" class="menu-name w-full bg-azure-950/60 border border-azure-700/40 rounded-lg px-2.5 py-1.5 text-cream focus:border-ochre/50 text-[11px]" placeholder="مثال: لاته کارامل">
1175
  </td>
1176
  <td class="px-2 py-2">
1177
+ <input type="text" class="menu-desc w-full bg-azure-950/60 border border-azure-700/40 rounded-lg px-2.5 py-1.5 text-cream focus:border-ochre/50 text-[11px]" placeholder="ترکیب اسپرسو دبل، سس کارامل و فوم شیر">
1178
  </td>
1179
  <td class="px-2 py-2">
1180
+ <input type="text" class="menu-price w-full bg-azure-950/60 border border-azure-700/40 rounded-lg px-2.5 py-1.5 text-cream focus:border-ochre/50 text-[11px]" placeholder="۸۵,۰۰۰">
1181
  </td>
1182
  <td class="px-2 py-2 text-center">
1183
+ <button onclick="removeMenuRow(this)" class="p-1.5 text-cream/30 hover:text-rug-light transition-colors rounded-lg hover:bg-bazaar-800/50">
1184
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
1185
+ <path stroke-linecap="round" stroke-linejoin="round" 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"/>
1186
  </svg>
1187
  </button>
1188
  </td>
 
1217
  });
1218
  const data = await response.json();
1219
  if (response.ok && data.success) {
1220
+ alert("منوی جدید با موفقیت ثبت و روی وب‌سایت همگام‌سازی شد!");
1221
  document.getElementById('menuEditorContainer').classList.add('hidden');
1222
+ fetchCurrentMenu();
1223
+ appendChatMessage('model', '✅ **منوی زنده همگام‌سازی شد.** سیستم سفارش‌گیری مشتریان اکنون بر مبنای آخرین لیست ویرایش‌شده کالیبره شده است.');
1224
  } else {
1225
  alert(data.error || 'بروز خطا در همگام‌سازی ساختار داده‌های جدید.');
1226
  }
 
1229
  }
1230
  }
1231
 
1232
+ // ==================== Admin Chat ====================
1233
  async function sendAdminMessage(e) {
1234
  e.preventDefault();
1235
  if (isGenerating) return;
 
1257
  isGenerating = false;
1258
 
1259
  if (response.ok && data.success) {
1260
+ const botBubbleId = appendChatMessage('model', '');
1261
  const botBubble = document.getElementById(botBubbleId);
1262
  const textResponse = data.response;
1263
  let i = 0;
 
1264
  function typeText() {
1265
  if (i < textResponse.length && !abortController.signal.aborted) {
1266
  botBubble.textContent += textResponse.charAt(i);
 
1268
  document.getElementById('chatMessages').scrollTop = document.getElementById('chatMessages').scrollHeight;
1269
  setTimeout(typeText, 6);
1270
  } else {
1271
+ botBubble.textContent = '';
 
1272
  botBubble.innerHTML = marked.parse(textResponse);
1273
  chatHistory.push({ role: 'model', content: textResponse });
 
1274
  fetchCurrentMenu();
1275
  }
1276
  }
 
1282
  toggleChatLoading(false);
1283
  isGenerating = false;
1284
  if (err.name !== 'AbortError') {
1285
+ appendChatMessage('model', 'عدم دریافت موفق پاسخ در بستر شبکه: ' + escapeHtml(err.message));
1286
  }
1287
  }
1288
  }
 
1312
 
1313
  function appendChatMessage(role, content) {
1314
  const container = document.getElementById('chatMessages');
1315
+ const bubbleId = 'bubble-admin-' + Date.now() + '-' + Math.random().toString(36).substr(2, 5);
1316
  let html = '';
1317
 
1318
  if (role === 'user') {
1319
  html = `
1320
  <div class="flex justify-end gap-2.5 max-w-[85%] mr-auto">
1321
+ <div class="bg-gradient-to-br from-rug/20 to-rug-dark/30 border border-rug/30 text-cream text-xs rounded-2xl rounded-tl-none px-3.5 py-2.5 leading-relaxed shadow-inner-soft">
1322
  ${escapeHtml(content)}
1323
  </div>
1324
+ <div class="w-8 h-8 rounded-xl bg-gradient-to-br from-ochre/30 to-rug/20 border border-ochre/40 flex items-center justify-center flex-shrink-0">
1325
+ <svg class="w-4 h-4 text-ochre-light" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
1326
+ <path stroke-linecap="round" stroke-linejoin="round" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/>
1327
+ </svg>
1328
+ </div>
1329
  </div>
1330
  `;
1331
  } else {
 
 
1332
  html = `
1333
  <div class="flex gap-2.5 max-w-[85%]">
1334
+ <div class="w-8 h-8 rounded-xl bg-gradient-to-br from-turk/20 to-azure-700/20 border border-turk/30 flex items-center justify-center flex-shrink-0">
1335
+ <span class="text-ochre-light font-display text-[11px]">ن</span>
1336
  </div>
1337
+ <div id="${bubbleId}" class="bg-bazaar-950/70 border border-ochre/20 text-cream text-xs rounded-2xl rounded-tr-none px-3.5 py-2.5 leading-relaxed shadow-inner-soft chat-markdown">
1338
  ${content ? marked.parse(content) : ''}
1339
  </div>
1340
  </div>