hmb HF Staff commited on
Commit
951c359
Β·
1 Parent(s): 315fc37

Initial commit: Dataframe demo with Vite + Svelte (no SvelteKit routing)

Browse files
README.md CHANGED
@@ -1,58 +1,36 @@
1
  ---
2
- title: Sandbox Dataframe
3
- emoji: πŸ”₯
4
- colorFrom: pink
5
- colorTo: gray
6
  sdk: static
7
  pinned: false
 
8
  app_build_command: npm run build
9
  app_file: dist/index.html
10
  ---
11
 
12
- # Svelte + TS + Vite
13
 
14
- This template should help get you started developing with Svelte and TypeScript in Vite.
15
 
16
- ## Recommended IDE Setup
17
 
18
- [VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode).
 
 
 
 
 
 
19
 
20
- ## Need an official Svelte framework?
21
 
22
- Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less, and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more.
23
 
24
- ## Technical considerations
25
 
26
- **Why use this over SvelteKit?**
27
-
28
- - It brings its own routing solution which might not be preferable for some users.
29
- - It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app.
30
-
31
- This template contains as little as possible to get started with Vite + TypeScript + Svelte, while taking into account the developer experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite` templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project.
32
-
33
- Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been structured similarly to SvelteKit so that it is easy to migrate.
34
-
35
- **Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?**
36
-
37
- Setting `compilerOptions.types` shuts out all other types not explicitly listed in the configuration. Using triple-slash references keeps the default TypeScript setting of accepting type information from the entire workspace, while also adding `svelte` and `vite/client` type information.
38
-
39
- **Why include `.vscode/extensions.json`?**
40
-
41
- Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to install the recommended extension upon opening the project.
42
-
43
- **Why enable `allowJs` in the TS template?**
44
-
45
- While `allowJs: false` would indeed prevent the use of `.js` files in the project, it does not prevent the use of JavaScript syntax in `.svelte` files. In addition, it would force `checkJs: false`, bringing the worst of both worlds: not being able to guarantee the entire codebase is TypeScript, and also having worse typechecking for the existing JavaScript. In addition, there are valid use cases in which a mixed codebase may be relevant.
46
-
47
- **Why is HMR not preserving my local component state?**
48
-
49
- HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr` and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the details [here](https://github.com/rixo/svelte-hmr#svelte-hmr).
50
-
51
- If you have state that's important to retain within a component, consider creating an external store which would not be replaced by HMR.
52
-
53
- ```ts
54
- // store.ts
55
- // An extremely simple external store
56
- import { writable } from "svelte/store";
57
- export default writable(0);
58
- ```
 
1
  ---
2
+ title: Dataframe Sandbox
3
+ emoji: πŸ“Š
4
+ colorFrom: red
5
+ colorTo: blue
6
  sdk: static
7
  pinned: false
8
+ license: apache-2.0
9
  app_build_command: npm run build
10
  app_file: dist/index.html
11
  ---
12
 
13
+ # @gradio/dataframe Demo
14
 
15
+ An interactive demonstration of the `@gradio/dataframe` component showcasing its features including editing, searching, filtering, and various configuration options.
16
 
17
+ ## Features
18
 
19
+ - 🎯 **Interactive Canvas** - Live dataframe component with real-time controls
20
+ - πŸ“– **Comprehensive Documentation** - Complete API reference and usage examples
21
+ - πŸ” **Event Handling** - Demonstration of component events and callbacks
22
+ - πŸ’» **Source Code** - Full implementation code with syntax highlighting
23
+ - πŸŒ™ **Dark Mode** - Toggle between light and dark themes
24
+ - πŸ“± **Responsive Design** - Works on desktop and mobile devices
25
+ - πŸ› οΈ **Resizable Controls** - Drag to adjust controls panel height
26
 
27
+ ## Usage
28
 
29
+ Explore different dataframe configurations using the examples panel, adjust settings with the controls panel, and see real-time updates to understand the component's capabilities.
30
 
31
+ ## Built with
32
 
33
+ - **Svelte 5** - Modern reactive framework
34
+ - **Vite** - Fast build tool and dev server
35
+ - **Tailwind CSS** - Utility-first CSS framework
36
+ - **@gradio/dataframe** - Standalone dataframe component
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
index.html CHANGED
@@ -4,7 +4,7 @@
4
  <meta charset="UTF-8" />
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>Vite + Svelte + TS</title>
8
  </head>
9
  <body>
10
  <div id="app"></div>
 
4
  <meta charset="UTF-8" />
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>@gradio/dataframe Demo</title>
8
  </head>
9
  <body>
10
  <div id="app"></div>
package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
package.json CHANGED
@@ -1,7 +1,8 @@
1
  {
2
- "name": "svelte",
 
3
  "private": true,
4
- "version": "0.0.0",
5
  "type": "module",
6
  "scripts": {
7
  "dev": "vite",
@@ -12,9 +13,19 @@
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": "dataframe-sandbox",
3
+ "description": "Interactive demo and playground for the @gradio/dataframe standalone component",
4
  "private": true,
5
+ "version": "1.0.0",
6
  "type": "module",
7
  "scripts": {
8
  "dev": "vite",
 
13
  "devDependencies": {
14
  "@sveltejs/vite-plugin-svelte": "^5.0.3",
15
  "@tsconfig/svelte": "^5.0.4",
16
+ "@types/prismjs": "^1.26.5",
17
  "svelte": "^5.28.1",
18
  "svelte-check": "^4.1.6",
19
  "typescript": "~5.8.3",
20
  "vite": "^6.3.5"
21
+ },
22
+ "dependencies": {
23
+ "@gradio/dataframe": "^0.19.2",
24
+ "@tailwindcss/postcss": "^4.1.13",
25
+ "@tailwindcss/typography": "^0.5.16",
26
+ "autoprefixer": "^10.4.21",
27
+ "postcss": "^8.5.6",
28
+ "prismjs": "^1.30.0",
29
+ "tailwindcss": "^4.1.13"
30
  }
31
  }
postcss.config.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ export default {
2
+ plugins: {
3
+ '@tailwindcss/postcss': {},
4
+ autoprefixer: {},
5
+ },
6
+ };
public/vite.svg CHANGED
src/App.svelte CHANGED
@@ -1,47 +1,919 @@
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 { onMount } from "svelte";
4
+ import ConfigPanel from "./lib/ConfigPanel.svelte";
5
+ import SyntaxHighlighter from "./lib/SyntaxHighlighter.svelte";
6
+ import { sampleDatasets } from "./lib/sampleData";
7
+
8
+ // Configuration state
9
+ let selectedDataset = "basic";
10
+ let value = {
11
+ data: sampleDatasets.basic.data,
12
+ headers: sampleDatasets.basic.headers,
13
+ metadata: null
14
+ };
15
+
16
+ let datatype: string[] = sampleDatasets.basic.datatypes;
17
+ let editable = sampleDatasets.basic.config.editable;
18
+ let show_row_numbers = sampleDatasets.basic.config.show_row_numbers;
19
+ let show_search: "none" | "search" | "filter" = sampleDatasets.basic.config.show_search;
20
+ let show_copy_button = sampleDatasets.basic.config.show_copy_button;
21
+ let show_fullscreen_button = sampleDatasets.basic.config.show_fullscreen_button;
22
+ let show_label = sampleDatasets.basic.config.show_label;
23
+ let label = sampleDatasets.basic.config.label;
24
+ let max_height = sampleDatasets.basic.config.max_height;
25
+ let line_breaks = sampleDatasets.basic.config.line_breaks;
26
+ let wrap = sampleDatasets.basic.config.wrap;
27
+ let column_widths: string[] = [];
28
+ let max_chars: number | undefined = sampleDatasets.basic.config.max_chars;
29
+
30
+ // Theme state
31
+ let currentTheme = "default";
32
+
33
+ // Active view state
34
+ let activeView = "canvas"; // "canvas", "docs", "events", "source"
35
+
36
+ // Mobile responsive state
37
+ let showLeftPanel = false;
38
+ let showRightPanel = true; // Show controls by default
39
+
40
+ // Resizable controls panel
41
+ let controlsHeight = 220; // Default height
42
+ let isDragging = false;
43
+ let dragStartY = 0;
44
+ let dragStartHeight = 0;
45
+
46
+ // Event handlers
47
+ function handleChange(e: CustomEvent) {
48
+ console.log("Data changed:", e.detail);
49
+ value = e.detail;
50
+ }
51
+
52
+ function handleSelect(e: CustomEvent) {
53
+ console.log("Cell selected:", e.detail);
54
+ }
55
+
56
+ function handleInput(e: CustomEvent) {
57
+ console.log("Input event:", e.detail);
58
+ }
59
+
60
+ function handleDatasetChange(e: CustomEvent) {
61
+ const dataset = e.detail.dataset;
62
+ selectedDataset = dataset;
63
+ const data = sampleDatasets[dataset as keyof typeof sampleDatasets];
64
+ value = {
65
+ data: data.data,
66
+ headers: data.headers,
67
+ metadata: null
68
+ };
69
+ datatype = data.datatypes;
70
+ }
71
+
72
+ function handleThemeChange(e: CustomEvent) {
73
+ const theme = e.detail.theme;
74
+ currentTheme = theme;
75
+ const body = document.body;
76
+ body.className = body.className.replace(/\b(dark|purple-theme|green-theme|orange-theme)\b/g, '');
77
+ if (theme !== 'default') {
78
+ body.classList.add(theme);
79
+ }
80
+ }
81
+
82
+ function switchDataset(dataset: string) {
83
+ selectedDataset = dataset;
84
+ const data = sampleDatasets[dataset as keyof typeof sampleDatasets];
85
+ value = {
86
+ data: data.data,
87
+ headers: data.headers,
88
+ metadata: null
89
+ };
90
+ datatype = data.datatypes;
91
+
92
+ // Apply configuration from the dataset
93
+ const config = data.config;
94
+ editable = config.editable;
95
+ show_row_numbers = config.show_row_numbers;
96
+ show_search = config.show_search;
97
+ show_copy_button = config.show_copy_button;
98
+ show_fullscreen_button = config.show_fullscreen_button;
99
+ show_label = config.show_label;
100
+ label = config.label;
101
+ max_height = config.max_height;
102
+ line_breaks = config.line_breaks;
103
+ wrap = config.wrap;
104
+ max_chars = config.max_chars;
105
+
106
+ // Switch to canvas view to show the selected example
107
+ activeView = 'canvas';
108
+ }
109
+
110
+ function applyTheme(theme: string) {
111
+ currentTheme = theme;
112
+ const body = document.body;
113
+ body.className = body.className.replace(/\b(dark|purple-theme|green-theme|orange-theme)\b/g, '');
114
+ if (theme !== 'default') {
115
+ body.classList.add(theme);
116
+ }
117
+ }
118
+
119
+ function setActiveView(view: string) {
120
+ activeView = view;
121
+ }
122
+
123
+ function getExampleIcon(key: string): string {
124
+ const icons: Record<string, string> = {
125
+ basic: 'πŸ“‹',
126
+ compact: 'πŸ“Š',
127
+ filterable: 'πŸ”',
128
+ readonly: 'πŸ”’',
129
+ wrapped: 'πŸ“',
130
+ large: 'πŸ“ˆ',
131
+ mixed: '🎨',
132
+ minimal: '⚑'
133
+ };
134
+ return icons[key] || 'πŸ“„';
135
+ }
136
+
137
+ function getExampleTitle(key: string): string {
138
+ const titles: Record<string, string> = {
139
+ basic: 'Basic Example',
140
+ compact: 'Compact View',
141
+ filterable: 'Filter & Search',
142
+ readonly: 'Read-Only',
143
+ wrapped: 'Text Wrapping',
144
+ large: 'Large Dataset',
145
+ mixed: 'Rich Content',
146
+ minimal: 'Minimal UI'
147
+ };
148
+ return titles[key] || key.charAt(0).toUpperCase() + key.slice(1);
149
+ }
150
+
151
+ function getExampleDescription(key: string): string {
152
+ const descriptions: Record<string, string> = {
153
+ basic: 'Standard configuration with all features',
154
+ compact: 'Minimal UI, no controls',
155
+ filterable: 'Advanced filtering capabilities',
156
+ readonly: 'Non-editable data display',
157
+ wrapped: 'Long text with wrapping',
158
+ large: 'Performance with 50 rows',
159
+ mixed: 'HTML & Markdown support',
160
+ minimal: 'Bare minimum interface'
161
+ };
162
+ return descriptions[key] || 'Example configuration';
163
+ }
164
+
165
+ function handleAddColumn() {
166
+ const newHeaders = [...value.headers, `Column ${value.headers.length + 1}`];
167
+ const newData = value.data.map((row: any) => [...row, ""]);
168
+ value = {
169
+ ...value,
170
+ headers: newHeaders,
171
+ data: newData
172
+ };
173
+ datatype = [...datatype, "str"];
174
+ }
175
+
176
+ function handleAddRow() {
177
+ const newRow = Array(value.headers.length).fill("");
178
+ value = {
179
+ ...value,
180
+ data: [...value.data, newRow]
181
+ };
182
+ }
183
+
184
+ // Resizable controls panel handlers
185
+ function handleDragStart(e: MouseEvent) {
186
+ isDragging = true;
187
+ dragStartY = e.clientY;
188
+ dragStartHeight = controlsHeight;
189
+ document.body.classList.add('dragging');
190
+ document.addEventListener('mousemove', handleDragMove);
191
+ document.addEventListener('mouseup', handleDragEnd);
192
+ e.preventDefault();
193
+ }
194
+
195
+ function handleDragMove(e: MouseEvent) {
196
+ if (!isDragging) return;
197
+
198
+ const deltaY = dragStartY - e.clientY; // Inverted because we want up movement to increase height
199
+ const newHeight = Math.max(180, Math.min(500, dragStartHeight + deltaY)); // Min 180px, max 500px
200
+ controlsHeight = newHeight;
201
+ }
202
+
203
+ function handleDragEnd() {
204
+ isDragging = false;
205
+ document.body.classList.remove('dragging');
206
+ document.removeEventListener('mousemove', handleDragMove);
207
+ document.removeEventListener('mouseup', handleDragEnd);
208
+ }
209
+
210
+ onMount(() => {
211
+ if (currentTheme !== 'default') {
212
+ document.body.classList.add(currentTheme);
213
+ }
214
+ });
215
  </script>
216
 
217
+ <!-- Storybook-style layout -->
218
+ <div class="min-h-screen bg-[#f6f9fc] flex flex-col">
219
+ <!-- Storybook Header -->
220
+ <header class="h-16 bg-white border-b-2 border-[#d1d5db] flex items-center px-4 md:px-6 relative z-20">
221
+ <!-- Mobile Menu Buttons -->
222
+ <div class="flex items-center space-x-2 md:hidden">
223
+ <button
224
+ on:click={() => currentTheme === 'dark' ? applyTheme('default') : applyTheme('dark')}
225
+ class="p-2 text-[#73828c] hover:text-[#2e3438] hover:bg-[#f6f9fc] rounded-lg transition-all duration-200"
226
+ aria-label="Toggle dark mode"
227
+ title="Toggle dark/light mode"
228
+ >
229
+ {#if currentTheme === 'dark'}
230
+ <span class="text-lg">β˜€οΈ</span>
231
+ {:else}
232
+ <span class="text-lg">πŸŒ™</span>
233
+ {/if}
234
+ </button>
235
+ <button
236
+ on:click={() => showLeftPanel = !showLeftPanel}
237
+ class="p-2 text-[#73828c] hover:text-[#2e3438] hover:bg-[#f6f9fc] rounded-lg transition-all duration-200"
238
+ aria-label="Toggle navigation menu"
239
+ >
240
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
241
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
242
+ </svg>
243
+ </button>
244
+ <button
245
+ on:click={() => showRightPanel = !showRightPanel}
246
+ class="p-2 text-[#73828c] hover:text-[#2e3438] hover:bg-[#f6f9fc] rounded-lg transition-all duration-200"
247
+ aria-label="Toggle controls panel"
248
+ >
249
+ <svg class="w-5 h-5" viewBox="0 0 24 24" stroke-width="1.5" fill="none" xmlns="http://www.w3.org/2000/svg">
250
+ <path d="M10.0503 10.6066L2.97923 17.6777C2.19818 18.4587 2.19818 19.725 2.97923 20.5061V20.5061C3.76027 21.2871 5.0266 21.2871 5.80765 20.5061L12.8787 13.435" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path>
251
+ <path d="M10.0502 10.6066C9.20638 8.45358 9.37134 5.6286 11.1109 3.88909C12.8504 2.14957 16.0606 1.76777 17.8284 2.82843L14.7877 5.8691L14.5051 8.98014L17.6161 8.69753L20.6568 5.65685C21.7175 7.42462 21.3357 10.6349 19.5961 12.3744C17.8566 14.1139 15.0316 14.2789 12.8786 13.435" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path>
252
+ </svg>
253
+ </button>
254
+ </div>
255
 
256
+ <div class="flex items-center space-x-3 md:space-x-4 flex-1 md:flex-initial justify-center md:justify-start">
257
+ <!-- Gradio Logo -->
258
+ <div class="w-8 h-8 md:w-10 md:h-10 flex items-center justify-center">
259
+ <img src="./gradio-logo.svg" alt="Gradio Logo" class="w-full h-full object-contain" />
260
+ </div>
261
+ <div class="flex flex-col">
262
+ <h1 class="text-sm md:text-base font-bold text-[#2e3438] leading-tight tracking-tight">
263
+ @gradio/dataframe demo
264
+ </h1>
265
+ </div>
266
+ </div>
267
+
268
+ <div class="hidden md:flex ml-auto items-center space-x-4">
269
+ <button
270
+ on:click={() => currentTheme === 'dark' ? applyTheme('default') : applyTheme('dark')}
271
+ class="px-3 py-2 !mr-2 text-sm font-medium text-[#73828c] rounded-lg flex items-center"
272
+ aria-label="Toggle dark mode"
273
+ title="Toggle dark/light mode"
274
+ >
275
+ {#if currentTheme === 'dark'}
276
+ <span class="mr-2">β˜€οΈ</span>
277
+ {:else}
278
+ <span class="mr-2">πŸŒ™</span>
279
+ {/if}
280
+ Toggle Theme
281
+ </button>
282
+
283
+ <button
284
+ on:click={() => showRightPanel = !showRightPanel}
285
+ class="px-4 py-2 !mr-2 text-sm font-medium text-[#73828c] hover:text-[#2e3438] hover:bg-[#f6f9fc] rounded-lg transition-all duration-200 flex items-center border border-[#e0e0e0]"
286
+ aria-label="Toggle controls panel"
287
+ >
288
+ <span class="mr-2">πŸ› οΈ</span>
289
+ {showRightPanel ? 'Hide' : 'Show'} Controls
290
+ </button>
291
+ <button
292
+ on:click={() => setActiveView('docs')}
293
+ class="px-4 py-2 text-sm font-medium text-[#73828c] hover:text-[#2e3438] hover:bg-[#f6f9fc] rounded-lg transition-all duration-200 flex items-center"
294
+ >
295
+ <span class="mr-2">πŸ“–</span>
296
+ Docs
297
+ </button>
298
+ <a
299
+ href="https://www.npmjs.com/package/@gradio/dataframe"
300
+ target="_blank"
301
+ rel="noopener noreferrer"
302
+ class="px-4 py-2 text-sm font-semibold text-white rounded-lg transition-all duration-200 flex items-center no-underline"
303
+ >
304
+ <span class="mr-2">πŸ“¦</span>
305
+ npm
306
+ </a>
307
+ </div>
308
+ </header>
309
+
310
+ <div class="flex flex-1 overflow-hidden relative">
311
+ <!-- Mobile Overlay -->
312
+ {#if showLeftPanel || showRightPanel}
313
+ <div
314
+ class="fixed inset-0 bg-black bg-opacity-50 z-10 md:hidden"
315
+ role="button"
316
+ tabindex="0"
317
+ on:click={() => { showLeftPanel = false; showRightPanel = false; }}
318
+ on:keydown={(e) => { if (e.key === 'Escape') { showLeftPanel = false; showRightPanel = false; } }}
319
+ ></div>
320
+ {/if}
321
+
322
+ <!-- Left Panel: Examples & Documentation -->
323
+ <div class="
324
+ {showLeftPanel ? 'translate-x-0' : '-translate-x-full'}
325
+ md:translate-x-0
326
+ fixed md:static
327
+ left-0 top-16 bottom-0
328
+ w-64 md:w-[200px] lg:w-[220px] xl:w-[240px]
329
+ bg-white border-r-1 border-[#d1d5db] [border-right-width:1px!important]
330
+ overflow-y-auto
331
+ z-20
332
+ transition-transform duration-300 ease-in-out
333
+ ">
334
+
335
+ <!-- Documentation Content -->
336
+ <div class="p-4 space-y-4">
337
+ <div>
338
+ <h3 class="text-xs font-semibold text-[#2e3438] mb-2">@gradio/dataframe</h3>
339
+ <p class="text-[10px] text-[#73828c] leading-relaxed">
340
+ A standalone dataframe component from Gradio that provides interactive table functionality with editing, searching, and data manipulation capabilities.
341
+ </p>
342
+ </div>
343
+ </div>
344
+
345
+ <!-- Documentation Navigation -->
346
+ <div class="p-4 border-b border-[#e0e0e0]">
347
+ <h2 class="text-[8px] font-bold text-[#2e3438] uppercase tracking-wider mb-3">Navigation</h2>
348
+ <div class="flex flex-col space-y-2">
349
+ <button
350
+ on:click={() => setActiveView('canvas')}
351
+ class="nav-button {activeView === 'canvas' ? 'nav-button-active' : 'nav-button-inactive'}"
352
+ >
353
+ <div class="flex items-center justify-center mr-3">
354
+ <span class="text-xs">🎯</span>
355
+ </div>
356
+ Canvas
357
+ </button>
358
+ <button
359
+ on:click={() => setActiveView('docs')}
360
+ class="nav-button {activeView === 'docs' ? 'nav-button-active' : 'nav-button-inactive'}"
361
+ >
362
+ <div class="flex items-center justify-center mr-3">
363
+ <span class="text-xs">πŸ“–</span>
364
+ </div>
365
+ Documentation
366
+ </button>
367
+ <button
368
+ on:click={() => setActiveView('events')}
369
+ class="nav-button {activeView === 'events' ? 'nav-button-active' : 'nav-button-inactive'}"
370
+ >
371
+ <div class="flex items-center justify-center mr-3">
372
+ <span class="text-xs">πŸ”</span>
373
+ </div>
374
+ Events
375
+ </button>
376
+ <button
377
+ on:click={() => setActiveView('source')}
378
+ class="nav-button {activeView === 'source' ? 'nav-button-active' : 'nav-button-inactive'}"
379
+ >
380
+ <div class="flex items-center justify-center mr-3">
381
+ <span class="text-xs">πŸ’»</span>
382
+ </div>
383
+ Source Code
384
+ </button>
385
+ </div>
386
+ </div>
387
+
388
+ <!-- Examples Navigation -->
389
+ <div class="p-4 border-b border-[#e0e0e0]">
390
+ <h2 class="text-[8px] font-bold text-[#2e3438] uppercase tracking-wider mb-3">Examples</h2>
391
+
392
+ <!-- Example Cards -->
393
+ <div class="space-y-2">
394
+ {#each Object.entries(sampleDatasets) as [key, dataset]}
395
+ <button
396
+ on:click={() => switchDataset(key)}
397
+ class="w-full group"
398
+ >
399
+ <div class="example-card {selectedDataset === key ? 'example-card-active' : 'example-card-inactive'}">
400
+ <div class="flex items-center justify-between p-2">
401
+ <div class="flex items-center">
402
+ <div class="example-icon {selectedDataset === key ? 'example-icon-active' : 'example-icon-inactive'}">
403
+ <span class="text-xs">{getExampleIcon(key)}</span>
404
+ </div>
405
+ <div class="text-left">
406
+ <h4 class="text-[10px] font-semibold {selectedDataset === key ? 'text-[#1e293b]' : 'text-[#374151]'} group-hover:text-[#1e293b] transition-colors duration-200">{getExampleTitle(key)}</h4>
407
+ <p class="text-[8px] {selectedDataset === key ? 'text-[#64748b]' : 'text-[#9ca3af]'} mt-0.5">{getExampleDescription(key)}</p>
408
+ </div>
409
+ </div>
410
+
411
+ </div>
412
+ </div>
413
+ </button>
414
+ {/each}
415
+ </div>
416
+ </div>
417
+ </div>
418
+
419
+ <!-- Main Content Area -->
420
+ <div class="flex-1 bg-[#f6f9fc] overflow-y-auto border-l border-r border-[#e0e0e0] md:border-l-0" style="padding-bottom: {activeView === 'canvas' ? controlsHeight + 'px' : '16px'}">
421
+ <!-- Canvas Area -->
422
+ {#if activeView === 'canvas'}
423
+ <div class="flex-1 bg-[#f6f9fc] p-2 sm:p-4 md:p-4 lg:p-6 xl:p-8 overflow-auto">
424
+ <div class="main-container">
425
+ <div class="content-card">
426
+ <div class="border border-[#e2e8f0] rounded-lg md:rounded-xl p-4 md:p-8 bg-[#f8fafc] overflow-x-auto">
427
+ <Dataframe
428
+ bind:value
429
+ datatype={datatype as any}
430
+ {editable}
431
+ {show_row_numbers}
432
+ {show_search}
433
+ {show_copy_button}
434
+ {show_fullscreen_button}
435
+ {show_label}
436
+ {label}
437
+ {max_height}
438
+ {line_breaks}
439
+ {wrap}
440
+ {column_widths}
441
+ {max_chars}
442
+ on:change={handleChange}
443
+ on:select={handleSelect}
444
+ on:input={handleInput}
445
+ />
446
+ </div>
447
+ </div>
448
+ </div>
449
+ </div>
450
+ {:else if activeView === 'docs'}
451
+ <!-- Documentation Page -->
452
+ <div class="page-wrapper">
453
+ <div class="main-container">
454
+ <div class="content-card">
455
+ <div class="mb-8 md:mb-12">
456
+ <h1 class="page-title">@gradio/dataframe</h1>
457
+ <p class="description-text">
458
+ A standalone dataframe component from Gradio that provides interactive table functionality with editing, searching, and data manipulation capabilities.
459
+ </p>
460
+ </div>
461
+
462
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-12 mb-12">
463
+ <div>
464
+ <h2 class="section-title">Installation</h2>
465
+ <div class="bg-[#f8fafc] border border-[#e2e8f0] rounded-xl p-6 mb-8">
466
+ <code class="text-sm text-[#2e3438] font-mono font-semibold">npm install @gradio/dataframe</code>
467
+ </div>
468
+
469
+
470
+ </div>
471
+
472
+ <div>
473
+ <h2 class="section-title">Key Features</h2>
474
+ <ul class="space-y-4">
475
+ <li class="flex items-start">
476
+ <span class="text-[#10b981] mr-4 mt-1 text-lg">βœ“</span>
477
+ <span class="feature-text">Interactive editing and data manipulation</span>
478
+ </li>
479
+ <li class="flex items-start">
480
+ <span class="text-[#10b981] mr-4 mt-1 text-lg">βœ“</span>
481
+ <span class="feature-text">Search and filter capabilities</span>
482
+ </li>
483
+ <li class="flex items-start">
484
+ <span class="text-[#10b981] mr-4 mt-1 text-lg">βœ“</span>
485
+ <span class="feature-text">Customizable appearance and behavior</span>
486
+ </li>
487
+ <li class="flex items-start">
488
+ <span class="text-[#10b981] mr-4 mt-1 text-lg">βœ“</span>
489
+ <span class="feature-text">Support for multiple data types</span>
490
+ </li>
491
+ <li class="flex items-start">
492
+ <span class="text-[#10b981] mr-4 mt-1 text-lg">βœ“</span>
493
+ <span class="feature-text">Copy to clipboard functionality</span>
494
+ </li>
495
+ <li class="flex items-start">
496
+ <span class="text-[#10b981] mr-4 mt-1 text-lg">βœ“</span>
497
+ <span class="feature-text">Fullscreen mode support</span>
498
+ </li>
499
+ </ul>
500
+ </div>
501
+
502
+ </div>
503
+
504
+ <div class="mb-12">
505
+
506
+ <h3 class="subsection-title">Quick Start</h3>
507
+ <SyntaxHighlighter
508
+ language="typescript"
509
+ code={`<script>
510
+ import Dataframe from "@gradio/dataframe";
511
+
512
+ let value = {
513
+ data: [["Alice", 25], ["Bob", 30]],
514
+ headers: ["Name", "Age"],
515
+ };
516
+
517
+ </script>
518
+
519
+ <Dataframe bind:value />`}
520
+ />
521
+ </div>
522
 
523
+ <div class="mb-12">
524
+ <h2 class="text-lg font-bold text-[#2e3438] mb-4">API Reference</h2>
525
+ <div class="overflow-x-auto border border-[#e2e8f0] rounded-xl">
526
+ <table class="w-full">
527
+ <thead class="bg-[#f8fafc]">
528
+ <tr>
529
+ <th class="px-6 py-4 text-left font-bold text-[#2e3438] border-b border-[#e2e8f0] text-sm">Prop</th>
530
+ <th class="px-6 py-4 text-left font-bold text-[#2e3438] border-b border-[#e2e8f0] text-sm">Type</th>
531
+ <th class="px-6 py-4 text-left font-bold text-[#2e3438] border-b border-[#e2e8f0] text-sm">Default</th>
532
+ <th class="px-6 py-4 text-left font-bold text-[#2e3438] border-b border-[#e2e8f0] text-sm">Description</th>
533
+ </tr>
534
+ </thead>
535
+ <tbody>
536
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
537
+ <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">value</code></td>
538
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">DataFrame | Array | List</td>
539
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td>
540
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Data to display. Supports pandas, numpy, polars, and list of lists</td>
541
+ </tr>
542
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
543
+ <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">headers</code></td>
544
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">string[]</td>
545
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td>
546
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">List of column header names</td>
547
+ </tr>
548
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
549
+ <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">datatype</code></td>
550
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">string | string[]</td>
551
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">"str"</td>
552
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Data types: "str", "number", "bool", "date", "markdown", "html", "image", "auto"</td>
553
+ </tr>
554
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
555
+ <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">interactive</code></td>
556
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">boolean</td>
557
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td>
558
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Whether users can edit the dataframe (inferred if not provided)</td>
559
+ </tr>
560
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
561
+ <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">label</code></td>
562
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">string</td>
563
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td>
564
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Label text that appears above the component</td>
565
+ </tr>
566
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
567
+ <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">show_label</code></td>
568
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">boolean</td>
569
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td>
570
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Whether to display the label</td>
571
+ </tr>
572
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
573
+ <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">max_height</code></td>
574
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">number | string</td>
575
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">500</td>
576
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Maximum height in pixels or CSS units</td>
577
+ </tr>
578
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
579
+ <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">show_row_numbers</code></td>
580
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">boolean</td>
581
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">false</td>
582
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Display row numbers in a separate column</td>
583
+ </tr>
584
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
585
+ <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">show_search</code></td>
586
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">"none" | "search" | "filter"</td>
587
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">"none"</td>
588
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Show search input and filter functionality</td>
589
+ </tr>
590
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
591
+ <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">show_copy_button</code></td>
592
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">boolean</td>
593
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">false</td>
594
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Show button to copy table data to clipboard</td>
595
+ </tr>
596
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
597
+ <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">show_fullscreen_button</code></td>
598
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">boolean</td>
599
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">false</td>
600
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Show button to view table in fullscreen mode</td>
601
+ </tr>
602
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
603
+ <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">wrap</code></td>
604
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">boolean</td>
605
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">false</td>
606
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Enable text wrapping in table cells</td>
607
+ </tr>
608
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
609
+ <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">line_breaks</code></td>
610
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">boolean</td>
611
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">true</td>
612
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Enable GitHub-flavored Markdown line breaks (for markdown columns)</td>
613
+ </tr>
614
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
615
+ <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">column_widths</code></td>
616
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">(string | number)[]</td>
617
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td>
618
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Width of each column in pixels ("100px") or percentage ("10%")</td>
619
+ </tr>
620
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
621
+ <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">max_chars</code></td>
622
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">number</td>
623
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td>
624
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Maximum characters to display per cell before truncating</td>
625
+ </tr>
626
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
627
+ <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">row_count</code></td>
628
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">number | [number, "fixed" | "dynamic"]</td>
629
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">[1, "dynamic"]</td>
630
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Limit number of rows and whether users can add/delete rows</td>
631
+ </tr>
632
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
633
+ <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">col_count</code></td>
634
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">number | [number, "fixed" | "dynamic"]</td>
635
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td>
636
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Limit number of columns and whether users can add/delete columns</td>
637
+ </tr>
638
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
639
+ <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">pinned_columns</code></td>
640
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">number</td>
641
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td>
642
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Number of columns to pin from the left</td>
643
+ </tr>
644
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
645
+ <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">static_columns</code></td>
646
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">number[]</td>
647
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td>
648
+ <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Column indices that should not be editable</td>
649
+ </tr>
650
+ <tr class="hover:bg-[#f8fafc] transition-colors duration-150">
651
+ <td class="px-6 py-4"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">type</code></td>
652
+ <td class="px-6 py-4 text-[#64748b] font-medium">"pandas" | "numpy" | "array" | "polars"</td>
653
+ <td class="px-6 py-4 text-[#64748b] font-medium">"pandas"</td>
654
+ <td class="px-6 py-4 text-[#64748b] leading-relaxed">Type of value returned by the component</td>
655
+ </tr>
656
+ </tbody>
657
+ </table>
658
+ </div>
659
+ </div>
660
+ </div>
661
+ </div>
662
+ </div>
663
+ {:else if activeView === 'events'}
664
+ <!-- Events Page -->
665
+ <div class="page-wrapper">
666
+ <div class="main-container">
667
+ <div class="content-card">
668
+ <div class="mb-8 md:mb-12">
669
+ <h1 class="page-title">Events</h1>
670
+ <p class="description-text">
671
+ The dataframe component fires several events that you can listen to for user interactions and data changes.
672
+ </p>
673
+ </div>
674
 
675
+ <div class="space-y-10">
676
+ <div class="event-section">
677
+ <div class="flex items-start mb-6">
678
+ <code class="bg-[#F87701] text-white px-4 py-2 rounded-lg text-[#2e3438] mr-6 font-mono font-bold text-sm border shadow-sm">change</code>
679
+ <div class="flex-1">
680
+ <h3 class="subsection-title">Data Change Event</h3>
681
+ <p class="text-sm text-[#64748b] mb-4 leading-relaxed font-medium">Fired when the table data is modified by the user.</p>
682
+ <SyntaxHighlighter
683
+ language="typescript"
684
+ code={`<Dataframe
685
+ bind:value
686
+ on:change={(e) => {
687
+ console.log("Data changed:", e.detail);
688
+ }}
689
+ />`}
690
+ />
691
+ </div>
692
+ </div>
693
+ </div>
694
 
695
+ <div class="event-section">
696
+ <div class="flex items-start mb-6">
697
+ <code class="bg-[#10b981] text-white px-4 py-2 rounded-lg text-[#2e3438] mr-6 font-mono font-bold text-sm border shadow-sm">select</code>
698
+ <div class="flex-1">
699
+ <h3 class="subsection-title">Cell Selection Event</h3>
700
+ <p class="text-[#64748b] mb-6 leading-relaxed font-medium">Fired when a cell is selected or focused.</p>
701
+ <SyntaxHighlighter
702
+ language="typescript"
703
+ code={`<Dataframe
704
+ bind:value
705
+ on:select={(e) => {
706
+ console.log("Cell selected:", e.detail);
707
+ // e.detail contains: { row: number, col: number }
708
+ }}
709
+ />`}
710
+ />
711
+ </div>
712
+ </div>
713
+ </div>
714
+
715
+ <div class="event-section">
716
+ <div class="flex items-start mb-6">
717
+ <code class="bg-[#f59e0b] text-white px-4 py-2 rounded-lg text-[#2e3438] mr-6 font-mono font-bold text-sm border shadow-sm">input</code>
718
+ <div class="flex-1">
719
+ <h3 class="subsection-title">User Input Event</h3>
720
+ <p class="text-[#64748b] mb-6 leading-relaxed font-medium">Fired during user input, useful for real-time validation.</p>
721
+ <SyntaxHighlighter
722
+ language="typescript"
723
+ code={`<Dataframe
724
+ bind:value
725
+ on:input={(e) => {
726
+ console.log("User input:", e.detail);
727
+ // Real-time validation logic here
728
+ }}
729
+ />`}
730
+ />
731
+ </div>
732
+ </div>
733
+ </div>
734
+ </div>
735
+
736
+ <div class="mt-12 p-8 bg-gradient-to-r from-[#f8fafc] to-[#e0f2fe] border border-[#e2e8f0] rounded-xl">
737
+ <h3 class="text-2xl font-bold text-[#2e3438] mb-4">Event Data Structure</h3>
738
+ <p class="text-[#64748b] mb-6 leading-relaxed font-medium">All events provide data through the <code class="bg-white px-3 py-1.5 rounded-md border font-mono text-sm text-[#1e293b] font-semibold">e.detail</code> property:</p>
739
+ <SyntaxHighlighter
740
+ language="typescript"
741
+ code={`// Change event detail
742
+ {
743
+ data: (string | number)[][],
744
+ headers: string[],
745
+ metadata: any
746
+ }
747
+
748
+ // Select event detail
749
+ {
750
+ row: number,
751
+ col: number,
752
+ value: string | number
753
+ }`}
754
+ />
755
+ </div>
756
+ </div>
757
+ </div>
758
+ </div>
759
+ {:else if activeView === 'source'}
760
+ <!-- Source Code Page -->
761
+ <div class="page-wrapper overflow-y-scroll">
762
+ <div class="main-container">
763
+ <div class="content-card">
764
+ <div class="mb-8 md:mb-12">
765
+ <h1 class="page-title">Source Code</h1>
766
+ <p class="description-text">
767
+ Complete example showing how to implement the dataframe component with all features.
768
+ </p>
769
+ </div>
770
+
771
+ <div class="mb-10">
772
+ <h2 class="text-lg font-bold text-[#2e3438] mb-4">Current Configuration</h2>
773
+ <SyntaxHighlighter
774
+ language="typescript"
775
+ code={`<script lang="ts">
776
+ import Dataframe from "@gradio/dataframe";
777
+
778
+ let value = ` + JSON.stringify({
779
+ data: value.data.slice(0, 3),
780
+ headers: value.headers,
781
+ metadata: null
782
+ }, null, 2) + `;
783
+
784
+ let datatype = ` + JSON.stringify(datatype) + `;
785
+
786
+ function handleChange(e: any) {
787
+ console.log("Data changed:", e.detail);
788
  }
789
+
790
+ function handleSelect(e: any) {
791
+ console.log("Cell selected:", e.detail);
792
  }
793
+
794
+ function handleInput(e: any) {
795
+ console.log("Input event:", e.detail);
796
  }
797
+ </script>
798
+
799
+ <Dataframe
800
+ bind:value
801
+ datatype={datatype}
802
+ editable={` + editable + `}
803
+ show_row_numbers={` + show_row_numbers + `}
804
+ show_search="` + show_search + `"
805
+ show_copy_button={` + show_copy_button + `}
806
+ show_fullscreen_button={` + show_fullscreen_button + `}
807
+ show_label={` + show_label + `}
808
+ label="` + label + `"
809
+ max_height={` + max_height + `}
810
+ line_breaks={` + line_breaks + `}
811
+ wrap={` + wrap + `}` + (max_chars ? `
812
+ max_chars={` + max_chars + `}` : '') + `
813
+ on:change={handleChange}
814
+ on:select={handleSelect}
815
+ on:input={handleInput}
816
+ />`}
817
+ />
818
+ </div>
819
+
820
+ <div class="mb-10">
821
+ <h2 class="text-lg font-bold text-[#2e3438] mb-4">TypeScript Definitions</h2>
822
+ <SyntaxHighlighter
823
+ language="typescript"
824
+ code={`interface DataframeValue {
825
+ data: (string | number)[][];
826
+ headers: string[];
827
+ metadata: any;
828
+ }
829
+
830
+ interface DataframeProps {
831
+ value: DataframeValue;
832
+ datatype?: string[];
833
+ editable?: boolean;
834
+ show_row_numbers?: boolean;
835
+ show_search?: "none" | "search" | "filter";
836
+ show_copy_button?: boolean;
837
+ show_fullscreen_button?: boolean;
838
+ show_label?: boolean;
839
+ label?: string;
840
+ max_height?: number;
841
+ line_breaks?: boolean;
842
+ wrap?: boolean;
843
+ max_chars?: number;
844
+ column_widths?: string[];
845
+ }`}
846
+ />
847
+ </div>
848
+
849
+ <div>
850
+ <h2 class="text-lg font-bold text-[#2e3438] mb-4">Installation</h2>
851
+ <div class="bg-[#f8fafc] border border-[#e2e8f0] rounded-xl p-8">
852
+ <h3 class="text-lg font-semibold text-[#2e3438] mb-4">Package.json</h3>
853
+ <SyntaxHighlighter
854
+ language="json"
855
+ code={`{
856
+ "dependencies": {
857
+ "@gradio/dataframe": "^latest"
858
  }
859
+ }`}
860
+ />
861
+ </div>
862
+ </div>
863
+ </div>
864
+ </div>
865
+ </div>
866
+ {/if}
867
+
868
+ <!-- Bottom Controls Panel (Horizontal) -->
869
+ <div class="
870
+ {showRightPanel && activeView === 'canvas' ? 'translate-y-0' : 'translate-y-full'}
871
+ fixed
872
+ left-0 md:left-[200px] lg:left-[220px] xl:left-[240px]
873
+ right-0 bottom-0
874
+ bg-white border-t border-[#d1d5db]
875
+ z-20
876
+ transition-transform duration-300 ease-in-out
877
+ " style="height: {controlsHeight}px">
878
+ <!-- Drag handle for resizing -->
879
+ <div
880
+ class="flex justify-center border-b border-[#e0e0e0] cursor-ns-resize hover:bg-gray-50 transition-colors duration-200 {isDragging ? 'bg-gray-100' : ''}"
881
+ on:mousedown={handleDragStart}
882
+ role="slider"
883
+ tabindex="0"
884
+ aria-label="Resize controls panel"
885
+ aria-valuenow={controlsHeight}
886
+ aria-valuemin="120"
887
+ aria-valuemax="400"
888
+ title="Drag to resize controls panel"
889
+ >
890
+ </div>
891
+
892
+ <!-- Mobile bottom sheet handle -->
893
+ <div class="md:hidden flex justify-center py-2 border-b border-[#e0e0e0]">
894
+ <div class="w-10 h-1 bg-[#d1d5db] rounded-full"></div>
895
+ </div>
896
+
897
+ <ConfigPanel
898
+ bind:selectedDataset
899
+ bind:currentTheme
900
+ bind:editable
901
+ bind:show_row_numbers
902
+ bind:show_search
903
+ bind:show_copy_button
904
+ bind:show_fullscreen_button
905
+ bind:show_label
906
+ bind:label
907
+ bind:max_height
908
+ bind:line_breaks
909
+ bind:wrap
910
+ bind:max_chars
911
+ on:datasetChange={handleDatasetChange}
912
+ on:themeChange={handleThemeChange}
913
+ on:addColumn={handleAddColumn}
914
+ on:addRow={handleAddRow}
915
+ />
916
+ </div>
917
+ </div>
918
+ </div>
919
+ </div>
src/app.css CHANGED
@@ -1,79 +1,696 @@
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 {
26
- margin: 0;
27
- display: flex;
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
+ @import "tailwindcss";
 
 
 
2
 
3
+ /* Base styles */
4
+ body {
5
+ margin: 0;
6
+ padding: 0;
7
+ font-family: "Nunito Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
8
+ font-size: 14px;
9
+ line-height: 1.6;
10
+ color: #2e3438;
11
+ background-color: #f6f9fc;
12
+ }
13
 
14
+ /* Storybook-specific styles */
15
+ .storybook-header {
16
+ font-family: "Nunito Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
 
17
  }
18
 
19
+ /* Override link styles for Storybook design */
20
  a {
21
+ color: inherit;
22
+ text-decoration: none;
 
23
  }
24
+
25
+ /* Button reset for Storybook style */
26
+ button {
27
+ font-family: inherit;
28
+ border: none;
29
+ cursor: pointer;
30
+ background: none;
31
  }
32
 
33
+ /* Input styles for controls */
34
+ input, select {
35
+ font-family: inherit;
 
 
 
36
  }
37
 
38
+ /* Storybook accent colors */
39
+ :root {
40
+ --storybook-primary: #F87701;
41
+ --storybook-secondary: #ff4785;
42
+ --storybook-green: #37d67a;
43
+ --storybook-orange: #fc521f;
44
+ --storybook-yellow: #ffae00;
45
+ --storybook-red: #fa5a5a;
46
+ --storybook-gray-1: #f6f9fc;
47
+ --storybook-gray-2: #e0e0e0;
48
+ --storybook-gray-3: #999;
49
+ --storybook-gray-4: #666;
50
+ --storybook-gray-5: #333;
51
+ --storybook-gray-6: #2b2b2b;
52
+ --storybook-gray-7: #1a1a1a;
53
  }
54
 
55
+ /* Gradio Dataframe CSS Variables */
56
+ :root {
57
+ --gr-df-table-bg-even: #ffffff;
58
+ --gr-df-table-bg-odd: #f9fafb;
59
+ --gr-df-copied-cell-color: #dbeafe;
60
+ --gr-df-table-border: #e5e7eb;
61
+ --gr-df-table-text: #374151;
62
+ --gr-df-accent: #3b82f6;
63
+ --gr-df-accent-soft: #dbeafe;
64
+ --gr-df-font-size: 14px;
65
+ --gr-df-font-mono: ui-monospace, SFMono-Regular, monospace;
66
+ --gr-df-font-sans: system-ui, -apple-system, sans-serif;
67
+ --gr-df-table-radius: 8px;
68
  }
69
 
70
+
71
+ /* Custom theme examples */
72
+ .purple-theme {
73
+ --gr-df-accent: #7c3aed;
74
+ --gr-df-accent-soft: #ede9fe;
75
+ --gr-df-copied-cell-color: #ede9fe;
76
  }
77
 
78
+ .green-theme {
79
+ --gr-df-accent: #059669;
80
+ --gr-df-accent-soft: #d1fae5;
81
+ --gr-df-copied-cell-color: #d1fae5;
82
+ }
83
+
84
+ .orange-theme {
85
+ --gr-df-accent: #ea580c;
86
+ --gr-df-accent-soft: #fed7aa;
87
+ --gr-df-copied-cell-color: #fed7aa;
88
+ }
89
+
90
+ /* Dark Mode Theme */
91
+ .dark {
92
+ /* Override root CSS variables for dark mode */
93
+ --gr-df-table-bg-even: #1f2937;
94
+ --gr-df-table-bg-odd: #111827;
95
+ --gr-df-copied-cell-color: #374151;
96
+ --gr-df-table-border: #374151;
97
+ --gr-df-table-text: #f9fafb;
98
+ --gr-df-accent: #60a5fa;
99
+ --gr-df-accent-soft: #1e3a8a;
100
+
101
+ /* Dark mode for body and base elements */
102
+ background-color: #0f172a;
103
+ color: #f1f5f9;
104
+ }
105
+
106
+ /* Dark mode specific overrides for the interface */
107
+ .dark .bg-white {
108
+ background-color: #1e293b;
109
+ }
110
+
111
+ .dark .bg-\[#f6f9fc\] {
112
+ background-color: #0f172a;
113
+ }
114
+
115
+ .dark .bg-\[#f8fafc\] {
116
+ background-color: #1e293b;
117
+ }
118
+
119
+ /* Dark mode for dataframe container background */
120
+ .dark div[class*="bg-[#f8fafc]"] {
121
+ background-color: #1e293b;
122
+ }
123
+
124
+ .dark .rounded-lg.bg-\[#f8fafc\] {
125
+ background-color: #1e293b;
126
+ }
127
+
128
+ .dark .rounded-xl.bg-\[#f8fafc\] {
129
+ background-color: #1e293b;
130
+ }
131
+
132
+ /* Comprehensive dark mode overrides for all light backgrounds */
133
+ .dark div,
134
+ .dark section,
135
+ .dark main,
136
+ .dark header,
137
+ .dark footer,
138
+ .dark aside,
139
+ .dark nav {
140
+ /* Override common light background colors */
141
+ }
142
+
143
+ .dark [class*="bg-white"]:not(button):not(.btn):not([role="button"]) {
144
+ background-color: #1e293b;
145
+ }
146
+
147
+ .dark [class*="bg-[#f6f9fc]"]:not(button):not(.btn):not([role="button"]) {
148
+ background-color: #0f172a;
149
+ }
150
+
151
+ .dark [class*="bg-[#f8fafc]"]:not(button):not(.btn):not([role="button"]) {
152
+ background-color: #1e293b;
153
+ }
154
+
155
+ .dark [class*="bg-[#f9fafb]"]:not(button):not(.btn):not([role="button"]) {
156
+ background-color: #1e293b;
157
+ }
158
+
159
+ .dark [class*="bg-[#fafafa]"]:not(button):not(.btn):not([role="button"]) {
160
+ background-color: #1e293b;
161
+ }
162
+
163
+ .dark [class*="bg-gray-50"]:not(button):not(.btn):not([role="button"]) {
164
+ background-color: #1e293b;
165
+ }
166
+
167
+ .dark [class*="bg-gray-100"]:not(button):not(.btn):not([role="button"]) {
168
+ background-color: #334155;
169
+ }
170
+
171
+ /* Dark mode for all text colors */
172
+ .dark [class*="text-[#2e3438]"] {
173
+ color: #f1f5f9;
174
+ }
175
+
176
+ .dark [class*="text-[#374151]"] {
177
+ color: #e2e8f0 ;
178
+ }
179
+
180
+ .dark [class*="text-[#64748b]"] {
181
+ color: #94a3b8 ;
182
+ }
183
+
184
+ .dark [class*="text-[#9ca3af]"] {
185
+ color: #6b7280 ;
186
+ }
187
+
188
+ .dark [class*="text-[#6b7280]"] {
189
+ color: #9ca3af ;
190
+ }
191
+
192
+ /* Dark mode for all border colors */
193
+ .dark [class*="border-[#e0e0e0]"] {
194
+ border-color: #475569;
195
+ }
196
+
197
+ .dark [class*="border-[#e5e7eb]"] {
198
+ border-color: #475569;
199
+ }
200
+
201
+ .dark [class*="border-[#d1d5db]"] {
202
+ border-color: #475569;
203
+ }
204
+
205
+ .dark [class*="border-[#e2e8f0]"] {
206
+ border-color: #475569;
207
+ }
208
+
209
+ .dark .border-\[#d1d5db\] {
210
+ border-color: #475569;
211
+ }
212
+
213
+ .dark .border-\[#e0e0e0\] {
214
+ border-color: #475569;
215
+ }
216
+
217
+ .dark .border-\[#e2e8f0\] {
218
+ border-color: #475569;
219
+ }
220
+
221
+ .dark .text-\[#2e3438\] {
222
+ color: #f1f5f9;
223
+ }
224
+
225
+ .dark .text-\[#73828c\] {
226
+ color: #cbd5e1;
227
+ }
228
+
229
+ .dark .text-\[#64748b\] {
230
+ color: #94a3b8 ;
231
+ }
232
+
233
+ .dark .text-\[#374151\] {
234
+ color: #e2e8f0 ;
235
+ }
236
+
237
+ .dark .text-\[#1e293b\] {
238
+ color: #f8fafc ;
239
+ }
240
+
241
+ .dark .text-\[#9ca3af\] {
242
+ color: #6b7280 ;
243
+ }
244
+
245
+ /* Dark mode hover states */
246
+ .dark .hover\:bg-\[#f6f9fc\]:hover {
247
+ background-color: #334155;
248
+ }
249
+
250
+ .dark .hover\:text-\[#2e3438\]:hover {
251
+ color: #f1f5f9;
252
+ }
253
+
254
+ .dark .hover\:border-\[#cbd5e1\]:hover {
255
+ border-color: #64748b ;
256
+ }
257
+
258
+ /* Dark mode focus states */
259
+ .dark .focus\:ring-\[#F87701\]:focus {
260
+ --tw-ring-color: #f97316 ;
261
+ }
262
+
263
+ .dark .focus\:border-\[#F87701\]:focus {
264
+ border-color: #f97316 ;
265
+ }
266
+
267
+ /* Dark mode for example cards */
268
+ .dark .bg-\[#f1f5f9\] {
269
+ background-color: #475569;
270
+ }
271
+
272
+ .dark .bg-\[#fef7f0\] {
273
+ background-color: #1e3a8a ;
274
+ }
275
+
276
+ .dark .border-\[#F87701\] {
277
+ border-color: #60a5fa ;
278
+ }
279
+
280
+ /* Dark mode for selected example card backgrounds - more specific selectors */
281
+ .dark .rounded-xl.border-2.bg-\[#fef7f0\] {
282
+ background-color: #1e3a8a ;
283
+ border-color: #60a5fa ;
284
+ }
285
+
286
+ .dark .rounded-xl.border-2.border-\[#F87701\] {
287
+ background-color: #1e3a8a ;
288
+ border-color: #60a5fa ;
289
+ }
290
+
291
+ /* Dark mode for example card selected state colors */
292
+ .dark .bg-\[#F87701\] {
293
+ background-color: #60a5fa ;
294
+ }
295
+
296
+ /* Force dark mode on selected example cards using attribute selectors */
297
+ .dark div[class*="bg-[#fef7f0]"] {
298
+ background-color: #1e3a8a ;
299
+ }
300
+
301
+ .dark div[class*="border-[#F87701]"] {
302
+ border-color: #60a5fa ;
303
+ }
304
+
305
+ .dark div[class*="bg-[#F87701]"] {
306
+ background-color: #60a5fa ;
307
+ }
308
+
309
+ /* Maximum specificity override for selected example cards in dark mode */
310
+ html.dark body div.space-y-2 button div.rounded-xl {
311
+ background-color: #1e3a8a ;
312
+ border-color: #60a5fa ;
313
+ }
314
+
315
+ /* Target any div with the specific orange background class in dark mode */
316
+ html.dark [class~="bg-[#fef7f0]"] {
317
+ background-color: #1e3a8a ;
318
+ }
319
+
320
+ html.dark [class~="border-[#F87701]"] {
321
+ border-color: #60a5fa ;
322
+ }
323
+
324
+ /* Nuclear option - override any element with these exact classes */
325
+ .dark * {
326
+ --selected-bg: #1e3a8a;
327
+ --selected-border: #60a5fa;
328
+ }
329
+
330
+ .dark .bg-\[#fef7f0\],
331
+ .dark [style*="background"],
332
+ .dark .rounded-xl[class*="bg-[#fef7f0]"] {
333
+ background-color: var(--selected-bg) ;
334
+ background: var(--selected-bg) ;
335
+ }
336
+
337
+ .dark .border-\[#F87701\],
338
+ .dark .rounded-xl[class*="border-[#F87701]"] {
339
+ border-color: var(--selected-border) ;
340
+ }
341
+
342
+ /* Dark mode for select dropdown */
343
+ .dark select {
344
+ background-color: #1e293b;
345
+ color: #f1f5f9;
346
+ border-color: #475569;
347
+ }
348
+
349
+ .dark select option {
350
+ background-color: #1e293b;
351
+ color: #f1f5f9;
352
+ }
353
+
354
+ /* Dark mode for gradients */
355
+ .dark .bg-gradient-to-r {
356
+ background: linear-gradient(to right, #1e293b, #0f172a) ;
357
+ }
358
+
359
+ /* Dark mode for shadows */
360
+ .dark .shadow-lg {
361
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3), 0 4px 6px -2px rgba(0, 0, 0, 0.2) ;
362
+ }
363
+
364
+ .dark .hover\:shadow-sm:hover {
365
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.3) ;
366
+ }
367
+
368
+ /* Dark mode for code blocks and syntax highlighting */
369
+ .dark code {
370
+ background-color: #374151 ;
371
+ color: #f9fafb ;
372
+ }
373
+
374
+ .dark pre {
375
+ background-color: #1f2937 ;
376
+ border-color: #475569;
377
+ }
378
+
379
+ /* Dark mode for tables */
380
+ .dark table {
381
+ background-color: #1e293b;
382
+ }
383
+
384
+ .dark th, .dark td {
385
+ border-color: #475569;
386
+ color: #f1f5f9;
387
+ }
388
+
389
+ .dark thead {
390
+ background-color: #374151 ;
391
+ }
392
+
393
+ .dark tbody tr:hover {
394
+ background-color: #334155;
395
+ }
396
+
397
+ /* Dark mode for mobile overlay */
398
+ .dark .bg-black {
399
+ background-color: rgba(0, 0, 0, 0.8) ;
400
+ }
401
+
402
+ /* Additional dark mode text color fixes */
403
+ .dark h1, .dark h2, .dark h3, .dark h4, .dark h5, .dark h6 {
404
+ color: #f1f5f9;
405
+ }
406
+
407
+ .dark p {
408
+ color: #cbd5e1;
409
+ }
410
+
411
+ .dark label {
412
+ color: #f1f5f9;
413
+ }
414
+
415
+ /* Dark mode for specific text color classes that might be missed */
416
+ .dark .text-gray-600 {
417
+ color: #94a3b8 ;
418
+ }
419
+
420
+ .dark .text-gray-700 {
421
+ color: #cbd5e1;
422
+ }
423
+
424
+ .dark .text-gray-800 {
425
+ color: #e2e8f0 ;
426
+ }
427
+
428
+ .dark .text-gray-900 {
429
+ color: #f1f5f9;
430
+ }
431
+
432
+ /* Dark mode for any remaining light backgrounds */
433
+ .dark .bg-gray-50 {
434
+ background-color: #1e293b;
435
+ }
436
+
437
+ .dark .bg-gray-100 {
438
+ background-color: #334155;
439
+ }
440
+
441
+ .dark .bg-gray-200 {
442
+ background-color: #475569;
443
+ }
444
+
445
+ /* Dark mode for input placeholders */
446
+ .dark input::placeholder {
447
+ color: #94a3b8 ;
448
+ }
449
+
450
+ .dark textarea::placeholder {
451
+ color: #94a3b8 ;
452
+ }
453
+
454
+ /* Dark mode for any white text that should be dark in light mode but light in dark mode */
455
+ .dark .text-white {
456
+ color: #f1f5f9;
457
+ }
458
+
459
+ /* Ensure dataframe component inherits dark theme properly */
460
+ .dark [data-testid="dataframe"] {
461
+ background-color: #1e293b;
462
+ color: #f1f5f9;
463
+ }
464
+
465
+ /* Dark mode for any remaining border colors */
466
+ .dark .border-gray-200 {
467
+ border-color: #475569;
468
+ }
469
+
470
+ .dark .border-gray-300 {
471
+ border-color: #64748b ;
472
+ }
473
+
474
+ /* Dark mode for button text that might not be covered */
475
+ .dark button {
476
+ color: inherit ;
477
+ }
478
+
479
+ /* Dark mode for links */
480
+ .dark a {
481
+ color: #60a5fa ;
482
+ }
483
+
484
+ .dark a:hover {
485
+ color: #93c5fd ;
486
+ }
487
+
488
+ /* Force dark mode on all text elements that might be using default colors */
489
+ .dark * {
490
+ border-color: #475569;
491
+ }
492
+
493
+ /* Specific overrides for components that might not inherit properly */
494
+ .dark .text-current {
495
+ color: #f1f5f9;
496
+ }
497
+
498
+ /* Dark mode for any remaining light text colors */
499
+ .dark .text-black {
500
+ color: #f1f5f9;
501
+ }
502
+
503
+ /* Dark mode for the dataframe component wrapper */
504
+ .dark div[class*="dataframe"] {
505
+ background-color: #1e293b;
506
+ color: #f1f5f9;
507
+ }
508
+
509
+ /* Dark mode for any input elements */
510
+ .dark input {
511
+ background-color: #1e293b;
512
+ color: #f1f5f9;
513
+ border-color: #475569;
514
+ }
515
+
516
+ /* Dark mode for checkboxes and form controls */
517
+ .dark input[type="checkbox"] {
518
+ background-color: #374151 ;
519
+ border-color: #6b7280 ;
520
+ }
521
+
522
+ .dark input[type="checkbox"]:checked {
523
+ background-color: #60a5fa ;
524
+ border-color: #60a5fa ;
525
+ }
526
+
527
+ /* Page titles */
528
+ .page-title {
529
+ @apply text-lg md:text-xl lg:text-2xl font-bold text-[#2e3438] mb-3 md:mb-4 tracking-tight;
530
+ }
531
+
532
+ /* Section titles */
533
+ .section-title {
534
+ @apply text-lg font-bold text-[#2e3438] mb-4;
535
+ }
536
+
537
+ /* Subsection titles */
538
+ .subsection-title {
539
+ @apply text-base font-bold text-[#2e3438] mb-2;
540
+ }
541
+
542
+ /* Content cards */
543
+ .content-card {
544
+ @apply bg-white rounded-xl md:rounded-2xl shadow-lg border border-[#e0e0e0] p-4 sm:p-6 md:p-6 lg:p-8 xl:p-12;
545
+ }
546
+
547
+ /* Navigation buttons */
548
+ .nav-button {
549
+ @apply flex items-center py-1 px-2 text-xs mb-1 font-medium transition-all duration-200 rounded-sm;
550
+ }
551
+
552
+ .nav-button-active {
553
+ @apply border-[#F87701] bg-[#fef7f0];
554
+ }
555
+
556
+ .nav-button-inactive {
557
+ @apply text-[#73828c] hover:text-[#2e3438] hover:bg-[#f6f9fc];
558
+ }
559
+
560
+ .example-card {
561
+ @apply flex items-center py-1 px-2 text-xs font-medium transition-all duration-200 rounded-sm;
562
+ }
563
+
564
+ /* Example card containers */
565
+ .example-card-active {
566
+ @apply border-[#F87701] bg-[#fef7f0];
567
+ }
568
+
569
+ .example-card-inactive {
570
+ @apply border-[#e2e8f0] bg-white;
571
+ }
572
+
573
+ /* Example card icons */
574
+ .example-icon {
575
+ @apply w-6 h-6 rounded-lg flex items-center justify-center mr-2 transition-colors duration-200;
576
+ }
577
+
578
+ .example-icon-active {
579
+ @apply bg-[#F87701] text-white;
580
+ }
581
+
582
+ .example-icon-inactive {
583
+ @apply bg-[#f1f5f9] text-[#64748b];
584
+ }
585
+
586
+ /* Text styles */
587
+ .description-text {
588
+ @apply text-sm md:text-base lg:text-lg text-[#73828c] leading-relaxed font-medium;
589
+ }
590
+
591
+ .feature-text {
592
+ @apply text-sm text-[#64748b] leading-relaxed font-medium;
593
+ }
594
+
595
+ /* Event sections */
596
+ .event-section {
597
+ @apply border border-[#e2e8f0] rounded-xl p-8 bg-gradient-to-r from-[#f8fafc] to-white;
598
+ }
599
+
600
+ /* Main layout containers */
601
+ .main-container {
602
+ @apply max-w-full md:max-w-3xl lg:max-w-5xl xl:max-w-6xl mx-auto ;
603
+ }
604
+
605
+ .page-wrapper {
606
+ @apply flex-1 bg-[#f6f9fc] p-4 sm:p-6 md:p-6 lg:p-8 xl:p-12 overflow-auto;
607
+ }
608
+
609
+ /* Dark mode overrides for new classes */
610
+ .dark .page-title,
611
+ .dark .section-title,
612
+ .dark .subsection-title {
613
+ color: #f1f5f9;
614
+ }
615
+
616
+ .dark .content-card {
617
+ background-color: #1e293b;
618
+ border-color: #475569;
619
+ }
620
+
621
+ .dark .nav-button-active {
622
+ background-color: #1e3a8a;
623
+ }
624
+
625
+ .dark .nav-button-inactive {
626
+ color: #cbd5e1;
627
+ }
628
+
629
+ .dark .nav-button-inactive:hover {
630
+ color: #f1f5f9;
631
+ background-color: #334155;
632
+ }
633
+
634
+ .dark .example-card-active {
635
+ background-color: #1e3a8a;
636
+ }
637
+
638
+ .dark .example-card-inactive {
639
+ background-color: #1e293b ;
640
+ }
641
+
642
+ .dark .example-card-inactive:hover {
643
+ background-color: #334155;
644
+ }
645
+
646
+ .dark .example-icon-active {
647
+ background-color: #60a5fa;
648
+ }
649
+
650
+ .dark .description-text,
651
+ .dark .feature-text {
652
+ color: #cbd5e1;
653
+ }
654
+
655
+ .dark .event-section {
656
+ background: linear-gradient(to right, #1e293b, #0f172a);
657
+ border-color: #475569;
658
+ }
659
+
660
+ div[role*="slider"] {
661
+ border-top: 1px solid #d1d5db;
662
+ }
663
+ /* Resizable controls panel styling */
664
+ .drag-handle {
665
+ user-select: none;
666
+ -webkit-user-select: none;
667
+ -moz-user-select: none;
668
+ -ms-user-select: none;
669
+ }
670
+
671
+ .drag-handle:hover {
672
+ background-color: #f9fafb;
673
+ }
674
+
675
+ .drag-handle.dragging {
676
+ background-color: #f3f4f6;
677
+ cursor: ns-resize;
678
+ }
679
+
680
+ /* Dark mode for drag handle */
681
+ .dark .drag-handle:hover {
682
+ background-color: #374151;
683
+ }
684
+
685
+ .dark .drag-handle.dragging {
686
+ background-color: #4b5563;
687
+ }
688
+
689
+ /* Prevent text selection during drag */
690
+ body.dragging {
691
+ user-select: none;
692
+ -webkit-user-select: none;
693
+ -moz-user-select: none;
694
+ -ms-user-select: none;
695
+ cursor: ns-resize;
696
  }
src/lib/ConfigPanel.svelte ADDED
@@ -0,0 +1,342 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { createEventDispatcher } from "svelte";
3
+ import { sampleDatasets } from "./sampleData";
4
+
5
+ const dispatch = createEventDispatcher();
6
+
7
+ export let selectedDataset = "basic";
8
+ export let currentTheme = "default";
9
+ export let editable = true;
10
+ export let show_row_numbers = true;
11
+ export let show_search: "none" | "search" | "filter" = "search";
12
+ export let show_copy_button = true;
13
+ export let show_fullscreen_button = true;
14
+ export let show_label = true;
15
+ export let label = "Sample Data";
16
+ export let max_height = 500;
17
+ export let line_breaks = true;
18
+ export let wrap = false;
19
+ export let max_chars: number | undefined = undefined;
20
+
21
+ // Controls panel state
22
+ let activeControlsTab = "properties"; // "properties" or "actions"
23
+
24
+ function switchDataset(dataset: string) {
25
+ selectedDataset = dataset;
26
+ dispatch('datasetChange', { dataset });
27
+ }
28
+
29
+ function applyTheme(theme: string) {
30
+ currentTheme = theme;
31
+ dispatch('themeChange', { theme });
32
+ }
33
+
34
+ function addCustomColumn() {
35
+ dispatch('addColumn');
36
+ }
37
+
38
+ function addCustomRow() {
39
+ dispatch('addRow');
40
+ }
41
+ </script>
42
+
43
+ <!-- Storybook Controls Panel -->
44
+ <div class="h-full flex flex-col w-full">
45
+ <!-- Controls Tab Header -->
46
+ <div class="p-4 border-b-2 border-[#e0e0e0] bg-[#f8fafc]">
47
+ <div class="flex items-center justify-between">
48
+ <h2 class="text-xs font-bold text-[#2e3438] uppercase tracking-wider">Controls</h2>
49
+ <div class="flex space-x-4">
50
+ <button
51
+ on:click={() => activeControlsTab = "properties"}
52
+ class="flex items-center py-2.5 !px-4 text-sm font-medium transition-all duration-200 rounded-lg
53
+ {activeControlsTab === 'properties'
54
+ ? 'text-[#F87701] bg-white border border-[#F87701]'
55
+ : 'text-[#64748b] hover:text-[#F87701] hover:bg-white/50 border border-transparent'}"
56
+ >
57
+ <span class="mr-2">βš™οΈ</span>
58
+ Properties
59
+ </button>
60
+ <button
61
+ on:click={() => activeControlsTab = "actions"}
62
+ class="flex items-center py-2.5 !px-4 text-sm font-medium transition-all duration-200 rounded-lg
63
+ {activeControlsTab === 'actions'
64
+ ? 'text-[#F87701] bg-white border border-[#F87701]'
65
+ : 'text-[#64748b] hover:text-[#F87701] hover:bg-white/50 border border-transparent'}"
66
+ >
67
+ <span class="mr-2">πŸ“</span>
68
+ Actions
69
+ </button>
70
+ </div>
71
+ </div>
72
+ </div>
73
+
74
+ <!-- Controls Content -->
75
+ <div class="flex-1 overflow-x-scroll overflow-y-scroll p-4 min-h-0">
76
+
77
+ {#if activeControlsTab === "properties"}
78
+ <!-- Properties Tab Content -->
79
+ <div class="flex space-x-8 min-w-max">
80
+
81
+ <!-- Boolean Controls -->
82
+ <div class="min-w-[300px]">
83
+ <h4 class="text-xs font-bold text-[#2e3438] uppercase tracking-wider mb-4">Display</h4>
84
+
85
+ <div class="space-y-4">
86
+ <label class="flex items-center justify-between py-3 px-3 hover:bg-[#f6f9fc] rounded-lg transition-all duration-200">
87
+ <span class="text-[14px] text-[#2e3438]">editable</span>
88
+ <input
89
+ type="checkbox"
90
+ bind:checked={editable}
91
+ class="w-5 h-5 rounded border-[#e0e0e0] text-[#F87701] focus:ring-[#F87701] focus:ring-2 bg-white"
92
+ >
93
+ </label>
94
+
95
+ <label class="flex items-center justify-between py-3 px-3 hover:bg-[#f6f9fc] rounded-lg transition-all duration-200">
96
+ <span class="text-[14px] text-[#2e3438]">show_row_numbers</span>
97
+ <input
98
+ type="checkbox"
99
+ bind:checked={show_row_numbers}
100
+ class="w-5 h-5 rounded border-[#e0e0e0] text-[#F87701] focus:ring-[#F87701] focus:ring-2 bg-white"
101
+ >
102
+ </label>
103
+
104
+ <label class="flex items-center justify-between py-3 px-3 hover:bg-[#f6f9fc] rounded-lg transition-all duration-200">
105
+ <span class="text-[14px] text-[#2e3438]">show_copy_button</span>
106
+ <input
107
+ type="checkbox"
108
+ bind:checked={show_copy_button}
109
+ class="w-5 h-5 rounded border-[#e0e0e0] text-[#F87701] focus:ring-[#F87701] focus:ring-2 bg-white"
110
+ >
111
+ </label>
112
+
113
+ <label class="flex items-center justify-between py-3 px-3 hover:bg-[#f6f9fc] rounded-lg transition-all duration-200">
114
+ <span class="text-[14px] text-[#2e3438]">show_fullscreen_button</span>
115
+ <input
116
+ type="checkbox"
117
+ bind:checked={show_fullscreen_button}
118
+ class="w-5 h-5 rounded border-[#e0e0e0] text-[#F87701] focus:ring-[#F87701] focus:ring-2 bg-white"
119
+ >
120
+ </label>
121
+
122
+ <label class="flex items-center justify-between py-3 px-3 hover:bg-[#f6f9fc] rounded-lg transition-all duration-200">
123
+ <span class="text-[14px] text-[#2e3438]">show_label</span>
124
+ <input
125
+ type="checkbox"
126
+ bind:checked={show_label}
127
+ class="w-5 h-5 rounded border-[#e0e0e0] text-[#F87701] focus:ring-[#F87701] focus:ring-2 bg-white"
128
+ >
129
+ </label>
130
+
131
+ <label class="flex items-center justify-between py-3 px-3 hover:bg-[#f6f9fc] rounded-lg transition-all duration-200">
132
+ <span class="text-[14px] text-[#2e3438]">line_breaks</span>
133
+ <input
134
+ type="checkbox"
135
+ bind:checked={line_breaks}
136
+ class="w-5 h-5 rounded border-[#e0e0e0] text-[#F87701] focus:ring-[#F87701] focus:ring-2 bg-white"
137
+ >
138
+ </label>
139
+
140
+ <label class="flex items-center justify-between py-3 px-3 hover:bg-[#f6f9fc] rounded-lg transition-all duration-200">
141
+ <span class="text-[14px] text-[#2e3438]">wrap</span>
142
+ <input
143
+ type="checkbox"
144
+ bind:checked={wrap}
145
+ class="w-5 h-5 rounded border-[#e0e0e0] text-[#F87701] focus:ring-[#F87701] focus:ring-2 bg-white"
146
+ >
147
+ </label>
148
+ </div>
149
+ </div>
150
+
151
+ <!-- Options Controls -->
152
+ <div class="min-w-[250px]">
153
+ <h4 class="text-xs font-bold text-[#2e3438] uppercase tracking-wider mb-4">Options</h4>
154
+
155
+ <div class="space-y-2">
156
+ <label for="show-search" class="block text-sm font-medium text-[#374151] mb-2">Search Type</label>
157
+ <div class="relative">
158
+ <select
159
+ id="show-search"
160
+ bind:value={show_search}
161
+ class="w-full px-4 py-3 !rounded-sm text-sm border-2 border-[#e5e7eb] rounded-lg bg-[#f9fafb] text-[#374151] focus:ring-2 focus:ring-[#F87701] focus:border-[#F87701] focus:bg-white transition-all duration-200 appearance-none cursor-pointer shadow-sm"
162
+ >
163
+ <option value="none">None</option>
164
+ <option value="search">Search</option>
165
+ <option value="filter">Filter</option>
166
+ </select>
167
+ <div class="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none">
168
+ <svg class="w-4 h-4 text-[#9ca3af]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
169
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
170
+ </svg>
171
+ </div>
172
+ </div>
173
+ <p class="text-xs text-[#6b7280] mt-1">Configure search functionality</p>
174
+ </div>
175
+ </div>
176
+
177
+ <!-- Number Controls -->
178
+ <div class="min-w-[250px]">
179
+ <h4 class="text-xs font-bold text-[#2e3438] uppercase tracking-wider mb-4">Numbers</h4>
180
+
181
+ <div class="space-y-6">
182
+ <div class="space-y-2">
183
+ <label for="max-height" class="block text-sm font-medium text-[#374151]">Maximum Height</label>
184
+ <div class="relative">
185
+ <input
186
+ id="max-height"
187
+ type="number"
188
+ bind:value={max_height}
189
+ min="200"
190
+ max="1000"
191
+ step="50"
192
+ class="w-full px-4 py-3 text-sm !rounded-sm border-2 border-[#e5e7eb] rounded-lg bg-[#f9fafb] text-[#374151] focus:ring-2 focus:ring-[#F87701] focus:border-[#F87701] focus:bg-white transition-all duration-200 shadow-sm"
193
+ >
194
+ <div class="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none">
195
+ <span class="text-xs text-[#9ca3af] font-medium">px</span>
196
+ </div>
197
+ </div>
198
+ <p class="text-xs text-[#6b7280]">Height constraint for the table (200-1000px)</p>
199
+ </div>
200
+
201
+ <div class="space-y-2">
202
+ <label for="max-chars" class="block text-sm font-medium text-[#374151]">Character Limit</label>
203
+ <input
204
+ id="max-chars"
205
+ type="number"
206
+ bind:value={max_chars}
207
+ min="10"
208
+ max="1000"
209
+ step="10"
210
+ placeholder="No limit"
211
+ class="w-full px-4 py-3 text-sm !rounded-sm border-2 border-[#e5e7eb] rounded-lg bg-[#f9fafb] text-[#374151] placeholder-[#9ca3af] focus:ring-2 focus:ring-[#F87701] focus:border-[#F87701] focus:bg-white transition-all duration-200 shadow-sm"
212
+ >
213
+ <p class="text-xs text-[#6b7280]">Maximum characters per cell (leave empty for no limit)</p>
214
+ </div>
215
+ </div>
216
+ </div>
217
+
218
+ <!-- Text Controls -->
219
+ <div class="min-w-[250px]">
220
+ <h4 class="text-xs font-bold text-[#2e3438] uppercase tracking-wider mb-4">Text</h4>
221
+
222
+ <div class="space-y-2">
223
+ <label for="label-input" class="block text-sm font-medium text-[#374151]">Table Label</label>
224
+ <div class="relative">
225
+ <input
226
+ id="label-input"
227
+ type="text"
228
+ bind:value={label}
229
+ placeholder="Enter table label..."
230
+ class="w-full px-4 py-3 text-sm !rounded-sm border-2 border-[#e5e7eb] rounded-lg bg-[#f9fafb] text-[#374151] placeholder-[#9ca3af] focus:ring-2 focus:ring-[#F87701] focus:border-[#F87701] focus:bg-white transition-all duration-200 shadow-sm"
231
+ >
232
+ <div class="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none">
233
+ <svg class="w-4 h-4 text-[#9ca3af]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
234
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a.997.997 0 01-1.414 0l-7-7A1.997 1.997 0 013 12V7a4 4 0 014-4z"></path>
235
+ </svg>
236
+ </div>
237
+ </div>
238
+ <p class="text-xs text-[#6b7280]">Display label shown above the dataframe</p>
239
+ </div>
240
+ </div>
241
+ </div>
242
+
243
+ {:else if activeControlsTab === "actions"}
244
+ <!-- Actions Tab Content -->
245
+ <div class="flex space-x-8 min-w-max">
246
+
247
+ <!-- Data Manipulation Section -->
248
+ <div class="min-w-[300px]">
249
+ <div>
250
+ <h4 class="text-xs font-bold text-[#2e3438] uppercase tracking-wider mb-3">Data Manipulation</h4>
251
+ <p class="text-sm text-[#64748b] mb-5 leading-relaxed">Add new rows and columns to the dataframe</p>
252
+
253
+ <div class="grid grid-cols-1 gap-3">
254
+ <button
255
+ on:click={addCustomColumn}
256
+ class="flex items-center justify-center px-6 py-4 text-sm font-semibold bg-gradient-to-r from-[#F87701] to-[#0f8bda] text-white rounded-xl hover:from-[#0f8bda] hover:to-[#0569b5] focus:ring-2 focus:ring-[#F87701] focus:ring-offset-2 transition-all duration-200"
257
+ >
258
+ <svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
259
+ <path stroke-linecap="round" stroke-linejoin="round" d="M12 4v16m8-8H4"></path>
260
+ </svg>
261
+ Add Column
262
+ </button>
263
+
264
+ <button
265
+ on:click={addCustomRow}
266
+ class="flex items-center justify-center px-6 py-4 text-sm font-semibold bg-gradient-to-r from-[#10b981] to-[#059669] text-white rounded-xl hover:from-[#059669] hover:to-[#047857] focus:ring-2 focus:ring-[#10b981] focus:ring-offset-2 transition-all duration-200"
267
+ >
268
+ <svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
269
+ <path stroke-linecap="round" stroke-linejoin="round" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
270
+ </svg>
271
+ Add Row
272
+ </button>
273
+ </div>
274
+ </div>
275
+
276
+ <div class="border-t border-[#e2e8f0] pt-6">
277
+ <h4 class="text-xs font-bold text-[#2e3438] uppercase tracking-wider mb-3">Export Options</h4>
278
+ <p class="text-sm text-[#64748b] mb-5 leading-relaxed">Export your data in different formats</p>
279
+
280
+ <div class="grid grid-cols-1 gap-3">
281
+ <button
282
+ class="flex items-center justify-center px-4 py-3 text-sm font-medium bg-[#f59e0b] text-white rounded-lg hover:bg-[#d97706] focus:ring-2 focus:ring-[#f59e0b] focus:ring-offset-2 transition-all duration-200 shadow-sm"
283
+ >
284
+ <svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
285
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
286
+ </svg>
287
+ Export as CSV
288
+ </button>
289
+
290
+ <button
291
+ class="flex items-center justify-center px-4 py-3 text-sm font-medium bg-[#8b5cf6] text-white rounded-lg hover:bg-[#7c3aed] focus:ring-2 focus:ring-[#8b5cf6] focus:ring-offset-2 transition-all duration-200 shadow-sm"
292
+ >
293
+ <svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
294
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 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 2"></path>
295
+ </svg>
296
+ Copy to Clipboard
297
+ </button>
298
+ </div>
299
+ </div>
300
+ </div>
301
+
302
+ <!-- Export & Reset Actions -->
303
+ <div class="min-w-[300px]">
304
+ <h4 class="text-xs font-bold text-[#2e3438] uppercase tracking-wider mb-3">Export Options</h4>
305
+ <p class="text-sm text-[#64748b] mb-5 leading-relaxed">Export your data in different formats</p>
306
+
307
+ <div class="grid grid-cols-1 gap-3 mb-6">
308
+ <button
309
+ class="flex items-center justify-center px-5 py-3 text-sm font-semibold bg-gradient-to-r from-[#f59e0b] to-[#d97706] text-white rounded-xl hover:from-[#d97706] hover:to-[#b45309] focus:ring-2 focus:ring-[#f59e0b] focus:ring-offset-2 transition-all duration-200"
310
+ >
311
+ <svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
312
+ <path stroke-linecap="round" stroke-linejoin="round" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
313
+ </svg>
314
+ Export CSV
315
+ </button>
316
+
317
+ <button
318
+ class="flex items-center justify-center px-5 py-3 text-sm font-semibold bg-gradient-to-r from-[#6366f1] to-[#4f46e5] text-white rounded-xl hover:from-[#4f46e5] hover:to-[#4338ca] focus:ring-2 focus:ring-[#6366f1] focus:ring-offset-2 transition-all duration-200"
319
+ >
320
+ <svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
321
+ <path stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 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 2"></path>
322
+ </svg>
323
+ Copy to Clipboard
324
+ </button>
325
+ </div>
326
+
327
+ <div class="border-t border-[#e2e8f0] pt-4">
328
+ <h4 class="text-xs font-bold text-[#2e3438] uppercase tracking-wider mb-3">Reset Actions</h4>
329
+ <button
330
+ class="w-full flex items-center justify-center px-5 py-3 text-sm font-semibold bg-gradient-to-r from-[#ef4444] to-[#dc2626] text-white rounded-xl hover:from-[#dc2626] hover:to-[#b91c1c] focus:ring-2 focus:ring-[#ef4444] focus:ring-offset-2 transition-all duration-200"
331
+ >
332
+ <svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
333
+ <path stroke-linecap="round" stroke-linejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
334
+ </svg>
335
+ Reset Data
336
+ </button>
337
+ </div>
338
+ </div>
339
+ </div>
340
+ {/if}
341
+ </div>
342
+ </div>
src/lib/SyntaxHighlighter.svelte ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import Prism from 'prismjs';
4
+
5
+ // Import the languages we need
6
+ import 'prismjs/components/prism-typescript';
7
+ import 'prismjs/components/prism-javascript';
8
+ import 'prismjs/components/prism-json';
9
+
10
+ // Import the theme CSS
11
+ import 'prismjs/themes/prism-tomorrow.css';
12
+
13
+ export let code: string;
14
+ export let language: string = 'typescript';
15
+ export let class_name: string = '';
16
+
17
+ let highlightedCode = '';
18
+
19
+ onMount(() => {
20
+ try {
21
+ highlightedCode = Prism.highlight(code, Prism.languages[language] || Prism.languages.typescript, language);
22
+ } catch (error) {
23
+ console.warn('Syntax highlighting failed:', error);
24
+ highlightedCode = code;
25
+ }
26
+ });
27
+
28
+ $: if (code) {
29
+ try {
30
+ highlightedCode = Prism.highlight(code, Prism.languages[language] || Prism.languages.typescript, language);
31
+ } catch (error) {
32
+ console.warn('Syntax highlighting failed:', error);
33
+ highlightedCode = code;
34
+ }
35
+ }
36
+ </script>
37
+
38
+ <div class="syntax-highlighter {class_name}">
39
+ <pre class="language-{language}"><code class="language-{language}">{@html highlightedCode}</code></pre>
40
+ </div>
41
+
42
+ <style>
43
+ .syntax-highlighter {
44
+ border-radius: 0.75rem;
45
+ overflow-x: auto;
46
+ }
47
+
48
+ .syntax-highlighter pre {
49
+ margin: 0;
50
+ padding: 1.5rem;
51
+ font-size: 0.875rem;
52
+ line-height: 1.625;
53
+ background-color: #1e293b;
54
+ border: 1px solid #334155;
55
+ font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
56
+ }
57
+
58
+ .syntax-highlighter code {
59
+ color: #e2e8f0;
60
+ font-family: inherit;
61
+ }
62
+
63
+ /* Custom syntax highlighting colors */
64
+ :global(.syntax-highlighter .token.comment) {
65
+ color: #64748b;
66
+ }
67
+
68
+ :global(.syntax-highlighter .token.string) {
69
+ color: #10b981;
70
+ }
71
+
72
+ :global(.syntax-highlighter .token.number) {
73
+ color: #f59e0b;
74
+ }
75
+
76
+ :global(.syntax-highlighter .token.keyword) {
77
+ color: #8b5cf6;
78
+ }
79
+
80
+ :global(.syntax-highlighter .token.function) {
81
+ color: #06b6d4;
82
+ }
83
+
84
+ :global(.syntax-highlighter .token.operator) {
85
+ color: #e2e8f0;
86
+ }
87
+
88
+ :global(.syntax-highlighter .token.punctuation) {
89
+ color: #94a3b8;
90
+ }
91
+
92
+ :global(.syntax-highlighter .token.property) {
93
+ color: #f472b6;
94
+ }
95
+
96
+ :global(.syntax-highlighter .token.boolean) {
97
+ color: #f59e0b;
98
+ }
99
+
100
+ :global(.syntax-highlighter .token.class-name) {
101
+ color: #06b6d4;
102
+ }
103
+
104
+ :global(.syntax-highlighter .token.tag) {
105
+ color: #8b5cf6;
106
+ }
107
+
108
+ :global(.syntax-highlighter .token.attr-name) {
109
+ color: #f472b6;
110
+ }
111
+
112
+ :global(.syntax-highlighter .token.attr-value) {
113
+ color: #10b981;
114
+ }
115
+ </style>
src/lib/assets/favicon.svg ADDED
src/lib/index.ts ADDED
@@ -0,0 +1 @@
 
 
1
+ // place files you want to import through the `$lib` alias in this folder.
src/lib/sampleData.ts ADDED
@@ -0,0 +1,253 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export const sampleDatasets = {
2
+ basic: {
3
+ data: [
4
+ ["Alice Johnson", 25, "true", "2023-01-15"],
5
+ ["Bob Smith", 30, "false", "2023-02-20"],
6
+ ["Charlie Brown", 35, "true", "2023-03-10"],
7
+ ["Diana Prince", 28, "false", "2023-04-05"],
8
+ ["Eve Wilson", 32, "true", "2023-05-12"],
9
+ ],
10
+ headers: ["Name", "Age", "Active", "Date"],
11
+ datatypes: ["str", "number", "bool", "date"],
12
+ config: {
13
+ editable: true,
14
+ show_row_numbers: true,
15
+ show_search: "search",
16
+ show_copy_button: true,
17
+ show_fullscreen_button: true,
18
+ max_height: 400,
19
+ label: "Employee Database",
20
+ show_label: true,
21
+ line_breaks: true,
22
+ wrap: false,
23
+ },
24
+ },
25
+ compact: {
26
+ data: [
27
+ ["AAPL", 150.25, 2.34, "πŸ“ˆ"],
28
+ ["GOOGL", 2845.67, -15.23, "πŸ“‰"],
29
+ ["MSFT", 412.89, 8.91, "πŸ“ˆ"],
30
+ ["TSLA", 238.45, -4.12, "πŸ“‰"],
31
+ ["AMZN", 3456.78, 12.34, "πŸ“ˆ"],
32
+ ["META", 487.23, -2.87, "πŸ“‰"],
33
+ ["NVDA", 875.23, 45.67, "πŸ“ˆ"],
34
+ ["NFLX", 425.18, -8.92, "πŸ“‰"],
35
+ ],
36
+ headers: ["Symbol", "Price", "Change", "Trend"],
37
+ datatypes: ["str", "number", "number", "str"],
38
+ config: {
39
+ editable: false,
40
+ show_row_numbers: false,
41
+ show_search: "none",
42
+ show_copy_button: false,
43
+ show_fullscreen_button: false,
44
+ max_height: 200,
45
+ label: "",
46
+ show_label: false,
47
+ line_breaks: false,
48
+ wrap: false,
49
+ },
50
+ },
51
+ filterable: {
52
+ data: [
53
+ ["John Doe", "Engineering", "Senior", 95000, "true"],
54
+ ["Jane Smith", "Marketing", "Manager", 75000, "true"],
55
+ ["Mike Johnson", "Sales", "Junior", 45000, "false"],
56
+ ["Sarah Wilson", "Engineering", "Lead", 120000, "true"],
57
+ ["David Brown", "HR", "Specialist", 55000, "true"],
58
+ ["Emily Davis", "Finance", "Analyst", 65000, "false"],
59
+ ["Tom Anderson", "Engineering", "Junior", 70000, "true"],
60
+ ["Lisa Garcia", "Marketing", "Senior", 85000, "false"],
61
+ ["James Miller", "Sales", "Manager", 90000, "true"],
62
+ ["Maria Rodriguez", "Finance", "Senior", 95000, "true"],
63
+ ],
64
+ headers: ["Name", "Department", "Level", "Salary", "Remote"],
65
+ datatypes: ["str", "str", "str", "number", "bool"],
66
+ config: {
67
+ editable: true,
68
+ show_row_numbers: true,
69
+ show_search: "filter",
70
+ show_copy_button: true,
71
+ show_fullscreen_button: true,
72
+ max_height: 350,
73
+ label: "Employee Directory with Filters",
74
+ show_label: true,
75
+ line_breaks: true,
76
+ wrap: false,
77
+ },
78
+ },
79
+ readonly: {
80
+ data: [
81
+ ["Q1 2023", "Revenue", 125000, "15% increase from Q4"],
82
+ ["Q1 2023", "Expenses", 85000, "5% decrease from Q4"],
83
+ ["Q1 2023", "Profit", 40000, "35% increase from Q4"],
84
+ ["Q2 2023", "Revenue", 145000, "16% increase from Q1"],
85
+ ["Q2 2023", "Expenses", 90000, "6% increase from Q1"],
86
+ ["Q2 2023", "Profit", 55000, "37% increase from Q1"],
87
+ ],
88
+ headers: ["Period", "Category", "Amount", "Change"],
89
+ datatypes: ["str", "str", "number", "str"],
90
+ config: {
91
+ editable: false,
92
+ show_row_numbers: true,
93
+ show_search: "search",
94
+ show_copy_button: true,
95
+ show_fullscreen_button: true,
96
+ max_height: 300,
97
+ label: "Financial Report (Read-Only)",
98
+ show_label: true,
99
+ line_breaks: true,
100
+ wrap: true,
101
+ },
102
+ },
103
+ wrapped: {
104
+ data: [
105
+ [
106
+ "Bug Fix",
107
+ "Fixed critical issue with user authentication that was causing login failures for users with special characters in their email addresses",
108
+ "High",
109
+ "Completed",
110
+ ],
111
+ [
112
+ "Feature",
113
+ "Implemented new dashboard analytics with real-time data visualization including charts, graphs, and interactive elements",
114
+ "Medium",
115
+ "In Progress",
116
+ ],
117
+ [
118
+ "Enhancement",
119
+ "Optimized database queries to improve application performance and reduce load times across all user-facing pages",
120
+ "Low",
121
+ "Testing",
122
+ ],
123
+ [
124
+ "Bug Fix",
125
+ "Resolved mobile responsiveness issues on the checkout page that were affecting user experience on smaller screens",
126
+ "High",
127
+ "Completed",
128
+ ],
129
+ ],
130
+ headers: ["Type", "Description", "Priority", "Status"],
131
+ datatypes: ["str", "str", "str", "str"],
132
+ config: {
133
+ editable: true,
134
+ show_row_numbers: true,
135
+ show_search: "search",
136
+ show_copy_button: true,
137
+ show_fullscreen_button: true,
138
+ max_height: 400,
139
+ label: "Task Management with Text Wrapping",
140
+ show_label: true,
141
+ line_breaks: true,
142
+ wrap: true,
143
+ max_chars: 100,
144
+ },
145
+ },
146
+ large: {
147
+ data: Array.from({ length: 50 }, (_, i) => [
148
+ `User ${i + 1}`,
149
+ `user${i + 1}@example.com`,
150
+ Math.floor(Math.random() * 50) + 18,
151
+ Math.random() > 0.5 ? "true" : "false",
152
+ new Date(
153
+ 2023,
154
+ Math.floor(Math.random() * 12),
155
+ Math.floor(Math.random() * 28) + 1
156
+ )
157
+ .toISOString()
158
+ .split("T")[0],
159
+ (Math.random() * 100000).toFixed(2),
160
+ Math.floor(Math.random() * 5) + 1,
161
+ ]),
162
+ headers: [
163
+ "Name",
164
+ "Email",
165
+ "Age",
166
+ "Active",
167
+ "Join Date",
168
+ "Revenue",
169
+ "Rating",
170
+ ],
171
+ datatypes: ["str", "str", "number", "bool", "date", "number", "number"],
172
+ config: {
173
+ editable: true,
174
+ show_row_numbers: true,
175
+ show_search: "filter",
176
+ show_copy_button: true,
177
+ show_fullscreen_button: true,
178
+ max_height: 500,
179
+ label: "Large Dataset (50 rows)",
180
+ show_label: true,
181
+ line_breaks: true,
182
+ wrap: false,
183
+ },
184
+ },
185
+ mixed: {
186
+ data: [
187
+ [
188
+ "**Product A**",
189
+ 99.99,
190
+ "Available",
191
+ "https://example.com",
192
+ "<span style='color: green'>βœ“ In Stock</span>",
193
+ ],
194
+ [
195
+ "*Product B*",
196
+ 149.99,
197
+ "Out of Stock",
198
+ "https://example.com",
199
+ "<span style='color: red'>βœ— Unavailable</span>",
200
+ ],
201
+ [
202
+ "Product C",
203
+ 79.99,
204
+ "Limited",
205
+ "https://example.com",
206
+ "<span style='color: orange'>⚠ Few Left</span>",
207
+ ],
208
+ [
209
+ "~~Product D~~",
210
+ 199.99,
211
+ "Discontinued",
212
+ "https://example.com",
213
+ "<span style='color: gray'>- Discontinued</span>",
214
+ ],
215
+ ],
216
+ headers: ["Product", "Price", "Status", "URL", "Availability"],
217
+ datatypes: ["markdown", "number", "str", "str", "html"],
218
+ config: {
219
+ editable: true,
220
+ show_row_numbers: false,
221
+ show_search: "search",
222
+ show_copy_button: true,
223
+ show_fullscreen_button: true,
224
+ max_height: 300,
225
+ label: "Rich Content (HTML & Markdown)",
226
+ show_label: true,
227
+ line_breaks: true,
228
+ wrap: false,
229
+ },
230
+ },
231
+ minimal: {
232
+ data: [
233
+ ["Task 1", "Complete"],
234
+ ["Task 2", "Pending"],
235
+ ["Task 3", "In Progress"],
236
+ ["Task 4", "Complete"],
237
+ ],
238
+ headers: ["Task", "Status"],
239
+ datatypes: ["str", "str"],
240
+ config: {
241
+ editable: true,
242
+ show_row_numbers: false,
243
+ show_search: "none",
244
+ show_copy_button: false,
245
+ show_fullscreen_button: false,
246
+ max_height: 200,
247
+ label: "",
248
+ show_label: false,
249
+ line_breaks: false,
250
+ wrap: false,
251
+ },
252
+ },
253
+ };
tailwind.config.js ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ /** @type {import('tailwindcss').Config} */
2
+ export default {
3
+ content: ["./src/**/*.{html,js,svelte,ts}"],
4
+ theme: {
5
+ extend: {},
6
+ },
7
+ plugins: [],
8
+ };
vite.config.ts CHANGED
@@ -4,4 +4,16 @@ import { svelte } from '@sveltejs/vite-plugin-svelte'
4
  // https://vite.dev/config/
5
  export default defineConfig({
6
  plugins: [svelte()],
 
 
 
 
 
 
 
 
 
 
 
 
7
  })
 
4
  // https://vite.dev/config/
5
  export default defineConfig({
6
  plugins: [svelte()],
7
+ base: './',
8
+ build: {
9
+ outDir: 'dist',
10
+ assetsDir: 'assets',
11
+ sourcemap: false,
12
+ minify: 'esbuild',
13
+ rollupOptions: {
14
+ output: {
15
+ manualChunks: undefined,
16
+ }
17
+ }
18
+ }
19
  })