akhaliq HF Staff commited on
Commit
1002db5
·
verified ·
1 Parent(s): 150e09e

Upload folder using huggingface_hub

Browse files
package.json CHANGED
@@ -1,5 +1,5 @@
1
  {
2
- "name": "svelte",
3
  "private": true,
4
  "version": "0.0.0",
5
  "type": "module",
@@ -7,14 +7,18 @@
7
  "dev": "vite",
8
  "build": "vite build",
9
  "preview": "vite preview",
10
- "check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json"
11
  },
12
  "devDependencies": {
13
- "@sveltejs/vite-plugin-svelte": "^5.0.3",
14
- "@tsconfig/svelte": "^5.0.4",
15
- "svelte": "^5.28.1",
16
- "svelte-check": "^4.1.6",
17
- "typescript": "~5.8.3",
18
- "vite": "^6.3.5"
 
 
 
 
19
  }
20
  }
 
1
  {
2
+ "name": "gradio-dataframe-demo",
3
  "private": true,
4
  "version": "0.0.0",
5
  "type": "module",
 
7
  "dev": "vite",
8
  "build": "vite build",
9
  "preview": "vite preview",
10
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json"
11
  },
12
  "devDependencies": {
13
+ "@sveltejs/vite-plugin-svelte": "^3.0.0",
14
+ "@tsconfig/svelte": "^5.0.0",
15
+ "svelte": "^4.2.0",
16
+ "svelte-check": "^3.6.0",
17
+ "tslib": "^2.6.0",
18
+ "typescript": "^5.2.0",
19
+ "vite": "^5.0.0"
20
+ },
21
+ "dependencies": {
22
+ "@gradio/dataframe": "^0.19.1"
23
  }
24
  }
src/App.svelte CHANGED
@@ -1,47 +1,308 @@
1
  <script lang="ts">
2
- import svelteLogo from './assets/svelte.svg'
3
- import viteLogo from '/vite.svg'
4
- import Counter from './lib/Counter.svelte'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  </script>
6
 
7
- <main>
8
- <div>
9
- <a href="https://vite.dev" target="_blank" rel="noreferrer">
10
- <img src={viteLogo} class="logo" alt="Vite Logo" />
11
- </a>
12
- <a href="https://svelte.dev" target="_blank" rel="noreferrer">
13
- <img src={svelteLogo} class="logo svelte" alt="Svelte Logo" />
14
- </a>
15
- </div>
16
- <h1>Vite + Svelte</h1>
17
 
18
- <div class="card">
19
- <Counter />
20
- </div>
 
21
 
22
- <p>
23
- Check out <a href="https://github.com/sveltejs/kit#readme" target="_blank" rel="noreferrer">SvelteKit</a>, the official Svelte app framework powered by Vite!
24
- </p>
 
 
 
 
 
 
 
 
25
 
26
- <p class="read-the-docs">
27
- Click on the Vite and Svelte logos to learn more
28
- </p>
29
- </main>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
  <style>
32
- .logo {
33
- height: 6em;
34
- padding: 1.5em;
35
- will-change: filter;
36
- transition: filter 300ms;
37
  }
