wop commited on
Commit
e540ed7
·
verified ·
1 Parent(s): b259315

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +244 -19
index.html CHANGED
@@ -1,19 +1,244 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Amber Chat Visualizer</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <style>
9
+ /* Custom Yellow Grayscale Palette */
10
+ :root {
11
+ --amber-50: #fffbeb;
12
+ --amber-100: #fef3c7;
13
+ --amber-200: #fde68a;
14
+ --amber-300: #fcd34d;
15
+ --amber-400: #fbbf24;
16
+ --amber-500: #f59e0b;
17
+ --amber-600: #d97706;
18
+ --amber-700: #b45309;
19
+ --amber-800: #92400e;
20
+ --amber-900: #78350f;
21
+ --amber-950: #1a1405; /* Deep warm black */
22
+ }
23
+
24
+ body {
25
+ background-color: var(--amber-950);
26
+ color: var(--amber-200);
27
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
28
+ }
29
+
30
+ .custom-scrollbar::-webkit-scrollbar {
31
+ width: 6px;
32
+ }
33
+ .custom-scrollbar::-webkit-scrollbar-track {
34
+ background: transparent;
35
+ }
36
+ .custom-scrollbar::-webkit-scrollbar-thumb {
37
+ background: rgba(245, 158, 11, 0.2);
38
+ border-radius: 10px;
39
+ }
40
+
41
+ .editable:focus {
42
+ outline: none;
43
+ border-bottom: 1px solid var(--amber-500);
44
+ background: rgba(245, 158, 11, 0.1);
45
+ }
46
+
47
+ /* Logic for mobile/desktop layout */
48
+ .main-container {
49
+ height: calc(100vh - 100px);
50
+ }
51
+
52
+ @media (max-width: 768px) {
53
+ .main-container {
54
+ flex-direction: column;
55
+ overflow-y: auto;
56
+ }
57
+ .panel {
58
+ height: 500px;
59
+ width: 100% !important;
60
+ flex-shrink: 0;
61
+ }
62
+ }
63
+ </style>
64
+ </head>
65
+ <body class="flex flex-col h-screen overflow-hidden">
66
+
67
+ <!-- Header -->
68
+ <header class="flex items-center justify-between px-6 py-4 border-b border-amber-900/50 bg-amber-950 shadow-lg">
69
+ <div class="flex items-center space-x-3">
70
+ <div class="bg-amber-500/20 p-2 rounded-lg">
71
+ <svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 text-amber-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
72
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z" />
73
+ </svg>
74
+ </div>
75
+ <h1 class="text-xl font-bold tracking-tight text-amber-400">Amber Chat <span class="text-amber-700 font-light">Visualizer</span></h1>
76
+ </div>
77
+ <div class="flex items-center gap-4 text-xs font-mono text-amber-700">
78
+ <span class="hidden sm:inline">JSON + VISUAL SYNC</span>
79
+ <button onclick="copyJson()" class="p-2 hover:bg-amber-500/10 rounded-full transition-colors text-amber-500">
80
+ <svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
81
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3" />
82
+ </svg>
83
+ </button>
84
+ </div>
85
+ </header>
86
+
87
+ <!-- Main Content -->
88
+ <main class="main-container flex-1 flex overflow-hidden">
89
+
90
+ <!-- Editor Panel -->
91
+ <section class="panel w-1/2 flex flex-col bg-black/40 border-r border-amber-900/30">
92
+ <div class="px-4 py-2 bg-amber-950/80 border-b border-amber-900/30 flex justify-between items-center">
93
+ <span class="text-[10px] font-mono uppercase tracking-widest text-amber-700">source.json</span>
94
+ <span id="json-error" class="text-[10px] text-red-500 hidden">Invalid JSON</span>
95
+ </div>
96
+ <textarea id="json-editor"
97
+ class="flex-1 p-6 bg-transparent text-amber-500 font-mono text-sm outline-none resize-none custom-scrollbar"
98
+ spellcheck="false"></textarea>
99
+ </section>
100
+
101
+ <!-- Preview Panel -->
102
+ <section id="chat-preview" class="panel w-1/2 overflow-y-auto p-6 md:p-12 bg-amber-950/20 custom-scrollbar">
103
+ <!-- Bubbles injected here -->
104
+ </section>
105
+
106
+ </main>
107
+
108
+ <!-- Footer -->
109
+ <footer class="h-10 border-t border-amber-900/30 flex items-center justify-between px-6 bg-amber-950 text-[10px] uppercase tracking-widest text-amber-800">
110
+ <div>Click text to edit visually</div>
111
+ <div>Grayscale Yellow Tint Mode</div>
112
+ </footer>
113
+
114
+ <script>
115
+ const jsonEditor = document.getElementById('json-editor');
116
+ const chatPreview = document.getElementById('chat-preview');
117
+ const errorLabel = document.getElementById('json-error');
118
+
119
+ let data = {
120
+ "messages": [
121
+ { "role": "system", "content": "You are a helpful assistant." },
122
+ { "role": "user", "content": "Tell me about this yellow theme." },
123
+ { "role": "assistant", "content": "<think>The user is noticing the monochrome amber palette. I should explain that it's designed for focus and health.</think>This is a yellow-tint grayscale theme. By removing blue light and focusing on amber tones, it aims to be much easier on your eyes during long coding sessions." }
124
+ ]
125
+ };
126
+
127
+ // Initialize
128
+ jsonEditor.value = JSON.stringify(data, null, 2);
129
+ renderChat();
130
+
131
+ // Listen for JSON changes
132
+ jsonEditor.addEventListener('input', (e) => {
133
+ try {
134
+ const parsed = JSON.parse(e.target.value);
135
+ if (parsed.messages && Array.isArray(parsed.messages)) {
136
+ data = parsed;
137
+ renderChat();
138
+ errorLabel.classList.add('hidden');
139
+ }
140
+ } catch (err) {
141
+ errorLabel.classList.remove('hidden');
142
+ }
143
+ });
144
+
145
+ function renderChat() {
146
+ chatPreview.innerHTML = '';
147
+ data.messages.forEach((msg, index) => {
148
+ const bubble = createBubble(msg, index);
149
+ chatPreview.appendChild(bubble);
150
+ });
151
+ }
152
+
153
+ function createBubble(msg, index) {
154
+ const isUser = msg.role.toLowerCase() === 'user';
155
+ const isAssistant = msg.role.toLowerCase() === 'assistant';
156
+ const isSystem = msg.role.toLowerCase() === 'system';
157
+
158
+ const container = document.createElement('div');
159
+ container.className = `flex flex-col mb-8 w-full ${isUser ? 'items-end' : 'items-start'}`;
160
+
161
+ // Role label
162
+ const label = document.createElement('div');
163
+ label.contentEditable = true;
164
+ label.className = `text-[10px] font-bold uppercase tracking-widest mb-1 px-1 outline-none ${isUser ? 'text-amber-400' : 'text-amber-700'}`;
165
+ label.innerText = msg.role;
166
+ label.onblur = (e) => updateData(index, 'role', e.target.innerText);
167
+
168
+ // Bubble body
169
+ const body = document.createElement('div');
170
+ const bubbleClasses = isUser
171
+ ? 'bg-amber-600 text-amber-950 rounded-br-none font-medium'
172
+ : isSystem
173
+ ? 'bg-amber-900/20 border border-amber-900/50 text-amber-600 italic text-center w-full max-w-none text-sm'
174
+ : 'bg-amber-900/40 border border-amber-800/50 text-amber-100 rounded-bl-none';
175
+
176
+ body.className = `max-w-[90%] md:max-w-[85%] rounded-2xl px-5 py-3 shadow-lg ${bubbleClasses}`;
177
+
178
+ // Handle thought tags
179
+ const content = msg.content || "";
180
+ const thinkMatch = content.match(/<think>([\s\S]*?)<\/think>/);
181
+ const thoughtText = thinkMatch ? thinkMatch[1] : "";
182
+ const cleanText = content.replace(/<think>[\s\S]*?<\/think>/, '').trim();
183
+
184
+ if (isAssistant || thoughtText) {
185
+ const details = document.createElement('details');
186
+ details.open = !!thoughtText;
187
+ details.className = 'mb-3 bg-black/30 rounded-lg border border-amber-900/50 overflow-hidden';
188
+
189
+ const summary = document.createElement('summary');
190
+ summary.className = 'cursor-pointer p-2 text-[10px] font-bold text-amber-700 hover:bg-amber-500/5 flex items-center select-none outline-none';
191
+ summary.innerHTML = `<span class="mr-1">▶</span> THOUGHT PROCESS`;
192
+
193
+ const thoughtDiv = document.createElement('div');
194
+ thoughtDiv.contentEditable = true;
195
+ thoughtDiv.className = 'p-3 text-xs text-amber-500/70 border-t border-amber-900/50 outline-none leading-relaxed';
196
+ thoughtDiv.innerText = thoughtText;
197
+ thoughtDiv.onblur = (e) => updateData(index, 'thought', e.target.innerText);
198
+
199
+ details.appendChild(summary);
200
+ details.appendChild(thoughtDiv);
201
+ body.appendChild(details);
202
+ }
203
+
204
+ const mainText = document.createElement('div');
205
+ mainText.contentEditable = true;
206
+ mainText.className = 'outline-none whitespace-pre-wrap leading-relaxed text-sm md:text-base';
207
+ mainText.innerText = cleanText;
208
+ mainText.onblur = (e) => updateData(index, 'content', e.target.innerText);
209
+
210
+ body.appendChild(mainText);
211
+ container.appendChild(label);
212
+ container.appendChild(body);
213
+ return container;
214
+ }
215
+
216
+ function updateData(index, field, value) {
217
+ const msg = data.messages[index];
218
+ if (field === 'role') {
219
+ msg.role = value;
220
+ } else if (field === 'thought') {
221
+ const currentContent = msg.content || "";
222
+ const cleanPart = currentContent.replace(/<think>[\s\S]*?<\/think>/, '').trim();
223
+ msg.content = `<think>${value}</think>${cleanPart}`;
224
+ } else if (field === 'content') {
225
+ const currentContent = msg.content || "";
226
+ const thinkMatch = currentContent.match(/<think>([\s\S]*?)<\/think>/);
227
+ const thinkPart = thinkMatch ? `<think>${thinkMatch[1]}</think>` : "";
228
+ msg.content = thinkPart + value;
229
+ }
230
+
231
+ jsonEditor.value = JSON.stringify(data, null, 2);
232
+ }
233
+
234
+ function copyJson() {
235
+ jsonEditor.select();
236
+ document.execCommand('copy');
237
+ const btn = document.querySelector('button[onclick="copyJson()"]');
238
+ const original = btn.innerHTML;
239
+ btn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" /></svg>`;
240
+ setTimeout(() => btn.innerHTML = original, 2000);
241
+ }
242
+ </script>
243
+ </body>
244
+ </html>