{"id":28435789,"url":"https://github.com/pondpilot/pondpilot-widget","last_synced_at":"2026-03-14T16:32:52.586Z","repository":{"id":295858527,"uuid":"991379614","full_name":"pondpilot/pondpilot-widget","owner":"pondpilot","description":"Transform static SQL code blocks into interactive snippets powered by DuckDB WASM.","archived":false,"fork":false,"pushed_at":"2025-05-27T23:25:27.000Z","size":56,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-27T22:38:29.705Z","etag":null,"topics":["duckdb","js","sql","wasm"],"latest_commit_sha":null,"homepage":"https://widget.pondpilot.io","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pondpilot.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-27T14:33:34.000Z","updated_at":"2025-06-06T08:49:59.000Z","dependencies_parsed_at":"2025-06-27T22:31:49.738Z","dependency_job_id":"f517fca5-e7b2-4fa3-a9b7-f88ec104acc0","html_url":"https://github.com/pondpilot/pondpilot-widget","commit_stats":null,"previous_names":["pondpilot/pondpilot-widget"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/pondpilot/pondpilot-widget","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pondpilot%2Fpondpilot-widget","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pondpilot%2Fpondpilot-widget/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pondpilot%2Fpondpilot-widget/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pondpilot%2Fpondpilot-widget/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pondpilot","download_url":"https://codeload.github.com/pondpilot/pondpilot-widget/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pondpilot%2Fpondpilot-widget/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262900086,"owners_count":23381657,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["duckdb","js","sql","wasm"],"created_at":"2025-06-05T21:08:41.126Z","updated_at":"2026-03-14T16:32:52.543Z","avatar_url":"https://github.com/pondpilot.png","language":"JavaScript","readme":"# PondPilot Widget\n\n[![npm version](https://img.shields.io/npm/v/pondpilot-widget.svg)](https://www.npmjs.com/package/pondpilot-widget)\n[![npm downloads](https://img.shields.io/npm/dm/pondpilot-widget.svg)](https://www.npmjs.com/package/pondpilot-widget)\n[![CDN hits](https://img.shields.io/jsdelivr/npm/hm/pondpilot-widget)](https://www.jsdelivr.com/package/npm/pondpilot-widget)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n\nTransform static SQL code blocks into interactive snippets powered by DuckDB WASM.\n\n🎮 **[Try it live](https://widget.pondpilot.io)** - Interactive examples and demos\n\n## Features\n\n- 🦆 **DuckDB in the Browser** - Full SQL analytics engine running locally\n- ✨ **Zero Backend** - Everything runs client-side in WebAssembly\n- 🎨 **Syntax Highlighting** - Beautiful SQL code formatting with cursor preservation\n- ⚡ **Instant Results** - Execute queries with one click or Ctrl/Cmd+Enter\n- 🔧 **Easy Integration** - Works with any static site or documentation\n- 🧩 **Configurable** - Tweak selectors, auto-init, editable mode, and UI affordances\n- 🗂️ **Init Queries** - Install DuckDB extensions or run setup SQL once per page\n- ♻️ **Reset Queries** - Optionally run cleanup SQL when the editor resets\n- 🎨 **Custom Themes** - Extend light/dark defaults or register fully custom palettes\n- ♿ **Accessible** - Full ARIA support and keyboard navigation\n- 🎯 **Lightweight** - Only ~22KB minified, loads DuckDB on-demand\n- 🌙 **Dark Mode** - Automatic theme detection or manual control\n- 🔒 **Secure** - No data leaves the browser, CSP-compatible\n- 📁 **Relative Paths** - Automatic resolution of relative parquet file paths\n\n## Installation\n\n### CDN (Recommended)\nThe easiest way to get started is via CDN:\n\n```html\n\u003c!-- Latest version --\u003e\n\u003cscript src=\"https://unpkg.com/pondpilot-widget\"\u003e\u003c/script\u003e\n\n\u003c!-- Specific version (recommended for production) --\u003e\n\u003cscript src=\"https://unpkg.com/pondpilot-widget@1.4.0\"\u003e\u003c/script\u003e\n\n\u003c!-- Alternative CDN --\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/pondpilot-widget\"\u003e\u003c/script\u003e\n```\n\n### Package Manager\nFor projects using a bundler:\n\n#### NPM\n```bash\nnpm install pondpilot-widget\n```\n\n#### Yarn\n```bash\nyarn add pondpilot-widget\n```\n\n## Quick Start\n\n### 1. Add the Script Tag\n\n```html\n\u003cscript src=\"https://unpkg.com/pondpilot-widget\"\u003e\u003c/script\u003e\n```\n\n### 2. Mark Your SQL Code Blocks\n\n```html\n\u003cpre class=\"pondpilot-snippet\"\u003e\nSELECT\n  'Hello World' as greeting,\n  42 as answer,\n  CURRENT_DATE as today;\n\u003c/pre\u003e\n```\n\n### 3. That's It!\n\nThe widget automatically transforms your static code blocks into interactive SQL editors.\n\n### Alternative: Using a Bundler\n\nIf you're using a bundler like Webpack, Vite, or Parcel:\n\n```javascript\nimport \"pondpilot-widget\";\n```\n\n## Usage Examples\n\n### Basic Configuration\n\n```javascript\n// Configure before initialization\nwindow.PondPilot.config.theme = 'dark';\nwindow.PondPilot.config.showPoweredBy = false;\n\n// Or initialize with options\nnew PondPilot.Widget(element, {\n  theme: 'dark',\n  editable: false,\n  showPoweredBy: false\n});\n```\n\n### Framework Integration\n\n#### React\n```jsx\nimport { useEffect, useRef } from \"react\";\nimport \"pondpilot-widget\";\n\nfunction SQLEditor({ sql, ...options }) {\n  const ref = useRef(null);\n\n  useEffect(() =\u003e {\n    if (ref.current) {\n      const widget = new window.PondPilot.Widget(ref.current, options);\n      return () =\u003e widget.destroy();\n    }\n  }, []);\n\n  return (\n    \u003cpre ref={ref} className=\"pondpilot-snippet\"\u003e\n      {sql}\n    \u003c/pre\u003e\n  );\n}\n```\n\n## Advanced Configuration\n\nThe runtime exposes a global API with ergonomic helpers:\n\n```javascript\nconst { config, init, create, destroy, registerTheme, getConfig } = window.PondPilot;\n\n// Merge default configuration\nconfig({\n  selector: \"pre.sql-demo\",\n  baseUrl: \"https://cdn.example.com/datasets\",\n  autoInit: false,\n  initQueries: [\"INSTALL httpfs\", \"LOAD httpfs\"],\n  resetQueries: [\"DROP TABLE IF EXISTS scratch_table;\"],\n});\n\n// Register a custom theme and apply it via data-theme or options.theme\nregisterTheme(\"sunset\", {\n  extends: \"light\",\n  config: {\n    bgColor: \"#ffedd5\",\n    textColor: \"#7c2d12\",\n    borderColor: \"#f97316\",\n    editorBg: \"#fff7ed\",\n    editorText: \"#7c2d12\",\n    editorFocusBg: \"#fed7aa\",\n    controlsBg: \"rgba(249, 115, 22, 0.12)\",\n    primaryBg: \"#f97316\",\n    primaryText: \"#ffffff\",\n    primaryHover: \"#ea580c\",\n    secondaryBg: \"rgba(249, 115, 22, 0.16)\",\n    secondaryText: \"#7c2d12\",\n    secondaryHover: \"rgba(249, 115, 22, 0.28)\",\n    mutedText: \"#9a3412\",\n    errorText: \"#dc2626\",\n    errorBg: \"rgba(220, 38, 38, 0.08)\",\n    errorBorder: \"rgba(220, 38, 38, 0.2)\",\n    tableHeaderBg: \"rgba(249, 115, 22, 0.16)\",\n    tableHeaderText: \"#7c2d12\",\n    tableHover: \"rgba(249, 115, 22, 0.12)\",\n    syntaxKeyword: \"#c2410c\",\n    syntaxString: \"#047857\",\n    syntaxNumber: \"#7c3aed\",\n    syntaxComment: \"#9a3412\",\n    syntaxSpecial: \"#dc2626\",\n    syntaxIdentifier: \"#facc15\",\n    fontFamily: \"Inter, system-ui, sans-serif\",\n    editorFontFamily: \"'JetBrains Mono', monospace\",\n    fontSize: \"14px\",\n    editorFontSize: \"13px\",\n    buttonFontSize: \"13px\",\n    metadataFontSize: \"12px\",\n  },\n});\n\n// Manually mount widgets when needed\ndocument.querySelectorAll(\"pre.sql-demo\").forEach((node) =\u003e {\n  window.PondPilot.create(node, { theme: \"sunset\" });\n});\n```\n\n### Data attributes\n\nPer-snippet overrides can be expressed declaratively:\n\n```html\n\u003cpre\n  class=\"pondpilot-snippet\"\n  data-theme=\"sunset\"\n  data-base-url=\"https://cdn.example.com/data\"\n  data-init-queries='[\"LOAD httpfs\"]'\n\u003e\n  \u003ccode\u003eSELECT * FROM 'sales.parquet';\u003c/code\u003e\n\u003c/pre\u003e\n```\n\nSupported attributes include:\n\n- `data-theme`\n- `data-base-url`\n- `data-editable`\n- `data-show-powered-by`\n- `data-init-queries` (semicolon or JSON array)\n\n## API Summary\n\n- `PondPilot.init(target?, options?)` – initialize matching elements (defaults to `config.selector`)\n- `PondPilot.create(element, options?)` – mount a single instance on demand\n- `PondPilot.destroy(target?)` – remove widgets (defaults to all)\n- `PondPilot.config(partial)` – merge configuration\n- `PondPilot.getConfig()` – inspect current configuration\n- `PondPilot.registerTheme(name, definition)` – extend theming system\n- `PondPilot.Widget` – constructor for manual control (`new PondPilot.Widget(element, options)`)\n\n#### Vue\n```vue\n\u003ctemplate\u003e\n  \u003cpre ref=\"editor\" class=\"pondpilot-snippet\"\u003e{{ sql }}\u003c/pre\u003e\n\u003c/template\u003e\n\n\u003cscript\u003e\nimport 'pondpilot-widget';\n\nexport default {\n  props: ['sql', 'options'],\n  mounted() {\n    this.widget = new window.PondPilot.Widget(this.$refs.editor, this.options);\n  },\n  beforeUnmount() {\n    this.widget?.destroy();\n  }\n}\n\u003c/script\u003e\n```\n\n### Markdown/Documentation Sites\n\n#### Docusaurus\n```javascript\n// In docusaurus.config.js\nmodule.exports = {\n  scripts: [\n    'https://unpkg.com/pondpilot-widget'\n  ],\n  // ...\n};\n```\n\n#### VitePress\n```javascript\n// In .vitepress/theme/index.js\nimport DefaultTheme from 'vitepress/theme';\nimport 'pondpilot-widget';\n\nexport default DefaultTheme;\n```\n\n## Local Examples (in this repo)\n\nYou can run a small examples site from the examples/ folder:\n\n1) Serve the repository root (so examples/ is web‑served):\n\n```bash\npython3 -m http.server 8080\n# then open http://localhost:8080/examples/index.html\n```\n\n2) Local .duckdb database demo (optional):\n\n```bash\n# create a tiny demo DB at examples/data/blog.duckdb\nuv run examples/create-blog-db.py   # or: pip install duckdb pandas \u0026\u0026 python3 examples/create-blog-db.py\n\n# open the demo page\nopen http://localhost:8080/examples/local-duckdb.html\n```\n\n3) Relative Parquet path handling demo (optional):\n\n```bash\ncd examples/relative-paths\npython3 create-test-data.py  # creates analytics.parquet in this directory\ncd ../..\nopen http://localhost:8080/examples/relative-paths/test-relative-paths.html\n```\n\n4) A5 Geospatial Extension demo with interactive map:\n\n```bash\n# No setup required - just open the demo\nopen http://localhost:8080/examples/a5-geospatial-demo.html\n```\n\nNotes:\n- The example pages in this repo load the widget from ../src/ for local development. You can switch them to use the CDN by replacing the script tag with the CDN snippet from Installation.\n- The local .duckdb example shows how to provide an external DuckDB WASM instance to the widget and open a DB file served over HTTP.\n- The relative‑paths example demonstrates how the widget auto‑resolves relative parquet file paths in queries.\n- The A5 demo shows how to use DuckDB community extensions for geospatial analysis with interactive Leaflet map visualization.\n\n## Configuration Options\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `selector` | string | `\"pre.pondpilot-snippet, .pondpilot-snippet pre\"` | CSS selector for SQL blocks |\n| `theme` | string | `\"light\"` | Theme: \"light\" or \"dark\" |\n| `editable` | boolean | `true` | Allow editing SQL code |\n| `showPoweredBy` | boolean | `true` | Show \"Powered by PondPilot\" branding |\n| `baseUrl` | string | `\"http://localhost:5173\"` | PondPilot instance URL |\n| `autoInit` | boolean | `true` | Auto-initialize on DOM ready |\n\n## API Reference\n\n### Global Object\n```javascript\nwindow.PondPilot = {\n  init(),           // Initialize all widgets\n  destroy(),        // Clean up all widgets\n  config: {},       // Global configuration\n  Widget: class {}  // Widget constructor\n};\n```\n\n### Widget Instance\n```javascript\nconst widget = new PondPilot.Widget(element, options);\n\n// Methods\nawait widget.run();      // Execute SQL query\nwidget.reset();          // Reset to original code\nawait widget.cleanup();  // Clean up resources\nwidget.destroy();        // Destroy widget\n```\n\n## Security Considerations\n\n1. **Content Security Policy (CSP)**\n   ```\n   Content-Security-Policy:\n     script-src 'self' https://unpkg.com https://cdn.jsdelivr.net;\n     worker-src 'self' blob: https://cdn.jsdelivr.net;\n     connect-src 'self' https://cdn.jsdelivr.net;\n   ```\n\n2. **Subresource Integrity (SRI)**\n   ```html\n   \u003cscript\n    src=\"https://unpkg.com/pondpilot-widget@1.4.0\"\n     integrity=\"sha384-[hash]\"\n     crossorigin=\"anonymous\"\u003e\n   \u003c/script\u003e\n   ```\n\n## Browser Support\n\n- Chrome/Edge 88+\n- Firefox 89+\n- Safari 15+\n\nRequires:\n- WebAssembly\n- Web Workers\n- ES2018+\n\n## Working with Parquet Files\n\nThe widget supports loading parquet files from various sources:\n\n### Direct HTTP URLs\n```sql\nSELECT * FROM 'https://example.com/data.parquet' LIMIT 10;\n```\n\n### Relative Paths (New in v1.1.0)\nThe widget automatically resolves relative paths to absolute URLs:\n\n```sql\n-- All of these formats are supported:\nSELECT * FROM 'data.parquet';\nSELECT * FROM './data.parquet';\nSELECT * FROM '/data.parquet';\n```\n\nWhen using relative paths:\n- Files must be accessible via HTTP from the same server\n- The widget resolves paths relative to the current page URL\n- For local development, ensure your files are served by a web server\n\n## Performance Tips\n\n1. **Lazy Loading**: DuckDB is only loaded when first query runs\n2. **Shared Instance**: Multiple widgets share the same DuckDB instance\n3. **Resource Cleanup**: Widgets automatically clean up when removed from DOM\n4. **File Caching**: Registered parquet files are cached to avoid duplicate downloads\n\n## Changelog\n\nSee [CHANGELOG.md](https://github.com/pondpilot/pondpilot-widget/blob/main/CHANGELOG.md) for release history.\n\n## License\n\nMIT © PondPilot\n\n## Contributing\n\nContributions welcome! Please read our [contributing guide](https://github.com/pondpilot/pondpilot-widget/blob/main/CONTRIBUTING.md).\n\n### Local development\n\n```bash\nnpm install       # install dependencies\nnpm run format    # apply Prettier formatting\nnpm test          # run the Vitest suite\n```\n\nPrefer `just`? We provide a lightweight `justfile` with the same commands (`just format`, `just test`, etc.).\n\n## Support\n\n- 🐛 [Issue Tracker](https://github.com/pondpilot/pondpilot-widget/issues)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpondpilot%2Fpondpilot-widget","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpondpilot%2Fpondpilot-widget","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpondpilot%2Fpondpilot-widget/lists"}