dr-widget 0.1.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dr_widget-0.1.5/PKG-INFO +62 -0
- dr_widget-0.1.5/README.md +49 -0
- dr_widget-0.1.5/pyproject.toml +41 -0
- dr_widget-0.1.5/src/dr_widget/__init__.py +5 -0
- dr_widget-0.1.5/src/dr_widget/py.typed +0 -0
- dr_widget-0.1.5/src/dr_widget/widgets/__init__.py +5 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/.gitignore +24 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/.vscode/extensions.json +3 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/README.md +89 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/__init__.py +283 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/components.json +16 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/index.html +12 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/jsrepo.json +18 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/package.json +49 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/postcss.config.js +6 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/public/fonts/Inter-roman.var.woff2 +0 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/public/vite.svg +1 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/App.svelte +62 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/ConfigFileManager.svelte +605 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/app.css +134 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/index.js +5 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/@test_state.json +20 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/Counter.svelte +10 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/file-drop/BrowseConfigsPanel.svelte +137 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/file-drop/ComplexJsonViewer.svelte +94 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/file-drop/ConfigViewerPanel.svelte +282 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/file-drop/LoadedConfigPreview.svelte +74 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/file-drop/SaveConfigPanel.svelte +449 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/file-drop/SelectedFileRow.svelte +38 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/file-drop/SelectedFilesList.svelte +30 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/file-drop/SimpleJsonViewer.svelte +405 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/badge/badge.svelte +50 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/badge/index.ts +2 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/button/button.svelte +128 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/button/index.ts +27 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/card/card-action.svelte +20 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/card/card-content.svelte +15 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/card/card-description.svelte +20 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/card/card-footer.svelte +20 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/card/card-header.svelte +23 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/card/card-title.svelte +20 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/card/card.svelte +23 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/card/index.ts +25 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/dialog/dialog-close.svelte +11 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/dialog/dialog-content.svelte +47 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/dialog/dialog-description.svelte +21 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/dialog/dialog-footer.svelte +24 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/dialog/dialog-header.svelte +24 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/dialog/dialog-overlay.svelte +24 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/dialog/dialog-title.svelte +21 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/dialog/dialog-trigger.svelte +11 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/dialog/index.ts +41 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer-close.svelte +11 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer-content.svelte +41 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer-description.svelte +21 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer-footer.svelte +24 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer-header.svelte +24 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer-nested.svelte +16 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer-overlay.svelte +24 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer-title.svelte +21 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer-trigger.svelte +11 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/drawer.svelte +16 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/drawer/index.ts +45 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/empty/empty-content.svelte +23 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/empty/empty-description.svelte +23 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/empty/empty-header.svelte +20 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/empty/empty-media.svelte +41 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/empty/empty-title.svelte +20 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/empty/empty.svelte +23 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/empty/index.ts +22 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field-content.svelte +20 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field-description.svelte +25 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field-error.svelte +58 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field-group.svelte +23 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field-label.svelte +26 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field-legend.svelte +29 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field-separator.svelte +38 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field-set.svelte +24 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field-title.svelte +23 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/field/field.svelte +53 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/field/index.ts +33 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/file-drop-zone/file-drop-zone.svelte +178 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/file-drop-zone/index.ts +29 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/file-drop-zone/types.ts +51 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/item/index.ts +34 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item-actions.svelte +20 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item-content.svelte +20 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item-description.svelte +24 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item-footer.svelte +20 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item-group.svelte +21 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item-header.svelte +20 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item-media.svelte +42 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item-separator.svelte +19 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item-title.svelte +20 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/item/item.svelte +60 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/label/index.ts +7 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/label/label.svelte +20 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/modal/index.ts +13 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/modal/modal-content.svelte +29 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/modal/modal-description.svelte +20 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/modal/modal-footer.svelte +29 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/modal/modal-header.svelte +29 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/modal/modal-title.svelte +20 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/modal/modal-trigger.svelte +24 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/modal/modal.svelte +24 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/modal/modal.svelte.ts +32 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/separator/index.ts +7 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/separator/separator.svelte +21 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/tabs/index.ts +16 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/tabs/tabs-content.svelte +17 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/tabs/tabs-list.svelte +20 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/tabs/tabs-trigger.svelte +20 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/components/ui/tabs/tabs.svelte +19 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/hooks/use-file-bindings.ts +189 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/react/JsonTreeCanvas.tsx +207 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/utils/config-format.ts +113 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/utils/utils.ts +21 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/lib/utils.ts +17 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/src/main.js +7 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/static/fonts/Inter-roman.var.woff2 +0 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/static/index.js +9719 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/static/style.css +1 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/static/vite.svg +1 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/svelte.config.js +8 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/tailwind.config.js +12 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/tsconfig.json +28 -0
- dr_widget-0.1.5/src/dr_widget/widgets/config_file_manager/vite.config.js +36 -0
dr_widget-0.1.5/PKG-INFO
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: dr-widget
|
|
3
|
+
Version: 0.1.5
|
|
4
|
+
Summary: Widgets to use with marimo notebooks
|
|
5
|
+
Author: Danielle Rothermel
|
|
6
|
+
Author-email: Danielle Rothermel <danielle.rothermel@gmail.com>
|
|
7
|
+
Requires-Dist: anywidget>=0.9.18
|
|
8
|
+
Requires-Dist: marimo>=0.19.4
|
|
9
|
+
Requires-Dist: pydantic>=2.12.4
|
|
10
|
+
Requires-Dist: traitlets>=5.14.3
|
|
11
|
+
Requires-Python: >=3.11
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# dr_widget
|
|
15
|
+
|
|
16
|
+
dr_widget is a hybrid Python/Svelte project for building reusable AnyWidget components that can be dropped into Marimo notebooks today and exported to full Svelte apps later. The repository currently ships a Config File Manager widget, but the layout is designed to host additional widgets.
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Install JS dependencies (root + workspace)
|
|
22
|
+
bun install
|
|
23
|
+
|
|
24
|
+
# Live-reload the Config File Manager widget in a browser
|
|
25
|
+
bun run dev:config-file-manager
|
|
26
|
+
|
|
27
|
+
# Produce the optimized bundle used by AnyWidget
|
|
28
|
+
bun run build
|
|
29
|
+
|
|
30
|
+
# Build the Python distributions (wheel + sdist)
|
|
31
|
+
uv build
|
|
32
|
+
|
|
33
|
+
# Launch the Marimo demo notebook
|
|
34
|
+
marimo run notebooks/config_file_manager_widget.py
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Prerequisites: Bun ≥ 1.0, Node-compatible environment, Python ≥ 3.11 with `uv`, and Marimo ≥ 0.17.6.
|
|
38
|
+
|
|
39
|
+
## Repository Layout
|
|
40
|
+
|
|
41
|
+
- `src/dr_widget/` – Python package exposing AnyWidget classes.
|
|
42
|
+
- `widgets/config_file_manager/` – widget workspace (Svelte source in `src/`, build output in `static/`).
|
|
43
|
+
- `src/ConfigFileManager.svelte` – orchestration layer wiring bindings into the panel components.
|
|
44
|
+
- `src/lib/hooks/use-file-bindings.ts` – shared logic for syncing AnyWidget traitlets.
|
|
45
|
+
- `src/lib/components/` – shadcn-style UI primitives and panels, including a config viewer card with both a tree view and graph view for JSON payloads.
|
|
46
|
+
- `docs/` – additional reference material (architecture, development workflows).
|
|
47
|
+
- `notebooks/config_file_manager_widget.py` – Marimo notebook that exercises the Config File Manager widget.
|
|
48
|
+
|
|
49
|
+
## Documentation
|
|
50
|
+
|
|
51
|
+
- [Architecture Overview](docs/architecture.md) – how Python, AnyWidget, and Svelte fit together.
|
|
52
|
+
- [Development Workflow](docs/development.md) – commands for widget builds, packaging, and notebooks.
|
|
53
|
+
- [Repository Guidelines](AGENTS.md) – coding standards, contracts, and contribution checklist.
|
|
54
|
+
|
|
55
|
+
## Contributing
|
|
56
|
+
|
|
57
|
+
1. Work inside a dedicated branch.
|
|
58
|
+
2. Run `bun run build`, `npx svelte-check`, and `uv build` before opening a PR.
|
|
59
|
+
3. Update the notebook and docs when you add or change widget behaviour.
|
|
60
|
+
4. Follow the commit and PR practices outlined in `AGENTS.md`.
|
|
61
|
+
|
|
62
|
+
Please open an issue if you hit build problems or want to discuss new widgets.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# dr_widget
|
|
2
|
+
|
|
3
|
+
dr_widget is a hybrid Python/Svelte project for building reusable AnyWidget components that can be dropped into Marimo notebooks today and exported to full Svelte apps later. The repository currently ships a Config File Manager widget, but the layout is designed to host additional widgets.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install JS dependencies (root + workspace)
|
|
9
|
+
bun install
|
|
10
|
+
|
|
11
|
+
# Live-reload the Config File Manager widget in a browser
|
|
12
|
+
bun run dev:config-file-manager
|
|
13
|
+
|
|
14
|
+
# Produce the optimized bundle used by AnyWidget
|
|
15
|
+
bun run build
|
|
16
|
+
|
|
17
|
+
# Build the Python distributions (wheel + sdist)
|
|
18
|
+
uv build
|
|
19
|
+
|
|
20
|
+
# Launch the Marimo demo notebook
|
|
21
|
+
marimo run notebooks/config_file_manager_widget.py
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Prerequisites: Bun ≥ 1.0, Node-compatible environment, Python ≥ 3.11 with `uv`, and Marimo ≥ 0.17.6.
|
|
25
|
+
|
|
26
|
+
## Repository Layout
|
|
27
|
+
|
|
28
|
+
- `src/dr_widget/` – Python package exposing AnyWidget classes.
|
|
29
|
+
- `widgets/config_file_manager/` – widget workspace (Svelte source in `src/`, build output in `static/`).
|
|
30
|
+
- `src/ConfigFileManager.svelte` – orchestration layer wiring bindings into the panel components.
|
|
31
|
+
- `src/lib/hooks/use-file-bindings.ts` – shared logic for syncing AnyWidget traitlets.
|
|
32
|
+
- `src/lib/components/` – shadcn-style UI primitives and panels, including a config viewer card with both a tree view and graph view for JSON payloads.
|
|
33
|
+
- `docs/` – additional reference material (architecture, development workflows).
|
|
34
|
+
- `notebooks/config_file_manager_widget.py` – Marimo notebook that exercises the Config File Manager widget.
|
|
35
|
+
|
|
36
|
+
## Documentation
|
|
37
|
+
|
|
38
|
+
- [Architecture Overview](docs/architecture.md) – how Python, AnyWidget, and Svelte fit together.
|
|
39
|
+
- [Development Workflow](docs/development.md) – commands for widget builds, packaging, and notebooks.
|
|
40
|
+
- [Repository Guidelines](AGENTS.md) – coding standards, contracts, and contribution checklist.
|
|
41
|
+
|
|
42
|
+
## Contributing
|
|
43
|
+
|
|
44
|
+
1. Work inside a dedicated branch.
|
|
45
|
+
2. Run `bun run build`, `npx svelte-check`, and `uv build` before opening a PR.
|
|
46
|
+
3. Update the notebook and docs when you add or change widget behaviour.
|
|
47
|
+
4. Follow the commit and PR practices outlined in `AGENTS.md`.
|
|
48
|
+
|
|
49
|
+
Please open an issue if you hit build problems or want to discuss new widgets.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "dr-widget"
|
|
3
|
+
version = "0.1.5"
|
|
4
|
+
description = "Widgets to use with marimo notebooks"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Danielle Rothermel", email = "danielle.rothermel@gmail.com" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.11"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"anywidget>=0.9.18",
|
|
12
|
+
"marimo>=0.19.4",
|
|
13
|
+
"pydantic>=2.12.4",
|
|
14
|
+
"traitlets>=5.14.3",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[build-system]
|
|
18
|
+
requires = ["uv_build>=0.9.7,<0.10.0"]
|
|
19
|
+
build-backend = "uv_build"
|
|
20
|
+
|
|
21
|
+
[tool.uv.build-backend]
|
|
22
|
+
source-include = ["src/dr_widget/widgets/config_file_manager/static/**"]
|
|
23
|
+
source-exclude = [
|
|
24
|
+
"src/dr_widget/widgets/config_file_manager/node_modules",
|
|
25
|
+
"src/dr_widget/widgets/config_file_manager/node_modules/**",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[dependency-groups]
|
|
29
|
+
dev = [
|
|
30
|
+
"python-lsp-server>=1.13.1",
|
|
31
|
+
"ruff>=0.14.4",
|
|
32
|
+
"watchdog>=6.0.0",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[tool.ruff]
|
|
36
|
+
include = ["src/**/*.py", "notebooks/**/*.py"]
|
|
37
|
+
exclude = ["tests/**/*.py", "dist/", "docs/"]
|
|
38
|
+
line-length = 88
|
|
39
|
+
|
|
40
|
+
[tool.basedpyright]
|
|
41
|
+
typeCheckingMode = "off"
|
|
File without changes
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Logs
|
|
2
|
+
logs
|
|
3
|
+
*.log
|
|
4
|
+
npm-debug.log*
|
|
5
|
+
yarn-debug.log*
|
|
6
|
+
yarn-error.log*
|
|
7
|
+
pnpm-debug.log*
|
|
8
|
+
lerna-debug.log*
|
|
9
|
+
|
|
10
|
+
node_modules
|
|
11
|
+
dist
|
|
12
|
+
dist-ssr
|
|
13
|
+
*.local
|
|
14
|
+
|
|
15
|
+
# Editor directories and files
|
|
16
|
+
.vscode/*
|
|
17
|
+
!.vscode/extensions.json
|
|
18
|
+
.idea
|
|
19
|
+
.DS_Store
|
|
20
|
+
*.suo
|
|
21
|
+
*.ntvs*
|
|
22
|
+
*.njsproj
|
|
23
|
+
*.sln
|
|
24
|
+
*.sw?
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Config File Manager Widget
|
|
2
|
+
|
|
3
|
+
The `dr_widget` package ships an AnyWidget-powered config file manager so notebooks can load, inspect, edit, and save JSON configuration blobs without leaving the browser. The frontend lives under `src/dr_widget/widgets/config_file_manager`, is built with Svelte + Vite via Bun, and syncs its state to Python traitlets.
|
|
4
|
+
|
|
5
|
+
## Repository Layout
|
|
6
|
+
|
|
7
|
+
- `src/dr_widget/widgets/config_file_manager/__init__.py` – AnyWidget class with initialization helpers and traitlet contracts.
|
|
8
|
+
- `src/dr_widget/widgets/config_file_manager/src/` – Svelte workspace (components live under `lib/`).
|
|
9
|
+
- `src/dr_widget/widgets/config_file_manager/static/` – Built bundle consumed by AnyWidget.
|
|
10
|
+
- `notebooks/config_file_manager_widget.py` – Marimo demo that exercises the widget end-to-end.
|
|
11
|
+
|
|
12
|
+
## Traitlets
|
|
13
|
+
|
|
14
|
+
| Traitlet | Direction | Description |
|
|
15
|
+
| --- | --- | --- |
|
|
16
|
+
| `current_state` | ↔ | JSON string representing **user data only** (no metadata). |
|
|
17
|
+
| `baseline_state` | ↔ | Last saved value of `current_state`, used for dirty detection/diffs. |
|
|
18
|
+
| `version` | ↔ | String metadata displayed in the UI and written to disk alongside `current_state` (now nested under `metadata.version`). |
|
|
19
|
+
| `config_file` | ↔ | Path to the backing file (may be relative today). |
|
|
20
|
+
| `config_file_display` | ↔ | UI-friendly label derived from `config_file`. |
|
|
21
|
+
| `files` | ↔ | JSON array of uploaded files (`{ name, size, type }`). |
|
|
22
|
+
| `file_count` | ← | Derived from `files.length`; read-only in the UI. |
|
|
23
|
+
| `error` | ↔ | User-facing error message cleared automatically on recovery. |
|
|
24
|
+
|
|
25
|
+
Python helper properties (`current_data`, `baseline_data`, `is_dirty`) expose parsed state for notebooks.
|
|
26
|
+
|
|
27
|
+
## Initialization Patterns
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
ConfigFileManager() # empty widget, user loads file via UI
|
|
31
|
+
|
|
32
|
+
ConfigFileManager(config_dict={"orchard": ["Basin"]}, version="exp_v1")
|
|
33
|
+
# - current_state populated with data dict
|
|
34
|
+
# - baseline_state empty → dirty until saved
|
|
35
|
+
# - config_file defaults to "exp_v1.json"
|
|
36
|
+
|
|
37
|
+
ConfigFileManager(config_file="/path/to/existing.json")
|
|
38
|
+
# - loads and migrates the file into new format
|
|
39
|
+
# - baseline_state matches current_state (clean)
|
|
40
|
+
# - version pulled from file metadata
|
|
41
|
+
|
|
42
|
+
ConfigFileManager(
|
|
43
|
+
config_file="/tmp/new.json",
|
|
44
|
+
config_dict={"selections": {"foo": True}},
|
|
45
|
+
version="v2",
|
|
46
|
+
)
|
|
47
|
+
# - writes wrapped payload {metadata:{version,saved_at},data}
|
|
48
|
+
# - baseline_state matches current_state
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Files saved through the UI (or via `config_file` + `config_dict`) are always written as:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"metadata": {
|
|
56
|
+
"version": "v1",
|
|
57
|
+
"saved_at": "2025-11-12T10:30:00Z"
|
|
58
|
+
},
|
|
59
|
+
"data": { ... user data ... }
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Older files that only contain `selections` or embed metadata at the top level are migrated into this structure when loaded, with legacy `version`/`saved_at` values relocated under `metadata`.
|
|
64
|
+
|
|
65
|
+
## Frontend Behavior
|
|
66
|
+
|
|
67
|
+
- `use-file-bindings.ts` manages read/write loops for every synced traitlet so Marimo reactivity stays intact.
|
|
68
|
+
- `ConfigFileManager.svelte` derives dirty state by comparing `current_state` vs `baseline_state`, shows the currently loaded file name/version, and exposes Browse + Save panels.
|
|
69
|
+
- `SaveConfigPanel.svelte` wraps the current data with metadata before writing to disk (File System Access API when available, otherwise download).
|
|
70
|
+
|
|
71
|
+
## Build & Test
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
bun install
|
|
75
|
+
npx svelte-check --tsconfig src/dr_widget/widgets/config_file_manager/tsconfig.json
|
|
76
|
+
bun run build:config-file-manager
|
|
77
|
+
bun run build # aggregates widgets (currently same as line above)
|
|
78
|
+
uv build # packages the Python wheel with fresh static assets
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Manual validation: run `marimo run notebooks/config_file_manager_widget.py`, load/upload JSON configs (including legacy "selections" files), edit values, and save to disk. Confirm dirty badge toggles correctly and version changes propagate between the sidebar and save panel.
|
|
82
|
+
|
|
83
|
+
## Contributing Tips
|
|
84
|
+
|
|
85
|
+
- Shared UI lives in `src/dr_widget/widgets/config_file_manager/src/lib/{components,hooks}`; prefer reusing hooks like `use-file-bindings`.
|
|
86
|
+
- Keep Tailwind utility classes grouped logically (layout → spacing → color → effects).
|
|
87
|
+
- Treat `node_modules/` as generated; never edit or commit them.
|
|
88
|
+
- Run `bunx prettier --write src/dr_widget/widgets/config_file_manager/src` before opening a PR.
|
|
89
|
+
- Document new traitlets or metadata fields in `docs/architecture.md` and notebook demos to keep Python + Svelte in sync.
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
"""AnyWidget bindings for the config file manager widget."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from datetime import datetime, timezone
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, Dict, Optional
|
|
9
|
+
|
|
10
|
+
import anywidget
|
|
11
|
+
import traitlets
|
|
12
|
+
|
|
13
|
+
__all__ = ["ConfigFileManager"]
|
|
14
|
+
|
|
15
|
+
_STATIC_DIR = Path(__file__).parent / "static"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _normalize_version(value: Optional[str]) -> str:
|
|
19
|
+
if value is None:
|
|
20
|
+
return "default_v0"
|
|
21
|
+
value = str(value).strip()
|
|
22
|
+
return value or "default_v0"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _default_config_name(version: str) -> str:
|
|
26
|
+
safe = ''.join(ch if ch.isalnum() or ch in {"-", "_"} else "_" for ch in version)
|
|
27
|
+
safe = safe or "default_v0"
|
|
28
|
+
return f"{safe}.json"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _resolve_config_path(value: str | Path | None) -> str:
|
|
32
|
+
if value is None:
|
|
33
|
+
return ""
|
|
34
|
+
|
|
35
|
+
raw = str(value).strip()
|
|
36
|
+
if not raw:
|
|
37
|
+
return ""
|
|
38
|
+
|
|
39
|
+
candidate = Path(raw).expanduser()
|
|
40
|
+
if not candidate.is_absolute():
|
|
41
|
+
candidate = Path.cwd() / candidate
|
|
42
|
+
|
|
43
|
+
return str(candidate.resolve())
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _serialize_user_state(data: Dict[str, Any]) -> str:
|
|
47
|
+
"""Return a JSON string for the user-facing state or an empty string."""
|
|
48
|
+
|
|
49
|
+
if not data:
|
|
50
|
+
return ""
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
return json.dumps(data, sort_keys=True, separators=(",", ":"))
|
|
54
|
+
except (TypeError, ValueError) as exc: # pragma: no cover - defensive
|
|
55
|
+
raise ValueError("Config state must be JSON serializable") from exc
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _ensure_mapping(value: Optional[Dict[str, Any]]) -> Dict[str, Any]:
|
|
59
|
+
if value is None:
|
|
60
|
+
return {}
|
|
61
|
+
if not isinstance(value, dict):
|
|
62
|
+
raise TypeError("config_dict must be a mapping of keys to values")
|
|
63
|
+
return value
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _utc_timestamp() -> str:
|
|
67
|
+
return datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _normalize_payload(payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
71
|
+
"""Ensure the payload follows the new metadata/data contract."""
|
|
72
|
+
|
|
73
|
+
normalized: Dict[str, Any] = dict(payload)
|
|
74
|
+
data = normalized.get("data")
|
|
75
|
+
|
|
76
|
+
metadata_candidate = normalized.get("metadata")
|
|
77
|
+
if isinstance(metadata_candidate, dict):
|
|
78
|
+
metadata: Dict[str, Any] = dict(metadata_candidate)
|
|
79
|
+
else:
|
|
80
|
+
metadata = {}
|
|
81
|
+
|
|
82
|
+
for legacy_key in ("version", "saved_at"):
|
|
83
|
+
if legacy_key in normalized and legacy_key not in metadata:
|
|
84
|
+
metadata[legacy_key] = normalized.pop(legacy_key)
|
|
85
|
+
|
|
86
|
+
if not isinstance(data, dict):
|
|
87
|
+
user_data: Dict[str, Any] = {}
|
|
88
|
+
|
|
89
|
+
selections = normalized.pop("selections", None)
|
|
90
|
+
if isinstance(selections, dict):
|
|
91
|
+
user_data.setdefault("selections", selections)
|
|
92
|
+
|
|
93
|
+
for key in list(normalized.keys()):
|
|
94
|
+
if key in {"version", "saved_at", "data", "metadata"}:
|
|
95
|
+
continue
|
|
96
|
+
user_data[key] = normalized.pop(key)
|
|
97
|
+
|
|
98
|
+
data = user_data
|
|
99
|
+
|
|
100
|
+
normalized["metadata"] = metadata
|
|
101
|
+
normalized["data"] = data if isinstance(data, dict) else {}
|
|
102
|
+
return normalized
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _load_config_from_file(path: Path) -> Dict[str, Any]:
|
|
106
|
+
try:
|
|
107
|
+
raw = path.read_text(encoding="utf-8")
|
|
108
|
+
except FileNotFoundError:
|
|
109
|
+
raise
|
|
110
|
+
except OSError as exc: # pragma: no cover - filesystem specific
|
|
111
|
+
raise IOError(f"Unable to read config file: {path}") from exc
|
|
112
|
+
|
|
113
|
+
try:
|
|
114
|
+
parsed = json.loads(raw)
|
|
115
|
+
except json.JSONDecodeError as exc:
|
|
116
|
+
raise ValueError(f"Config file must contain valid JSON: {path}") from exc
|
|
117
|
+
|
|
118
|
+
if not isinstance(parsed, dict):
|
|
119
|
+
raise ValueError("Config file root must be a JSON object")
|
|
120
|
+
|
|
121
|
+
return _normalize_payload(parsed)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _write_config_to_file(path: Path, *, data: Dict[str, Any], version: str) -> str:
|
|
125
|
+
saved_at = _utc_timestamp()
|
|
126
|
+
payload = {
|
|
127
|
+
"metadata": {
|
|
128
|
+
"version": version,
|
|
129
|
+
"saved_at": saved_at,
|
|
130
|
+
"save_path": str(path),
|
|
131
|
+
},
|
|
132
|
+
"data": data,
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
serialized = json.dumps(payload, indent=2, sort_keys=True)
|
|
136
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
137
|
+
path.write_text(serialized + "\n", encoding="utf-8")
|
|
138
|
+
return saved_at
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _file_binding_entry(path: Path) -> Dict[str, Any]:
|
|
142
|
+
try:
|
|
143
|
+
size = path.stat().st_size
|
|
144
|
+
except OSError:
|
|
145
|
+
size = 0
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
"name": path.name,
|
|
149
|
+
"size": size,
|
|
150
|
+
"type": "application/json",
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class ConfigFileManager(anywidget.AnyWidget):
|
|
155
|
+
"""Config file manager widget for notebooks."""
|
|
156
|
+
|
|
157
|
+
# AnyWidget expects module references pointing at the built assets on disk.
|
|
158
|
+
_esm = _STATIC_DIR / "index.js"
|
|
159
|
+
_css = _STATIC_DIR / "style.css"
|
|
160
|
+
|
|
161
|
+
current_state = traitlets.Unicode("").tag(sync=True)
|
|
162
|
+
baseline_state = traitlets.Unicode("").tag(sync=True)
|
|
163
|
+
config_file = traitlets.Unicode("").tag(sync=True)
|
|
164
|
+
config_file_display = traitlets.Unicode("").tag(sync=True)
|
|
165
|
+
version = traitlets.Unicode("default_v0").tag(sync=True)
|
|
166
|
+
saved_at = traitlets.Unicode("").tag(sync=True)
|
|
167
|
+
files = traitlets.Unicode("[]").tag(sync=True)
|
|
168
|
+
file_count = traitlets.Int(0).tag(sync=True)
|
|
169
|
+
error = traitlets.Unicode("").tag(sync=True)
|
|
170
|
+
|
|
171
|
+
def __init__(
|
|
172
|
+
self,
|
|
173
|
+
config_file: str | Path | None = None,
|
|
174
|
+
config_dict: Optional[Dict[str, Any]] = None,
|
|
175
|
+
version: str = "default_v0",
|
|
176
|
+
**kwargs: Any,
|
|
177
|
+
) -> None:
|
|
178
|
+
super().__init__(**kwargs)
|
|
179
|
+
|
|
180
|
+
normalized_version = _normalize_version(version)
|
|
181
|
+
self.version = normalized_version
|
|
182
|
+
self.current_state = ""
|
|
183
|
+
self.baseline_state = ""
|
|
184
|
+
self.config_file = ""
|
|
185
|
+
self.saved_at = ""
|
|
186
|
+
|
|
187
|
+
if config_file is None and config_dict is None:
|
|
188
|
+
return
|
|
189
|
+
|
|
190
|
+
if config_file is None:
|
|
191
|
+
user_data = _ensure_mapping(config_dict)
|
|
192
|
+
self.current_state = _serialize_user_state(user_data)
|
|
193
|
+
# No baseline until the data is persisted via the UI.
|
|
194
|
+
self.baseline_state = ""
|
|
195
|
+
default_name = _default_config_name(self.version)
|
|
196
|
+
default_path = _resolve_config_path(default_name)
|
|
197
|
+
self.config_file = default_path
|
|
198
|
+
return
|
|
199
|
+
|
|
200
|
+
resolved_path = _resolve_config_path(config_file)
|
|
201
|
+
path = Path(resolved_path)
|
|
202
|
+
|
|
203
|
+
if config_dict is not None:
|
|
204
|
+
if path.exists():
|
|
205
|
+
raise FileExistsError(
|
|
206
|
+
f"Config file already exists: {path}. Refusing to overwrite."
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
user_data = _ensure_mapping(config_dict)
|
|
210
|
+
_write_config_to_file(path, data=user_data, version=self.version)
|
|
211
|
+
elif not path.exists():
|
|
212
|
+
raise FileNotFoundError(f"Config file does not exist: {path}")
|
|
213
|
+
|
|
214
|
+
payload = _load_config_from_file(path)
|
|
215
|
+
file_data = payload.get("data")
|
|
216
|
+
user_state = file_data if isinstance(file_data, dict) else {}
|
|
217
|
+
serialized_state = _serialize_user_state(user_state)
|
|
218
|
+
|
|
219
|
+
metadata = payload.get("metadata")
|
|
220
|
+
if not isinstance(metadata, dict):
|
|
221
|
+
metadata = {}
|
|
222
|
+
|
|
223
|
+
payload_version = metadata.get("version")
|
|
224
|
+
if payload_version is not None:
|
|
225
|
+
version_str = _normalize_version(str(payload_version))
|
|
226
|
+
self.version = version_str
|
|
227
|
+
|
|
228
|
+
self.config_file = str(path)
|
|
229
|
+
self.current_state = serialized_state
|
|
230
|
+
self.baseline_state = serialized_state
|
|
231
|
+
saved_at_value = metadata.get("saved_at")
|
|
232
|
+
if saved_at_value:
|
|
233
|
+
self.saved_at = str(saved_at_value)
|
|
234
|
+
else:
|
|
235
|
+
self.saved_at = ""
|
|
236
|
+
|
|
237
|
+
file_entry = _file_binding_entry(path)
|
|
238
|
+
self.files = json.dumps([file_entry])
|
|
239
|
+
self.file_count = 1
|
|
240
|
+
|
|
241
|
+
def _parse_state(self, value: str) -> Dict[str, Any]:
|
|
242
|
+
if not value:
|
|
243
|
+
return {}
|
|
244
|
+
|
|
245
|
+
try:
|
|
246
|
+
parsed = json.loads(value)
|
|
247
|
+
except json.JSONDecodeError:
|
|
248
|
+
return {}
|
|
249
|
+
|
|
250
|
+
if isinstance(parsed, dict):
|
|
251
|
+
return parsed
|
|
252
|
+
|
|
253
|
+
return {}
|
|
254
|
+
|
|
255
|
+
@property
|
|
256
|
+
def current_data(self) -> Dict[str, Any]:
|
|
257
|
+
"""Return the parsed current_state JSON payload as a dict."""
|
|
258
|
+
|
|
259
|
+
return self._parse_state(self.current_state)
|
|
260
|
+
|
|
261
|
+
@property
|
|
262
|
+
def baseline_data(self) -> Dict[str, Any]:
|
|
263
|
+
"""Return the parsed baseline_state JSON payload as a dict."""
|
|
264
|
+
|
|
265
|
+
return self._parse_state(self.baseline_state)
|
|
266
|
+
|
|
267
|
+
@property
|
|
268
|
+
def is_dirty(self) -> bool:
|
|
269
|
+
"""True if the current state differs from the last saved baseline."""
|
|
270
|
+
|
|
271
|
+
return self.current_data != self.baseline_data
|
|
272
|
+
|
|
273
|
+
@traitlets.validate("config_file")
|
|
274
|
+
def _validate_config_file(self, proposal: traitlets.Bunch) -> str:
|
|
275
|
+
return _resolve_config_path(proposal["value"])
|
|
276
|
+
|
|
277
|
+
@traitlets.observe("config_file")
|
|
278
|
+
def _observe_config_file(self, change: traitlets.Bunch) -> None:
|
|
279
|
+
value = change["new"]
|
|
280
|
+
if value:
|
|
281
|
+
self.config_file_display = Path(value).name
|
|
282
|
+
else:
|
|
283
|
+
self.config_file_display = ""
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://shadcn-svelte.com/schema.json",
|
|
3
|
+
"tailwind": {
|
|
4
|
+
"css": "src/app.css",
|
|
5
|
+
"baseColor": "slate"
|
|
6
|
+
},
|
|
7
|
+
"aliases": {
|
|
8
|
+
"components": "$lib/components",
|
|
9
|
+
"utils": "$lib/utils",
|
|
10
|
+
"ui": "$lib/components/ui",
|
|
11
|
+
"hooks": "$lib/hooks",
|
|
12
|
+
"lib": "$lib"
|
|
13
|
+
},
|
|
14
|
+
"typescript": true,
|
|
15
|
+
"registry": "https://shadcn-svelte.com/registry"
|
|
16
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>File Drop Widget - Dev Preview</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="app"></div>
|
|
10
|
+
<script type="module" src="/src/main.js"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://unpkg.com/jsrepo@2.5.1/schemas/project-config.json",
|
|
3
|
+
"repos": ["@ieedan/shadcn-svelte-extras"],
|
|
4
|
+
"includeTests": false,
|
|
5
|
+
"includeDocs": false,
|
|
6
|
+
"watermark": true,
|
|
7
|
+
"formatter": "prettier",
|
|
8
|
+
"configFiles": {
|
|
9
|
+
"Shadcn Svelte Extras Cursor Rules": "./../../../../.cursor/rules/shadcn-svelte-extras.mdc"
|
|
10
|
+
},
|
|
11
|
+
"paths": {
|
|
12
|
+
"*": "./src/lib",
|
|
13
|
+
"ui": "./src/lib/components/ui",
|
|
14
|
+
"actions": "./src/lib/actions",
|
|
15
|
+
"hooks": "./src/lib/hooks",
|
|
16
|
+
"utils": "./src/lib/utils"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dr-widget/config-file-manager",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "vite build",
|
|
8
|
+
"dev": "vite dev",
|
|
9
|
+
"preview": "vite preview",
|
|
10
|
+
"check": "svelte-check --watch --tsconfig ./tsconfig.json"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@anywidget/svelte": "^0.1.0",
|
|
14
|
+
"@zerodevx/svelte-json-view": "^1.0.11",
|
|
15
|
+
"elkjs": "^0.11.0",
|
|
16
|
+
"lucide-svelte": "^0.552.0",
|
|
17
|
+
"react": "18.2.0",
|
|
18
|
+
"react-dom": "18.2.0",
|
|
19
|
+
"react-zoom-pan-pinch": "^3.7.0",
|
|
20
|
+
"reaflow": "^5.4.1",
|
|
21
|
+
"svelte": "^5.43.2"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@internationalized/date": "^3.8.1",
|
|
25
|
+
"@lucide/svelte": "^0.544.0",
|
|
26
|
+
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
|
27
|
+
"@tailwindcss/postcss": "^4.0.9",
|
|
28
|
+
"@types/bun": "latest",
|
|
29
|
+
"@types/react": "18.2.74",
|
|
30
|
+
"@types/react-dom": "18.2.25",
|
|
31
|
+
"@vitejs/plugin-react-swc": "3.7.0",
|
|
32
|
+
"autoprefixer": "^10.4.20",
|
|
33
|
+
"bits-ui": "^2.11.0",
|
|
34
|
+
"clsx": "^2.1.1",
|
|
35
|
+
"postcss": "^8.4.49",
|
|
36
|
+
"prettier": "^3.6.2",
|
|
37
|
+
"runed": "^0.31.1",
|
|
38
|
+
"svelte-check": "^4.3.3",
|
|
39
|
+
"tailwind-merge": "^3.3.1",
|
|
40
|
+
"tailwind-variants": "^3.1.1",
|
|
41
|
+
"tailwindcss": "^4.1.16",
|
|
42
|
+
"tw-animate-css": "^1.4.0",
|
|
43
|
+
"vaul-svelte": "1.0.0-next.7",
|
|
44
|
+
"vite": "^5.4.11"
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"typescript": "^5.9.3"
|
|
48
|
+
}
|
|
49
|
+
}
|