38
- .logo:hover {
39
- filter: drop-shadow(0 0 2em #646cffaa);
 
 
 
 
40
  }
41
- .logo.svelte:hover {
42
- filter: drop-shadow(0 0 2em #ff3e00aa);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  }
44
- .read-the-docs {
45
- color: #888;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  }
47
- </style>
 
1
  <script lang="ts">
2
+ import Dataframe from "@gradio/dataframe";
3
+ import ConfigPanel from "./components/ConfigPanel.svelte";
4
+ import EventLog from "./components/EventLog.svelte";
5
+ import { dataframeConfig, eventLog } from "./stores/config";
6
+
7
+ // Sample data
8
+ let value = {
9
+ data: [
10
+ ["Alice Johnson", 28, true, "2024-01-15", "**Senior** Developer", "<em>Tech Corp</em>"],
11
+ ["Bob Smith", 35, false, "2023-11-20", "*Team Lead*", "<strong>Data Inc</strong>"],
12
+ ["Charlie Brown", 42, true, "2023-08-10", "Product Manager", "StartUp Co"],
13
+ ["Diana Prince", 31, true, "2024-02-28", "**UX Designer**", "<span style='color: blue;'>Design Studio</span>"],
14
+ ["Eve Wilson", 26, false, "2023-12-05", "Junior Developer", "Web Solutions"],
15
+ ["Frank Miller", 39, true, "2023-09-15", "*DevOps* Engineer", "<code>Cloud Systems</code>"],
16
+ ["Grace Lee", 33, true, "2024-01-10", "Data Scientist", "AI Labs"],
17
+ ["Henry Chen", 29, false, "2023-10-22", "**Backend** Developer", "<mark>Mobile Apps</mark>"],
18
+ ["Iris Taylor", 37, true, "2023-07-18", "Project Manager", "Enterprise Solutions"],
19
+ ["Jack Davis", 45, true, "2024-03-01", "*CTO*", "<strong>Innovation Hub</strong>"]
20
+ ],
21
+ headers: ["Name", "Age", "Active", "Join Date", "Role (Markdown)", "Company (HTML)"],
22
+ metadata: { last_updated: new Date().toISOString() }
23
+ };
24
+
25
+ // Configure datatypes for columns
26
+ $: datatype = [
27
+ "str", // Name
28
+ "number", // Age
29
+ "bool", // Active
30
+ "date", // Join Date
31
+ "markdown", // Role
32
+ "html" // Company
33
+ ];
34
+
35
+ // Column widths configuration
36
+ $: columnWidths = $dataframeConfig.useCustomWidths
37
+ ? ["200px", "80px", "100px", "150px", "180px", "200px"]
38
+ : undefined;
39
+
40
+ function handleChange(e: CustomEvent) {
41
+ $eventLog = [
42
+ {
43
+ type: "change",
44
+ detail: e.detail,
45
+ timestamp: new Date().toLocaleTimeString()
46
+ },
47
+ ...$eventLog.slice(0, 9)
48
+ ];
49
+ value = { ...e.detail };
50
+ }
51
+
52
+ function handleSelect(e: CustomEvent) {
53
+ $eventLog = [
54
+ {
55
+ type: "select",
56
+ detail: e.detail,
57
+ timestamp: new Date().toLocaleTimeString()
58
+ },
59
+ ...$eventLog.slice(0, 9)
60
+ ];
61
+ }
62
+
63
+ function handleInput(e: CustomEvent) {
64
+ $eventLog = [
65
+ {
66
+ type: "input",
67
+ detail: e.detail,
68
+ timestamp: new Date().toLocaleTimeString()
69
+ },
70
+ ...$eventLog.slice(0, 9)
71
+ ];
72
+ }
73
+
74
+ // Sample data sets for quick switching
75
+ function loadSampleData(type: string) {
76
+ switch(type) {
77
+ case 'small':
78
+ value = {
79
+ data: [
80
+ ["Item A", 10, true],
81
+ ["Item B", 20, false],
82
+ ["Item C", 30, true]
83
+ ],
84
+ headers: ["Name", "Value", "Enabled"],
85
+ metadata: { dataset: "small" }
86
+ };
87
+ break;
88
+ case 'large':
89
+ const largeData = [];
90
+ for (let i = 1; i <= 100; i++) {
91
+ largeData.push([
92
+ `User ${i}`,
93
+ Math.floor(Math.random() * 50) + 20,
94
+ Math.random() > 0.5,
95
+ new Date(2024, 0, Math.floor(Math.random() * 365)).toISOString().split('T')[0],
96
+ `Role ${Math.floor(Math.random() * 5) + 1}`,
97
+ `Company ${Math.floor(Math.random() * 10) + 1}`
98
+ ]);
99
+ }
100
+ value = {
101
+ data: largeData,
102
+ headers: ["Name", "Age", "Active", "Join Date", "Role", "Company"],
103
+ metadata: { dataset: "large", count: 100 }
104
+ };
105
+ break;
106
+ default:
107
+ // Reset to original
108
+ location.reload();
109
+ }
110
+ }
111
  </script>
112
 
113
+ <div class="app-container">
114
+ <header>
115
+ <h1>🎨 @gradio/dataframe Demo</h1>
116
+ <p>Interactive demonstration of the Gradio Dataframe component for Svelte</p>
117
+ </header>
 
 
 
 
 
118
 
119
+ <div class="main-layout">
120
+ <aside class="config-panel">
121
+ <ConfigPanel {loadSampleData} />
122
+ </aside>
123
 
124
+ <main class="dataframe-container">
125
+ <div class="dataframe-header">
126
+ <h2>📊 Dataframe Component</h2>
127
+ <div class="data-info">
128
+ <span>Rows: {value.data.length}</span>
129
+ <span>Columns: {value.headers.length}</span>
130
+ {#if value.metadata?.last_updated}
131
+ <span>Updated: {new Date(value.metadata.last_updated).toLocaleTimeString()}</span>
132
+ {/if}
133
+ </div>
134
+ </div>
135
 
136
+ <div class="dataframe-wrapper" class:custom-theme={$dataframeConfig.useCustomTheme}>
137
+ <Dataframe
138
+ bind:value
139
+ {datatype}
140
+ show_search={$dataframeConfig.showSearch}
141
+ show_row_numbers={$dataframeConfig.showRowNumbers}
142
+ show_copy_button={$dataframeConfig.showCopyButton}
143
+ show_fullscreen_button={$dataframeConfig.showFullscreenButton}
144
+ editable={$dataframeConfig.editable}
145
+ label={$dataframeConfig.showLabel ? "Employee Data Table" : null}
146
+ show_label={$dataframeConfig.showLabel}
147
+ column_widths={columnWidths}
148
+ max_height={$dataframeConfig.maxHeight}
149
+ max_chars={$dataframeConfig.maxChars}
150
+ line_breaks={$dataframeConfig.lineBreaks}
151
+ wrap={$dataframeConfig.wrap}
152
+ on:change={handleChange}
153
+ on:select={handleSelect}
154
+ on:input={handleInput}
155
+ />
156
+ </div>
157
+ </main>
158
+
159
+ <aside class="event-panel">
160
+ <EventLog />
161
+ </aside>
162
+ </div>
163
+
164
+ <footer>
165
+ <p>Built with Svelte + @gradio/dataframe | <a href="https://www.npmjs.com/package/@gradio/dataframe" target="_blank">View on npm</a></p>
166
+ </footer>
167
+ </div>
168
 
169
  <style>
170
+ .app-container {
171
+ min-height: 100vh;
172
+ display: flex;
173
+ flex-direction: column;
174
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
175
  }
176
+
177
+ header {
178
+ background: rgba(255, 255, 255, 0.95);
179
+ padding: 1.5rem;
180
+ text-align: center;
181
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
182
  }
183
+
184
+ header h1 {
185
+ margin: 0;
186
+ color: #333;
187
+ font-size: 2rem;
188
+ }
189
+
190
+ header p {
191
+ margin: 0.5rem 0 0;
192
+ color: #666;
193
+ }
194
+
195
+ .main-layout {
196
+ flex: 1;
197
+ display: grid;
198
+ grid-template-columns: 300px 1fr 350px;
199
+ gap: 1.5rem;
200
+ padding: 1.5rem;
201
+ max-width: 1600px;
202
+ margin: 0 auto;
203
+ width: 100%;
204
+ }
205
+
206
+ .config-panel, .event-panel, .dataframe-container {
207
+ background: white;
208
+ border-radius: 12px;
209
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
210
+ overflow: hidden;
211
+ }
212
+
213
+ .dataframe-container {
214
+ display: flex;
215
+ flex-direction: column;
216
  }
217
+
218
+ .dataframe-header {
219
+ padding: 1rem 1.5rem;
220
+ border-bottom: 1px solid #e5e7eb;
221
+ display: flex;
222
+ justify-content: space-between;
223
+ align-items: center;
224
+ }
225
+
226
+ .dataframe-header h2 {
227
+ margin: 0;
228
+ color: #333;
229
+ font-size: 1.25rem;
230
+ }
231
+
232
+ .data-info {
233
+ display: flex;
234
+ gap: 1rem;
235
+ font-size: 0.875rem;
236
+ color: #666;
237
+ }
238
+
239
+ .data-info span {
240
+ padding: 0.25rem 0.75rem;
241
+ background: #f3f4f6;
242
+ border-radius: 4px;
243
+ }
244
+
245
+ .dataframe-wrapper {
246
+ padding: 1.5rem;
247
+ flex: 1;
248
+ overflow: auto;
249
+ }
250
+
251
+ .dataframe-wrapper.custom-theme {
252
+ --gr-df-accent: #7c3aed;
253
+ --gr-df-accent-soft: #e9d5ff;
254
+ --gr-df-table-bg-even: #fafafa;
255
+ --gr-df-table-bg-odd: #ffffff;
256
+ --gr-df-table-border: #e5e7eb;
257
+ --gr-df-table-radius: 8px;
258
+ --gr-df-font-size: 14px;
259
+ }
260
+
261
+ footer {
262
+ background: rgba(0, 0, 0, 0.1);
263
+ color: white;
264
+ text-align: center;
265
+ padding: 1rem;
266
+ }
267
+
268
+ footer a {
269
+ color: white;
270
+ text-decoration: underline;
271
+ }
272
+
273
+ @media (max-width: 1200px) {
274
+ .main-layout {
275
+ grid-template-columns: 250px 1fr 300px;
276
+ }
277
+ }
278
+
279
+ @media (max-width: 968px) {
280
+ .main-layout {
281
+ grid-template-columns: 1fr;
282
+ }
283
+
284
+ .config-panel, .event-panel {
285
+ order: 2;
286
+ }
287
+
288
+ .dataframe-container {
289
+ order: 1;
290
+ }
291
+ }
292
+
293
+ @media (max-width: 640px) {
294
+ header h1 {
295
+ font-size: 1.5rem;
296
+ }
297
+
298
+ .main-layout {
299
+ padding: 1rem;
300
+ gap: 1rem;
301
+ }
302
+
303
+ .data-info {
304
+ flex-direction: column;
305
+ gap: 0.5rem;
306
+ }
307
  }
308
+ </style>
src/app.css CHANGED
@@ -1,25 +1,19 @@
1
  :root {
2
- font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
3
  line-height: 1.5;
4
  font-weight: 400;
5
-
6
- color-scheme: light dark;
7
- color: rgba(255, 255, 255, 0.87);
8
- background-color: #242424;
9
-
10
  font-synthesis: none;
11
  text-rendering: optimizeLegibility;
12
  -webkit-font-smoothing: antialiased;
13
  -moz-osx-font-smoothing: grayscale;
 
14
  }
15
 
16
- a {
17
- font-weight: 500;
18
- color: #646cff;
19
- text-decoration: inherit;
20
- }
21
- a:hover {
22
- color: #535bf2;
23
  }
24
 
25
  body {
@@ -28,52 +22,45 @@ body {
28
  place-items: center;
29
  min-width: 320px;
30
  min-height: 100vh;
 
31
  }
32
 
33
- h1 {
34
- font-size: 3.2em;
35
- line-height: 1.1;
36
  }
37
 
38
- .card {
39
- padding: 2em;
 
 
40
  }
41
 
42
- #app {
43
- max-width: 1280px;
44
- margin: 0 auto;
45
- padding: 2rem;
46
- text-align: center;
47
  }
48
 
49
- button {
50
- border-radius: 8px;
51
- border: 1px solid transparent;
52
- padding: 0.6em 1.2em;
53
- font-size: 1em;
54
- font-weight: 500;
55
- font-family: inherit;
56
- background-color: #1a1a1a;
57
- cursor: pointer;
58
- transition: border-color 0.25s;
59
  }
60
- button:hover {
61
- border-color: #646cff;
 
62
  }
63
- button:focus,
64
- button:focus-visible {
65
- outline: 4px auto -webkit-focus-ring-color;
 
 
66
  }
67
 
68
- @media (prefers-color-scheme: light) {
69
- :root {
70
- color: #213547;
71
- background-color: #ffffff;
 
 
72
  }
73
- a:hover {
74
- color: #747bff;
75
- }
76
- button {
77
- background-color: #f9f9f9;
78
- }
79
- }
 
1
  :root {
2
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
3
  line-height: 1.5;
4
  font-weight: 400;
5
+ color-scheme: light;
 
 
 
 
6
  font-synthesis: none;
7
  text-rendering: optimizeLegibility;
8
  -webkit-font-smoothing: antialiased;
9
  -moz-osx-font-smoothing: grayscale;
10
+ -webkit-text-size-adjust: 100%;
11
  }
12
 
13
+ * {
14
+ margin: 0;
15
+ padding: 0;
16
+ box-sizing: border-box;
 
 
 
17
  }
18
 
19
  body {
 
22
  place-items: center;
23
  min-width: 320px;
24
  min-height: 100vh;
25
+ background: #f3f4f6;
26
  }
27
 
28
+ #app {
29
+ width: 100%;
30
+ min-height: 100vh;
31
  }
32
 
33
+ /* Scrollbar styling */
34
+ ::-webkit-scrollbar {
35
+ width: 8px;
36
+ height: 8px;
37
  }
38
 
39
+ ::-webkit-scrollbar-track {
40
+ background: #f1f1f1;
41
+ border-radius: 4px;
 
 
42
  }
43
 
44
+ ::-webkit-scrollbar-thumb {
45
+ background: #888;
46
+ border-radius: 4px;
 
 
 
 
 
 
 
47
  }
48
+
49
+ ::-webkit-scrollbar-thumb:hover {
50
+ background: #555;
51
  }
52
+
53
+ /* Accessibility */
54
+ :focus-visible {
55
+ outline: 2px solid #667eea;
56
+ outline-offset: 2px;
57
  }
58
 
59
+ /* Responsive utilities */
60
+ @media (prefers-reduced-motion: reduce) {
61
+ * {
62
+ animation-duration: 0.01ms !important;
63
+ animation-iteration-count: 1 !important;
64
+ transition-duration: 0.01ms !important;
65
  }
66
+ }
 
 
 
 
 
 
src/components/ConfigPanel.svelte ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { dataframeConfig } from "../stores/config";
3
+
4
+ export let loadSampleData: (type: string) => void;
5
+ </script>
6
+
7
+ <div class="panel">
8
+ <h3>⚙️ Configuration</h3>
9
+
10
+ <div class="section">
11
+ <h4>Display Options</h4>
12
+
13
+ <label>
14
+ <input type="checkbox" bind:checked={$dataframeConfig.showRowNumbers} />
15
+ Show Row Numbers
16
+ </label>
17
+
18
+ <label>
19
+ <input type="checkbox" bind:checked={$dataframeConfig.showCopyButton} />
20
+ Show Copy Button
21
+ </label>
22
+
23
+ <label>
24
+ <input type="checkbox" bind:checked={$dataframeConfig.showFullscreenButton} />
25
+ Show Fullscreen Button
26
+ </label>
27
+
28
+ <label>
29
+ <input type="checkbox" bind:checked={$dataframeConfig.showLabel} />
30
+ Show Label
31
+ </label>
32
+
33
+ <label>
34
+ <input type="checkbox" bind:checked={$dataframeConfig.editable} />
35
+ Editable Cells
36
+ </label>
37
+ </div>
38
+
39
+ <div class="section">
40
+ <h4>Search/Filter</h4>
41
+ <select bind:value={$dataframeConfig.showSearch}>
42
+ <option value="none">None</option>
43
+ <option value="search">Search</option>
44
+ <option value="filter">Filter</option>
45
+ </select>
46
+ </div>
47
+
48
+ <div class="section">
49
+ <h4>Layout Options</h4>
50
+
51
+ <label>
52
+ <input type="checkbox" bind:checked={$dataframeConfig.lineBreaks} />
53
+ Line Breaks
54
+ </label>
55
+
56
+ <label>
57
+ <input type="checkbox" bind:checked={$dataframeConfig.wrap} />
58
+ Text Wrap
59
+ </label>
60
+
61
+ <label>
62
+ <input type="checkbox" bind:checked={$dataframeConfig.useCustomWidths} />
63
+ Custom Column Widths
64
+ </label>
65
+
66
+ <label>
67
+ Max Height (px)
68
+ <input type="number" bind:value={$dataframeConfig.maxHeight} min="200" max="1000" step="50" />
69
+ </label>
70
+
71
+ <label>
72
+ Max Characters
73
+ <input type="number" bind:value={$dataframeConfig.maxChars} min="10" max="200" step="10" />
74
+ </label>
75
+ </div>
76
+
77
+ <div class="section">
78
+ <h4>Theme</h4>
79
+ <label>
80
+ <input type="checkbox" bind:checked={$dataframeConfig.useCustomTheme} />
81
+ Use Custom Theme
82
+ </label>
83
+ </div>
84
+
85
+ <div class="section">
86
+ <h4>Sample Data</h4>
87
+ <div class="button-group">
88
+ <button on:click={() => loadSampleData('small')}>Small Dataset</button>
89
+ <button on:click={() => loadSampleData('large')}>Large Dataset (100 rows)</button>
90
+ <button on:click={() => loadSampleData('default')}>Reset Data</button>
91
+ </div>
92
+ </div>
93
+ </div>
94
+
95
+ <style>
96
+ .panel {
97
+ padding: 1.5rem;
98
+ }
99
+
100
+ h3 {
101
+ margin: 0 0 1.5rem;
102
+ color: #333;
103
+ font-size: 1.25rem;
104
+ }
105
+
106
+ .section {
107
+ margin-bottom: 1.5rem;
108
+ padding-bottom: 1.5rem;
109
+ border-bottom: 1px solid #e5e7eb;
110
+ }
111
+
112
+ .section:last-child {
113
+ border-bottom: none;
114
+ }
115
+
116
+ h4 {
117
+ margin: 0 0 0.75rem;
118
+ color: #666;
119
+ font-size: 0.875rem;
120
+ font-weight: 600;
121
+ text-transform: uppercase;
122
+ letter-spacing: 0.5px;
123
+ }
124
+
125
+ label {
126
+ display: flex;
127
+ align-items: center;
128
+ margin-bottom: 0.5rem;
129
+ font-size: 0.875rem;
130
+ color: #333;
131
+ cursor: pointer;
132
+ }
133
+
134
+ input[type="checkbox"] {
135
+ margin-right: 0.5rem;
136
+ }
137
+
138
+ input[type="number"], select {
139
+ width: 100%;
140
+ padding: 0.375rem 0.5rem;
141
+ border: 1px solid #d1d5db;
142
+ border-radius: 4px;
143
+ font-size: 0.875rem;
144
+ margin-top: 0.25rem;
145
+ }
146
+
147
+ .button-group {
148
+ display: flex;
149
+ flex-direction: column;
150
+ gap: 0.5rem;
151
+ }
152
+
153
+ button {
154
+ padding: 0.5rem 1rem;
155
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
156
+ color: white;
157
+ border: none;
158
+ border-radius: 6px;
159
+ font-size: 0.875rem;
160
+ cursor: pointer;
161
+ transition: transform 0.2s, box-shadow 0.2s;
162
+ }
163
+
164
+ button:hover {
165
+ transform: translateY(-2px);
166
+ box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
167
+ }
168
+
169
+ button:active {
170
+ transform: translateY(0);
171
+ }
172
+ </style>
src/components/EventLog.svelte ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { eventLog } from "../stores/config";
3
+
4
+ function clearLog() {
5
+ $eventLog = [];
6
+ }
7
+
8
+ function getEventIcon(type: string) {
9
+ switch(type) {
10
+ case 'change': return '✏️';
11
+ case 'select': return '👆';
12
+ case 'input': return '🔍';
13
+ default: return '📝';
14
+ }
15
+ }
16
+
17
+ function formatDetail(detail: any) {
18
+ if (typeof detail === 'string' || detail === null) {
19
+ return detail || 'null';
20
+ }
21
+ return JSON.stringify(detail, null, 2);
22
+ }
23
+ </script>
24
+
25
+ <div class="panel">
26
+ <div class="header">
27
+ <h3>📋 Event Log</h3>
28
+ <button on:click={clearLog} class="clear-btn">Clear</button>
29
+ </div>
30
+
31
+ <div class="events">
32
+ {#if $eventLog.length === 0}
33
+ <div class="empty">
34
+ <p>No events yet</p>
35
+ <p class="hint">Try interacting with the dataframe!</p>
36
+ </div>
37
+ {:else}
38
+ {#each $eventLog as event}
39
+ <div class="event event-{event.type}">
40
+ <div class="event-header">
41
+ <span class="event-icon">{getEventIcon(event.type)}</span>
42
+ <span class="event-type">{event.type}</span>
43
+ <span class="event-time">{event.timestamp}</span>
44
+ </div>
45
+ <div class="event-detail">
46
+ <pre>{formatDetail(event.detail)}</pre>
47
+ </div>
48
+ </div>
49
+ {/each}
50
+ {/if}
51
+ </div>
52
+ </div>
53
+
54
+ <style>
55
+ .panel {
56
+ padding: 1.5rem;
57
+ display: flex;
58
+ flex-direction: column;
59
+ height: 100%;
60
+ }
61
+
62
+ .header {
63
+ display: flex;
64
+ justify-content: space-between;
65
+ align-items: center;
66
+ margin-bottom: 1rem;
67
+ }
68
+
69
+ h3 {
70
+ margin: 0;
71
+ color: #333;
72
+ font-size: 1.25rem;
73
+ }
74
+
75
+ .clear-btn {
76
+ padding: 0.25rem 0.75rem;
77
+ background: #ef4444;
78
+ color: white;
79
+ border: none;
80
+ border-radius: 4px;
81
+ font-size: 0.75rem;
82
+ cursor: pointer;
83
+ transition: background 0.2s;
84
+ }
85
+
86
+ .clear-btn:hover {
87
+ background: #dc2626;
88
+ }
89
+
90
+ .events {
91
+ flex: 1;
92
+ overflow-y: auto;
93
+ display: flex;
94
+ flex-direction: column;
95
+ gap: 0.75rem;
96
+ }
97
+
98
+ .empty {
99
+ text-align: center;
100
+ padding: 2rem;
101
+ color: #9ca3af;
102
+ }
103
+
104
+ .empty p {
105
+ margin: 0;
106
+ }
107
+
108
+ .hint {
109
+ margin-top: 0.5rem !important;
110
+ font-size: 0.875rem;
111
+ }
112
+
113
+ .event {
114
+ background: #f9fafb;
115
+ border-radius: 6px;
116
+ padding: 0.75rem;
117
+ border-left: 3px solid;
118
+ }
119
+
120
+ .event-change {
121
+ border-color: #10b981;
122
+ }
123
+
124
+ .event-select {
125
+ border-color: #3b82f6;
126
+ }
127
+
128
+ .event-input {
129
+ border-color: #f59e0b;
130
+ }
131
+
132
+ .event-header {
133
+ display: flex;
134
+ align-items: center;
135
+ gap: 0.5rem;
136
+ margin-bottom: 0.5rem;
137
+ }
138
+
139
+ .event-icon {
140
+ font-size: 1rem;
141
+ }
142
+
143
+ .event-type {
144
+ font-weight: 600;
145
+ font-size: 0.875rem;
146
+ color: #333;
147
+ text-transform: uppercase;
148
+ }
149
+
150
+ .event-time {
151
+ margin-left: auto;
152
+ font-size: 0.75rem;
153
+ color: #6b7280;
154
+ }
155
+
156
+ .event-detail {
157
+ background: white;
158
+ border-radius: 4px;
159
+ padding: 0.5rem;
160
+ max-height: 150px;
161
+ overflow-y: auto;
162
+ }
163
+
164
+ pre {
165
+ margin: 0;
166
+ font-size: 0.75rem;
167
+ color: #4b5563;
168
+ white-space: pre-wrap;
169
+ word-break: break-word;
170
+ }
171
+ </style>
src/stores/config.ts ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { writable } from 'svelte/store';
2
+
3
+ interface DataframeConfig {
4
+ showRowNumbers: boolean;
5
+ showCopyButton: boolean;
6
+ showFullscreenButton: boolean;
7
+ showLabel: boolean;
8
+ editable: boolean;
9
+ showSearch: "none" | "search" | "filter";
10
+ lineBreaks: boolean;
11
+ wrap: boolean;
12
+ useCustomWidths: boolean;
13
+ maxHeight: number;
14
+ maxChars: number;
15
+ useCustomTheme: boolean;
16
+ }
17
+
18
+ interface EventLogEntry {
19
+ type: string;
20
+ detail: any;
21
+ timestamp: string;
22
+ }
23
+
24
+ export const dataframeConfig = writable<DataframeConfig>({
25
+ showRowNumbers: true,
26
+ showCopyButton: true,
27
+ showFullscreenButton: true,
28
+ showLabel: true,
29
+ editable: true,
30
+ showSearch: "search",
31
+ lineBreaks: true,
32
+ wrap: false,
33
+ useCustomWidths: false,
34
+ maxHeight: 500,
35
+ maxChars: 100,
36
+ useCustomTheme: false
37
+ });
38
+
39
+ export const eventLog = writable<EventLogEntry[]>([]);