@bilalba/fig-mcp 1.0.1 → 1.1.3
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.
- package/LICENSE +21 -0
- package/README.md +110 -55
- package/dist/index.js +55 -2
- package/dist/index.js.map +1 -1
- package/dist/inspect-fig.d.ts +1 -1
- package/dist/inspect-fig.d.ts.map +1 -1
- package/dist/inspect-fig.js +7 -3
- package/dist/inspect-fig.js.map +1 -1
- package/dist/web-viewer/build-client.d.ts +1 -0
- package/dist/web-viewer/build-client.d.ts.map +1 -1
- package/dist/web-viewer/build-client.js +32 -5
- package/dist/web-viewer/build-client.js.map +1 -1
- package/dist/web-viewer/client/dist/viewer.js +10 -0
- package/dist/web-viewer/client/index.html +138 -0
- package/dist/web-viewer/client/styles.css +561 -0
- package/package.json +6 -3
- package/dist/debug/debug-stroke-geom.d.ts +0 -2
- package/dist/debug/debug-stroke-geom.d.ts.map +0 -1
- package/dist/debug/debug-stroke-geom.js +0 -67
- package/dist/debug/debug-stroke-geom.js.map +0 -1
- package/dist/debug/debug-transforms.d.ts +0 -2
- package/dist/debug/debug-transforms.d.ts.map +0 -1
- package/dist/debug/debug-transforms.js +0 -97
- package/dist/debug/debug-transforms.js.map +0 -1
- package/dist/debug/debug-vertex.d.ts +0 -2
- package/dist/debug/debug-vertex.d.ts.map +0 -1
- package/dist/debug/debug-vertex.js +0 -72
- package/dist/debug/debug-vertex.js.map +0 -1
- package/dist/debug-group.d.ts +0 -5
- package/dist/debug-group.d.ts.map +0 -1
- package/dist/debug-group.js +0 -44
- package/dist/debug-group.js.map +0 -1
- package/dist/debug-stroke-geom.d.ts +0 -2
- package/dist/debug-stroke-geom.d.ts.map +0 -1
- package/dist/debug-stroke-geom.js +0 -67
- package/dist/debug-stroke-geom.js.map +0 -1
- package/dist/debug-transforms.d.ts +0 -2
- package/dist/debug-transforms.d.ts.map +0 -1
- package/dist/debug-transforms.js +0 -97
- package/dist/debug-transforms.js.map +0 -1
- package/dist/debug-vertex.d.ts +0 -2
- package/dist/debug-vertex.d.ts.map +0 -1
- package/dist/debug-vertex.js +0 -72
- package/dist/debug-vertex.js.map +0 -1
- package/dist/experimental/paint-utils.d.ts +0 -35
- package/dist/experimental/paint-utils.d.ts.map +0 -1
- package/dist/experimental/paint-utils.js +0 -105
- package/dist/experimental/paint-utils.js.map +0 -1
- package/dist/experimental/render-screen-v2.d.ts +0 -32
- package/dist/experimental/render-screen-v2.d.ts.map +0 -1
- package/dist/experimental/render-screen-v2.js +0 -366
- package/dist/experimental/render-screen-v2.js.map +0 -1
- package/dist/experimental/render-screen.d.ts +0 -26
- package/dist/experimental/render-screen.d.ts.map +0 -1
- package/dist/experimental/render-screen.js +0 -547
- package/dist/experimental/render-screen.js.map +0 -1
- package/dist/experimental/render-types.d.ts +0 -43
- package/dist/experimental/render-types.d.ts.map +0 -1
- package/dist/experimental/render-types.js +0 -22
- package/dist/experimental/render-types.js.map +0 -1
- package/dist/experimental/render-utils.d.ts +0 -38
- package/dist/experimental/render-utils.d.ts.map +0 -1
- package/dist/experimental/render-utils.js +0 -126
- package/dist/experimental/render-utils.js.map +0 -1
- package/dist/experimental/screenshot.d.ts +0 -11
- package/dist/experimental/screenshot.d.ts.map +0 -1
- package/dist/experimental/screenshot.js +0 -26
- package/dist/experimental/screenshot.js.map +0 -1
- package/dist/experimental/vector-renderer.d.ts +0 -31
- package/dist/experimental/vector-renderer.d.ts.map +0 -1
- package/dist/experimental/vector-renderer.js +0 -427
- package/dist/experimental/vector-renderer.js.map +0 -1
- package/dist/test-render-v2.d.ts +0 -5
- package/dist/test-render-v2.d.ts.map +0 -1
- package/dist/test-render-v2.js +0 -76
- package/dist/test-render-v2.js.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 bilal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,106 +1,161 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @bilalba/fig-mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
MCP server for parsing `.fig` files. Enables AI assistants to understand and extract design information from the `.fig` file format for implementation guidance.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
- Extract colors, text content, and styling information
|
|
11
|
-
- Find nodes by type or name
|
|
12
|
-
- Get detailed node information for implementation
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @bilalba/fig-mcp
|
|
9
|
+
```
|
|
13
10
|
|
|
14
|
-
|
|
11
|
+
Or use directly with npx:
|
|
15
12
|
|
|
16
13
|
```bash
|
|
17
|
-
|
|
18
|
-
npm run build
|
|
14
|
+
npx @bilalba/fig-mcp --help
|
|
19
15
|
```
|
|
20
16
|
|
|
21
|
-
##
|
|
17
|
+
## Quick Start
|
|
22
18
|
|
|
23
|
-
### As MCP Server
|
|
19
|
+
### As MCP Server (for Claude Desktop)
|
|
24
20
|
|
|
25
|
-
Add to your
|
|
21
|
+
Add to your Claude Desktop configuration (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
|
|
26
22
|
|
|
27
23
|
```json
|
|
28
24
|
{
|
|
29
25
|
"mcpServers": {
|
|
30
26
|
"fig-mcp": {
|
|
31
|
-
"command": "
|
|
32
|
-
"args": ["/
|
|
27
|
+
"command": "npx",
|
|
28
|
+
"args": ["@bilalba/fig-mcp"]
|
|
33
29
|
}
|
|
34
30
|
}
|
|
35
31
|
}
|
|
36
32
|
```
|
|
37
33
|
|
|
38
|
-
|
|
34
|
+
Then ask Claude to parse your `.fig` files:
|
|
35
|
+
|
|
36
|
+
> "Parse my design.fig file and show me the document structure"
|
|
37
|
+
|
|
38
|
+
### Web Viewer
|
|
39
|
+
|
|
40
|
+
Browse and preview `.fig` files in your browser:
|
|
39
41
|
|
|
40
42
|
```bash
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
fig-mcp viewer design.fig
|
|
44
|
+
# Opens http://localhost:3000
|
|
45
|
+
```
|
|
43
46
|
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
Features:
|
|
48
|
+
- Tree navigation with collapsible nodes
|
|
49
|
+
- SVG preview with zoom/pan
|
|
50
|
+
- Node details panel
|
|
51
|
+
- Copy node IDs for MCP tool calls
|
|
46
52
|
|
|
47
|
-
|
|
48
|
-
npx tsx src/inspect-fig.ts design.fig json
|
|
53
|
+
### CLI Inspector
|
|
49
54
|
|
|
50
|
-
|
|
51
|
-
npx tsx src/inspect-fig.ts design.fig stats
|
|
55
|
+
Inspect `.fig` files from the command line:
|
|
52
56
|
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
```bash
|
|
58
|
+
fig-mcp inspect design.fig summary # Show document structure
|
|
59
|
+
fig-mcp inspect design.fig stats # Show node type counts
|
|
60
|
+
fig-mcp inspect design.fig list # List archive contents
|
|
61
|
+
fig-mcp inspect design.fig json # Output simplified JSON
|
|
55
62
|
```
|
|
56
63
|
|
|
64
|
+
## CLI Commands
|
|
65
|
+
|
|
66
|
+
| Command | Description |
|
|
67
|
+
|---------|-------------|
|
|
68
|
+
| `fig-mcp` | Start MCP server (for AI assistants) |
|
|
69
|
+
| `fig-mcp viewer <file> [port]` | Open web viewer |
|
|
70
|
+
| `fig-mcp inspect <file> [cmd]` | Inspect file |
|
|
71
|
+
| `fig-mcp --help` | Show help |
|
|
72
|
+
| `fig-mcp --version` | Show version |
|
|
73
|
+
|
|
57
74
|
## MCP Tools
|
|
58
75
|
|
|
76
|
+
The MCP server exposes the following tools for AI assistants:
|
|
77
|
+
|
|
78
|
+
### Document Structure
|
|
79
|
+
|
|
59
80
|
| Tool | Description |
|
|
60
81
|
|------|-------------|
|
|
61
82
|
| `parse_fig_file` | Parse and return simplified document structure |
|
|
62
|
-
| `get_document_summary` | Text tree of document structure |
|
|
83
|
+
| `get_document_summary` | Text tree of document structure with pagination |
|
|
84
|
+
| `get_tree_summary` | Hierarchical summary for drill-down navigation |
|
|
85
|
+
| `list_pages` | List all pages (canvases) in the document |
|
|
86
|
+
| `get_page_contents` | Get contents of a specific page |
|
|
87
|
+
|
|
88
|
+
### Node Queries
|
|
89
|
+
|
|
90
|
+
| Tool | Description |
|
|
91
|
+
|------|-------------|
|
|
63
92
|
| `find_nodes` | Find nodes by type or name |
|
|
64
|
-
| `get_node_details` | Get details for a node path |
|
|
93
|
+
| `get_node_details` | Get details for a node by path |
|
|
94
|
+
| `get_node_by_id` | Get details for a node by GUID |
|
|
65
95
|
| `get_layout_info` | Get inferred layout properties |
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
|
96
|
+
|
|
97
|
+
### Content Extraction
|
|
98
|
+
|
|
99
|
+
| Tool | Description |
|
|
100
|
+
|------|-------------|
|
|
101
|
+
| `get_text_content` | Extract all text content |
|
|
102
|
+
| `get_colors` | Extract unique color palette |
|
|
103
|
+
| `list_nodes_with_fills` | List nodes with fill paints |
|
|
104
|
+
|
|
105
|
+
### Image & Rendering
|
|
106
|
+
|
|
107
|
+
| Tool | Description |
|
|
108
|
+
|------|-------------|
|
|
109
|
+
| `list_images` | List all images with metadata |
|
|
110
|
+
| `get_image` | Get image by hash (base64) |
|
|
111
|
+
| `get_thumbnail` | Get document thumbnail |
|
|
112
|
+
| `render_screen` | Render node subtree as PNG |
|
|
113
|
+
| `get_vector` | Export vector as SVG, PDF, PNG, or WebP |
|
|
114
|
+
|
|
115
|
+
### Debugging
|
|
116
|
+
|
|
117
|
+
| Tool | Description |
|
|
118
|
+
|------|-------------|
|
|
119
|
+
| `get_schema_info` | Kiwi schema information |
|
|
120
|
+
| `get_raw_message` | Raw decoded message |
|
|
121
|
+
| `list_archive_contents` | List files in the archive |
|
|
122
|
+
| `clear_cache` | Clear file cache |
|
|
70
123
|
|
|
71
124
|
## How It Works
|
|
72
125
|
|
|
73
|
-
1. `.fig` files are ZIP archives containing
|
|
126
|
+
1. `.fig` files are ZIP archives containing:
|
|
127
|
+
- `canvas.fig` - Main document data (kiwi binary format)
|
|
128
|
+
- `meta.json` - File metadata
|
|
129
|
+
- `thumbnail.png` - Preview image
|
|
130
|
+
- `images/` - Image assets
|
|
131
|
+
|
|
74
132
|
2. The `canvas.fig` uses Evan Wallace's [kiwi](https://github.com/evanw/kiwi) binary format
|
|
133
|
+
|
|
75
134
|
3. The kiwi schema is embedded in each file and extracted at parse time
|
|
76
|
-
|
|
135
|
+
|
|
136
|
+
4. Document data is decoded and transformed into structured information
|
|
137
|
+
|
|
77
138
|
5. Layout properties are inferred from node positions and auto-layout settings
|
|
78
139
|
|
|
79
|
-
##
|
|
140
|
+
## Features
|
|
80
141
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
│ └── inspect-fig.ts # CLI tool
|
|
93
|
-
├── kiwi/ # Cloned kiwi library
|
|
94
|
-
├── CLAUDE.md # Development guide
|
|
95
|
-
└── TODO.md # Project roadmap
|
|
96
|
-
```
|
|
142
|
+
- Parse `.fig` files locally without API access
|
|
143
|
+
- Extract document structure, nodes, and hierarchy
|
|
144
|
+
- Infer layout properties (flexbox-like direction, gap, padding, alignment)
|
|
145
|
+
- Extract colors, text content, and styling information
|
|
146
|
+
- Render nodes to PNG screenshots
|
|
147
|
+
- Export vectors as SVG, PDF, PNG, or WebP
|
|
148
|
+
- Full effect support (shadows, blurs)
|
|
149
|
+
|
|
150
|
+
## Requirements
|
|
151
|
+
|
|
152
|
+
- Node.js 18 or higher
|
|
97
153
|
|
|
98
154
|
## Limitations
|
|
99
155
|
|
|
100
156
|
- The `.fig` format is undocumented and may change
|
|
101
|
-
- Some complex properties (vector networks, gradients) may not be fully parsed
|
|
102
|
-
- Blob data (embedded images in fills) is not decoded
|
|
103
157
|
- This is for local `.fig` files only (use a cloud API for hosted files)
|
|
158
|
+
- Some complex properties may not be fully parsed
|
|
104
159
|
|
|
105
160
|
## License
|
|
106
161
|
|
package/dist/index.js
CHANGED
|
@@ -9,8 +9,53 @@ import open from "open";
|
|
|
9
9
|
import { startServer } from "./mcp/server.js";
|
|
10
10
|
import { startHttpServer } from "./http-server.js";
|
|
11
11
|
import { createServer as createViewerServer } from "./web-viewer/server.js";
|
|
12
|
+
import { runInspect } from "./inspect-fig.js";
|
|
13
|
+
import { readFileSync } from "fs";
|
|
14
|
+
import { fileURLToPath } from "url";
|
|
15
|
+
import { dirname, join } from "path";
|
|
12
16
|
const args = process.argv.slice(2);
|
|
13
|
-
|
|
17
|
+
const command = args[0];
|
|
18
|
+
// Get package.json for version
|
|
19
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8"));
|
|
21
|
+
if (command === "--version" || command === "-v") {
|
|
22
|
+
console.log(pkg.version);
|
|
23
|
+
process.exit(0);
|
|
24
|
+
}
|
|
25
|
+
if (command === "--help" || command === "-h" || command === "help") {
|
|
26
|
+
console.log(`
|
|
27
|
+
fig-mcp v${pkg.version} - MCP server for parsing .fig files
|
|
28
|
+
|
|
29
|
+
Usage:
|
|
30
|
+
fig-mcp Start MCP server (for AI assistants)
|
|
31
|
+
fig-mcp viewer <file> [port] Start web viewer for a .fig file
|
|
32
|
+
fig-mcp inspect <file> [command] Inspect a .fig file
|
|
33
|
+
|
|
34
|
+
Viewer:
|
|
35
|
+
Opens a local web UI to browse and preview .fig file contents.
|
|
36
|
+
Default port: 3000
|
|
37
|
+
|
|
38
|
+
Inspect commands:
|
|
39
|
+
list - List archive contents
|
|
40
|
+
schema - Show kiwi schema info
|
|
41
|
+
summary - Show document structure (default)
|
|
42
|
+
raw - Show raw message (truncated)
|
|
43
|
+
json - Output simplified JSON
|
|
44
|
+
stats - Show node type statistics
|
|
45
|
+
|
|
46
|
+
Options:
|
|
47
|
+
--help, -h Show this help
|
|
48
|
+
--version, -v Show version
|
|
49
|
+
|
|
50
|
+
Examples:
|
|
51
|
+
fig-mcp viewer design.fig # Open viewer on port 3000
|
|
52
|
+
fig-mcp viewer design.fig 8080 # Open viewer on port 8080
|
|
53
|
+
fig-mcp inspect design.fig summary # Show document structure
|
|
54
|
+
fig-mcp inspect design.fig stats # Show node type counts
|
|
55
|
+
`);
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
58
|
+
if (command === "viewer") {
|
|
14
59
|
const figFile = args[1];
|
|
15
60
|
const port = parseInt(args[2] || "3000", 10);
|
|
16
61
|
if (!figFile) {
|
|
@@ -22,7 +67,10 @@ if (args[0] === "viewer") {
|
|
|
22
67
|
void open(url);
|
|
23
68
|
});
|
|
24
69
|
}
|
|
25
|
-
else {
|
|
70
|
+
else if (command === "inspect") {
|
|
71
|
+
await runInspect(args.slice(1));
|
|
72
|
+
}
|
|
73
|
+
else if (!command) {
|
|
26
74
|
// Start HTTP server for image serving
|
|
27
75
|
startHttpServer();
|
|
28
76
|
// Exit when stdin closes (MCP client disconnected)
|
|
@@ -35,4 +83,9 @@ else {
|
|
|
35
83
|
process.exit(1);
|
|
36
84
|
});
|
|
37
85
|
}
|
|
86
|
+
else {
|
|
87
|
+
console.error(`Unknown command: ${command}`);
|
|
88
|
+
console.error("Run 'fig-mcp --help' for usage information.");
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
38
91
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,YAAY,IAAI,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,YAAY,IAAI,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5E,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAErC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AAExB,+BAA+B;AAC/B,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AAElF,IAAI,OAAO,KAAK,WAAW,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;IACnE,OAAO,CAAC,GAAG,CAAC;WACH,GAAG,CAAC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BrB,CAAC,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;IACzB,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACxB,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;IAE7C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;QAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,YAAY,GAAG,kBAAkB,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,YAAY,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC,CAAC,CAAC;AACL,CAAC;KAAM,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;IACjC,MAAM,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAClC,CAAC;KAAM,IAAI,CAAC,OAAO,EAAE,CAAC;IACpB,sCAAsC;IACtC,eAAe,EAAE,CAAC;IAElB,mDAAmD;IACnD,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,mBAAmB;IACnB,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QAC5B,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;KAAM,CAAC;IACN,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;IAC7C,OAAO,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;IAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
|
package/dist/inspect-fig.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inspect-fig.d.ts","sourceRoot":"","sources":["../src/inspect-fig.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG"}
|
|
1
|
+
{"version":3,"file":"inspect-fig.d.ts","sourceRoot":"","sources":["../src/inspect-fig.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG;AAcH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA4H9D"}
|
package/dist/inspect-fig.js
CHANGED
|
@@ -13,8 +13,7 @@
|
|
|
13
13
|
* json - Output simplified JSON
|
|
14
14
|
*/
|
|
15
15
|
import { readFigFile, listFigContents, parseCanvasFig, getSchemaInfo, extractDocumentTree, getDocumentSummary, simplifyNode, countNodesByType, } from "./parser/index.js";
|
|
16
|
-
async function
|
|
17
|
-
const args = process.argv.slice(2);
|
|
16
|
+
export async function runInspect(args) {
|
|
18
17
|
if (args.length === 0) {
|
|
19
18
|
console.log(`
|
|
20
19
|
Fig Inspector - Inspect .fig files
|
|
@@ -130,5 +129,10 @@ Commands:
|
|
|
130
129
|
process.exit(1);
|
|
131
130
|
}
|
|
132
131
|
}
|
|
133
|
-
|
|
132
|
+
// Run when executed directly
|
|
133
|
+
const isDirectExecution = import.meta.url === `file://${process.argv[1]}` ||
|
|
134
|
+
process.argv[1]?.endsWith('inspect-fig.ts');
|
|
135
|
+
if (isDirectExecution) {
|
|
136
|
+
runInspect(process.argv.slice(2));
|
|
137
|
+
}
|
|
134
138
|
//# sourceMappingURL=inspect-fig.js.map
|
package/dist/inspect-fig.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inspect-fig.js","sourceRoot":"","sources":["../src/inspect-fig.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG;AAGH,OAAO,EACL,WAAW,EACX,eAAe,EACf,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAE3B,
|
|
1
|
+
{"version":3,"file":"inspect-fig.js","sourceRoot":"","sources":["../src/inspect-fig.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG;AAGH,OAAO,EACL,WAAW,EACX,eAAe,EACf,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAc;IAE7C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;CAaf,CAAC,CAAC;QACC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;IAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;IAErC,IAAI,CAAC;QACH,QAAQ,OAAO,EAAE,CAAC;YAChB,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,QAAQ,CAAC,CAAC;gBACjD,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;gBACjC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;oBAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;gBAC3B,CAAC;gBACD,MAAM;YACR,CAAC;YAED,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;gBAC5C,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBACjD,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAChD,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC1C,OAAO,CAAC,GAAG,CAAC,yBAAyB,UAAU,CAAC,eAAe,MAAM,CAAC,CAAC;gBACvE,KAAK,MAAM,GAAG,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;oBACzC,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC;oBACzC,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;wBAC/B,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;wBAC5C,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,GAAG,SAAS,EAAE,CAAC,CAAC;oBAC5D,CAAC;oBACD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBACrB,CAAC;gBACD,MAAM;YACR,CAAC;YAED,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;gBAC5C,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC9D,OAAO,CAAC,GAAG,CAAC,aAAa,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;gBAEhD,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBACjD,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;gBAE1C,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBACrD,IAAI,QAAQ,EAAE,CAAC;oBACb,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;oBACrC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAC5C,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;oBACjD,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;gBAChE,CAAC;gBACD,MAAM;YACR,CAAC;YAED,KAAK,KAAK,CAAC,CAAC,CAAC;gBACX,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;gBAC5C,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBACjD,IAAI,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;gBACnD,IAAI,IAAI,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC;oBACxB,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,qBAAqB,CAAC;gBAC1D,CAAC;gBACD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAClB,MAAM;YACR,CAAC;YAED,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;gBAC5C,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBACjD,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBACrD,IAAI,QAAQ,EAAE,CAAC;oBACb,MAAM,UAAU,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;oBAC1C,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBACnD,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;oBACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAClB,CAAC;gBACD,MAAM;YACR,CAAC;YAED,KAAK,OAAO,CAAC,CAAC,CAAC;gBACb,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;gBAC5C,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBACjD,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBACrD,IAAI,QAAQ,EAAE,CAAC;oBACb,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;oBAC1C,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;oBACjC,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CACxC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CACxB,CAAC;oBACF,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;wBACnC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC;oBACrC,CAAC;oBACD,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC9E,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;oBACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAClB,CAAC;gBACD,MAAM;YACR,CAAC;YAED;gBACE,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;gBAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,6BAA6B;AAC7B,MAAM,iBAAiB,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,UAAU,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;IACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;AAE9C,IAAI,iBAAiB,EAAE,CAAC;IACtB,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-client.d.ts","sourceRoot":"","sources":["../../src/web-viewer/build-client.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"build-client.d.ts","sourceRoot":"","sources":["../../src/web-viewer/build-client.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -1,16 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Build script for the web viewer client.
|
|
3
3
|
* Bundles viewer.ts into a browser-compatible JavaScript file.
|
|
4
|
+
* Also copies static assets to dist/ for npm package.
|
|
4
5
|
*/
|
|
5
6
|
import * as esbuild from "esbuild";
|
|
7
|
+
import fs from "node:fs";
|
|
6
8
|
import path from "node:path";
|
|
7
9
|
import { fileURLToPath } from "node:url";
|
|
8
10
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const srcClientDir = path.join(__dirname, "client");
|
|
12
|
+
const distClientDir = path.join(__dirname, "../../dist/web-viewer/client");
|
|
13
|
+
function copyStaticFiles() {
|
|
14
|
+
// Ensure dist directories exist
|
|
15
|
+
fs.mkdirSync(path.join(distClientDir, "dist"), { recursive: true });
|
|
16
|
+
// Copy static files to dist
|
|
17
|
+
const staticFiles = ["index.html", "styles.css"];
|
|
18
|
+
for (const file of staticFiles) {
|
|
19
|
+
const src = path.join(srcClientDir, file);
|
|
20
|
+
const dest = path.join(distClientDir, file);
|
|
21
|
+
if (fs.existsSync(src)) {
|
|
22
|
+
fs.copyFileSync(src, dest);
|
|
23
|
+
console.log(`Copied ${file} to dist/`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
9
27
|
async function build() {
|
|
10
28
|
const watch = process.argv.includes("--watch");
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
29
|
+
// Build to src for dev, build to dist for production
|
|
30
|
+
const srcOptions = {
|
|
31
|
+
entryPoints: [path.join(srcClientDir, "viewer.ts")],
|
|
32
|
+
outfile: path.join(srcClientDir, "dist/viewer.js"),
|
|
14
33
|
bundle: true,
|
|
15
34
|
minify: !watch,
|
|
16
35
|
sourcemap: watch,
|
|
@@ -20,12 +39,20 @@ async function build() {
|
|
|
20
39
|
logLevel: "info",
|
|
21
40
|
};
|
|
22
41
|
if (watch) {
|
|
23
|
-
const ctx = await esbuild.context(
|
|
42
|
+
const ctx = await esbuild.context(srcOptions);
|
|
24
43
|
await ctx.watch();
|
|
25
44
|
console.log("Watching for changes...");
|
|
26
45
|
}
|
|
27
46
|
else {
|
|
28
|
-
|
|
47
|
+
// Build to src/client/dist (for dev)
|
|
48
|
+
await esbuild.build(srcOptions);
|
|
49
|
+
// Also build to dist/web-viewer/client/dist (for npm package)
|
|
50
|
+
copyStaticFiles();
|
|
51
|
+
await esbuild.build({
|
|
52
|
+
...srcOptions,
|
|
53
|
+
outfile: path.join(distClientDir, "dist/viewer.js"),
|
|
54
|
+
sourcemap: false,
|
|
55
|
+
});
|
|
29
56
|
console.log("Build complete!");
|
|
30
57
|
}
|
|
31
58
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-client.js","sourceRoot":"","sources":["../../src/web-viewer/build-client.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"build-client.js","sourceRoot":"","sources":["../../src/web-viewer/build-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";(()=>{var _=null,E=[],L=null,y=null,u=1,C="",V=null,f=[],T=null,g=null,r=e=>document.getElementById(e),i={fileName:r("file-name"),openBtn:r("open-btn"),search:r("search"),pagesList:r("pages-list"),tree:r("tree"),canvas:r("canvas"),canvasPlaceholder:r("canvas-placeholder"),zoomIn:r("zoom-in"),zoomOut:r("zoom-out"),zoomLevel:r("zoom-level"),zoomFit:r("zoom-fit"),noSelection:r("no-selection"),nodeDetails:r("node-details"),nodeId:r("node-id"),copyId:r("copy-id"),nodeType:r("node-type"),nodeName:r("node-name"),nodeX:r("node-x"),nodeY:r("node-y"),nodeWidth:r("node-width"),nodeHeight:r("node-height"),textSection:r("text-section"),nodeText:r("node-text"),nodeJson:r("node-json"),fileDialog:r("file-dialog"),filePathInput:r("file-path-input"),cancelOpen:r("cancel-open"),confirmOpen:r("confirm-open")};async function b(e,n){let t=await fetch(e,n);if(!t.ok){let o=await t.json().catch(()=>({error:t.statusText}));throw new Error(o.error||"Request failed")}return t.json()}async function j(){return b("/api/tree")}async function J(e){return b(`/api/node/${encodeURIComponent(e)}`)}async function Z(e){return b(`/api/node-raw/${encodeURIComponent(e)}`)}async function K(e){let n=await fetch(`/api/render/${encodeURIComponent(e)}`);if(!n.ok)throw new Error("Failed to render");return n.text()}async function Q(e){return(await b(`/api/flat-nodes/${encodeURIComponent(e)}`)).nodes}async function ee(e){await b("/api/open",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({filePath:e})})}function te(e){return{DOCUMENT:"D",CANVAS:"P",FRAME:"F",GROUP:"G",TEXT:"T",RECTANGLE:"R",ELLIPSE:"O",VECTOR:"V",LINE:"L",STAR:"*",REGULAR_POLYGON:"P",COMPONENT:"C",COMPONENT_SET:"S",INSTANCE:"I",BOOLEAN_OPERATION:"B",SLICE:"S",STICKY:"N",SHAPE_WITH_TEXT:"ST",CONNECTOR:"CN",SECTION:"SE"}[e]||"?"}function ne(){i.pagesList.innerHTML="";for(let e of E){let n=document.createElement("div");n.className="page-item",e.id===L&&n.classList.add("selected"),n.dataset.pageId=e.id;let t=document.createElement("span");t.className="page-icon",t.textContent="P",n.appendChild(t);let o=document.createElement("span");o.className="page-name",o.textContent=e.name||"(unnamed)",n.appendChild(o),n.addEventListener("click",()=>ie(e.id)),i.pagesList.appendChild(n)}}function ie(e){L=e,y=null,i.pagesList.querySelectorAll(".page-item").forEach(n=>{n.classList.toggle("selected",n.getAttribute("data-page-id")===e)}),I(),i.canvas.innerHTML='<div id="canvas-placeholder">Select a node to preview</div>',i.noSelection.classList.remove("hidden"),i.nodeDetails.classList.add("hidden")}function oe(e,n){if(!n)return!0;let t=n.toLowerCase();return e.name.toLowerCase().includes(t)||e.type.toLowerCase().includes(t)||e.id.toLowerCase().includes(t)}function G(e,n){return oe(e,n)?!0:e.children?e.children.some(t=>G(t,n)):!1}function N(e,n=0){let t=document.createElement("div");t.className="tree-node",t.dataset.nodeId=e.id;let o=e.children&&e.children.length>0,s=n<2;s&&o&&t.classList.add("expanded");let a=document.createElement("div");a.className="tree-node-row",a.style.paddingLeft=`${n*16+8}px`,e.id===y&&a.classList.add("selected");let l=document.createElement("span");l.className=`tree-toggle ${o?s?"expanded":"collapsed":""}`,o&&l.addEventListener("click",v=>{v.stopPropagation(),t.classList.toggle("expanded"),l.classList.toggle("collapsed"),l.classList.toggle("expanded")}),a.appendChild(l);let c=document.createElement("span");c.className=`tree-icon type-${e.type}`,c.textContent=te(e.type),a.appendChild(c);let d=document.createElement("span");d.className="tree-name",d.textContent=e.name||"(unnamed)",a.appendChild(d);let p=document.createElement("span");if(p.className="tree-type",p.textContent=e.type,a.appendChild(p),a.addEventListener("click",()=>O(e.id)),t.appendChild(a),o){let v=document.createElement("div");v.className="tree-children";for(let w of e.children)C&&!G(w,C)||v.appendChild(N(w,n+1));t.appendChild(v)}return t}function I(){i.tree.innerHTML="";let e=E.find(n=>n.id===L);if(!e){i.tree.innerHTML='<div style="padding: 20px; color: #999;">Select a page to view its contents</div>';return}if(C){let n=o=>{o.classList.add("expanded");let s=o.querySelector(".tree-toggle");s&&(s.classList.remove("collapsed"),s.classList.add("expanded"))},t=document.createDocumentFragment();t.appendChild(N(e)),i.tree.appendChild(t),i.tree.querySelectorAll(".tree-node").forEach(o=>{n(o)})}else i.tree.appendChild(N(e))}async function O(e,n){y=e,i.tree.querySelectorAll(".tree-node-row.selected").forEach(o=>{o.classList.remove("selected")});let t=i.tree.querySelector(`[data-node-id="${e}"] > .tree-node-row`);t&&t.classList.add("selected"),i.noSelection.classList.add("hidden"),i.nodeDetails.classList.remove("hidden"),i.nodeId.textContent=e;try{let[o,s]=await Promise.allSettled([J(e),Z(e)]);if(o.status!=="fulfilled")throw o.reason;let{node:a}=o.value,l=s.status==="fulfilled"?s.value.node:a;i.nodeType.textContent=a.type,i.nodeName.textContent=a.name||"(unnamed)",i.nodeX.textContent=a.x?.toFixed(1)??"-",i.nodeY.textContent=a.y?.toFixed(1)??"-",i.nodeWidth.textContent=a.width?.toFixed(1)??"-",i.nodeHeight.textContent=a.height?.toFixed(1)??"-",a.characters?(i.textSection.classList.remove("hidden"),i.nodeText.textContent=a.characters):i.textSection.classList.add("hidden"),i.nodeJson.textContent=JSON.stringify(l,null,2),n?.skipRender?M(e):await ae(e)}catch(o){console.error("Failed to load node details:",o)}}async function ae(e){let n=e!==V;try{let[t,o]=await Promise.all([K(e),Q(e)]);if(i.canvas.innerHTML=t,i.canvasPlaceholder?.remove(),V=e,f=o,o.length>0){let s=1/0,a=1/0,l=-1/0,c=-1/0;for(let d of o)s=Math.min(s,d.absX),a=Math.min(a,d.absY),l=Math.max(l,d.absX+d.width),c=Math.max(c,d.absY+d.height);g={minX:s,minY:a,width:l-s,height:c-a}}else g=null;if(re(),n){x=0,H=0,u=1;let s=F(),a=i.canvas.parentElement;s?(a.scrollLeft=0,a.scrollTop=0):A()}}catch(t){console.error("Failed to render preview:",t),i.canvas.innerHTML=`<div id="canvas-placeholder">Failed to render: ${t}</div>`,i.canvas.style.width="",i.canvas.style.height="",f=[],g=null}}var x=0,H=0;function F(){let n=i.canvas.parentElement.getBoundingClientRect();i.zoomLevel.textContent=`${Math.round(u*100)}%`,i.canvas.style.transform="";let t=i.canvas.querySelector("svg:not(#hover-overlay)");if(t){x===0&&(x=t.width.baseVal.value||parseFloat(t.getAttribute("width")||"100"),H=t.height.baseVal.value||parseFloat(t.getAttribute("height")||"100"));let o=x*u,s=H*u;t.setAttribute("width",String(o)),t.setAttribute("height",String(s));let a=i.canvas.querySelector("#hover-overlay");a&&(a.setAttribute("width",String(o)),a.setAttribute("height",String(s)));let l=80,c=o+l,d=s+l,p=c<=n.width&&d<=n.height;return p?(i.canvas.style.width="",i.canvas.style.height=""):(i.canvas.style.width=`${c}px`,i.canvas.style.height=`${d}px`),p}return!0}function P(e,n){let t=i.canvas.parentElement,o=t.getBoundingClientRect(),s=u,a=n||{x:o.width/2,y:o.height/2},l=40,c=(t.scrollLeft+a.x-l)/s,d=(t.scrollTop+a.y-l)/s;if(u=e,F())t.scrollLeft=0,t.scrollTop=0;else{let v=c*e+l-a.x,w=d*e+l-a.y,q=Math.max(0,t.scrollWidth-t.clientWidth),U=Math.max(0,t.scrollHeight-t.clientHeight);t.scrollLeft=Math.max(0,Math.min(q,v)),t.scrollTop=Math.max(0,Math.min(U,w))}}function Y(){let e=Math.min(u*1.15,10);P(e)}function X(){let e=Math.max(u/1.15,.1);P(e)}function se(e,n){let t=Math.max(-100,Math.min(100,e)),o=1+Math.abs(t)*.003,s;t<0?s=Math.min(u*o,10):s=Math.max(u/o,.1),P(s,n)}function A(){let e=i.canvas.querySelector("svg:not(#hover-overlay)");if(!e)return;let n=i.canvas.parentElement,t=n.getBoundingClientRect(),o=e.width.baseVal.value||parseFloat(e.getAttribute("width")||"100"),s=e.height.baseVal.value||parseFloat(e.getAttribute("height")||"100"),a=80,l=(t.width-a)/o,c=(t.height-a)/s;u=Math.min(l,c,1);let d=F();n.scrollLeft=0,n.scrollTop=0}var h=null,m=null;function re(){m&&m.remove();let e=i.canvas.querySelector("svg");e&&(m=document.createElement("div"),m.id="svg-wrapper",m.style.cssText=`
|
|
2
|
+
position: relative;
|
|
3
|
+
display: inline-block;
|
|
4
|
+
`,e.parentNode?.insertBefore(m,e),m.appendChild(e),h=document.createElementNS("http://www.w3.org/2000/svg","svg"),h.id="hover-overlay",h.style.cssText=`
|
|
5
|
+
position: absolute;
|
|
6
|
+
top: 0;
|
|
7
|
+
left: 0;
|
|
8
|
+
pointer-events: none;
|
|
9
|
+
overflow: visible;
|
|
10
|
+
`,m.appendChild(h))}function z(){return m?m.querySelector("svg:not(#hover-overlay)"):i.canvas.querySelector("svg:not(#hover-overlay)")}function M(e){if(!h||!g||(h.innerHTML="",!e))return;let n=f.find(d=>d.id===e);if(!n)return;let t=z();if(!t)return;let o=t.width.baseVal.value||parseFloat(t.getAttribute("width")||"0"),s=t.height.baseVal.value||parseFloat(t.getAttribute("height")||"0");h.setAttribute("viewBox",`0 0 ${o} ${s}`),h.setAttribute("width",String(o)),h.setAttribute("height",String(s));let a=n.absX-g.minX,l=n.absY-g.minY,c=document.createElementNS("http://www.w3.org/2000/svg","rect");c.setAttribute("x",String(a)),c.setAttribute("y",String(l)),c.setAttribute("width",String(n.width)),c.setAttribute("height",String(n.height)),c.setAttribute("fill","rgba(0, 120, 212, 0.1)"),c.setAttribute("stroke","#0078d4"),c.setAttribute("stroke-width","2"),h.appendChild(c)}function k(e,n){let t=z();if(!t||!g)return null;let o=t.getBoundingClientRect(),s=t.width.baseVal.value||parseFloat(t.getAttribute("width")||"0"),a=t.height.baseVal.value||parseFloat(t.getAttribute("height")||"0"),l=(e-o.left)/u,c=(n-o.top)/u,d=l+g.minX,p=c+g.minY;return{x:d,y:p}}function R(e,n){return f.filter(t=>t.visible&&e>=t.absX&&e<=t.absX+t.width&&n>=t.absY&&n<=t.absY+t.height).sort((t,o)=>o.depth-t.depth)}function D(e){return e.length===0?null:e[0]}function $(e){let n=i.tree.querySelector(`[data-node-id="${e}"]`);if(!n)return;let t=n.parentElement;for(;t;){if(t.classList?.contains("tree-node")){t.classList.add("expanded");let s=t.querySelector(":scope > .tree-node-row > .tree-toggle");s&&(s.classList.remove("collapsed"),s.classList.add("expanded"))}if(t.id==="tree")break;t=t.parentElement}let o=n.querySelector(":scope > .tree-node-row");o&&o.scrollIntoView({behavior:"smooth",block:"center"})}function le(e){if(f.length===0)return;let n=k(e.clientX,e.clientY);if(!n){T=null,M(null);return}let t=R(n.x,n.y),o=D(t);o?.id!==T&&(T=o?.id??null,M(T))}function ce(e){if(f.length===0)return;let n=k(e.clientX,e.clientY);if(!n)return;let t=R(n.x,n.y),o=D(t);if(o){$(o.id);let s=f.some(a=>a.id===o.id);O(o.id,{skipRender:s})}}function de(e){if(f.length===0)return;let n=k(e.clientX,e.clientY);if(!n)return;let t=R(n.x,n.y),o=D(t);o&&($(o.id),O(o.id))}function ue(){T=null,M(null)}function me(){i.fileDialog.classList.remove("hidden"),i.filePathInput.focus()}function S(){i.fileDialog.classList.add("hidden")}async function B(){let e=i.filePathInput.value.trim();if(e)try{i.confirmOpen.disabled=!0,i.confirmOpen.textContent="Loading...",await ee(e),S(),L=null,y=null,await W(),i.fileName.textContent=e.split("/").pop()||e}catch(n){alert(`Failed to open file: ${n}`)}finally{i.confirmOpen.disabled=!1,i.confirmOpen.textContent="Open"}}async function W(){try{let{tree:e,meta:n}=await j();_=e,E=[],e.children&&(E=e.children.filter(t=>t.type==="CANVAS")),E.length>0&&!L&&(L=E[0].id),ne(),I(),n?.name&&(i.fileName.textContent=n.name)}catch(e){console.error("Failed to load tree:",e),E=[],i.pagesList.innerHTML="",i.tree.innerHTML='<div style="padding: 20px; color: #999;">No file loaded. Click "Open File" to start.</div>'}}async function he(){if(y)try{await navigator.clipboard.writeText(y);let e=i.copyId.textContent;i.copyId.textContent="Copied!",setTimeout(()=>{i.copyId.textContent=e},1e3)}catch{let e=document.createElement("textarea");e.value=y,document.body.appendChild(e),e.select(),document.execCommand("copy"),document.body.removeChild(e)}}function pe(){i.zoomIn.addEventListener("click",Y),i.zoomOut.addEventListener("click",X),i.zoomFit.addEventListener("click",A),document.addEventListener("keydown",e=>{e.target instanceof HTMLInputElement||(e.key==="="||e.key==="+"?(e.preventDefault(),Y()):e.key==="-"?(e.preventDefault(),X()):e.key==="0"&&(e.preventDefault(),A()))}),i.canvas.parentElement?.addEventListener("wheel",e=>{if(e.ctrlKey||e.metaKey){e.preventDefault();let t=i.canvas.parentElement.getBoundingClientRect(),o={x:e.clientX-t.left,y:e.clientY-t.top};se(e.deltaY,o)}},{passive:!1}),i.canvas.addEventListener("mousemove",le),i.canvas.addEventListener("click",ce),i.canvas.addEventListener("dblclick",de),i.canvas.addEventListener("mouseleave",ue),i.search.addEventListener("input",e=>{C=e.target.value,I()}),i.openBtn.addEventListener("click",me),i.cancelOpen.addEventListener("click",S),i.confirmOpen.addEventListener("click",B),i.filePathInput.addEventListener("keydown",e=>{e.key==="Enter"?B():e.key==="Escape"&&S()}),i.fileDialog.addEventListener("click",e=>{e.target===i.fileDialog&&S()}),i.copyId.addEventListener("click",he),W()}document.addEventListener("DOMContentLoaded",pe);})();
|
|
@@ -0,0 +1,138 @@
|
|
|
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>Fig Viewer</title>
|
|
7
|
+
<link rel="stylesheet" href="/styles.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="app">
|
|
11
|
+
<!-- Header -->
|
|
12
|
+
<header id="header">
|
|
13
|
+
<h1>Fig Viewer</h1>
|
|
14
|
+
<div id="file-info">
|
|
15
|
+
<span id="file-name">No file loaded</span>
|
|
16
|
+
<button id="open-btn" title="Open .fig file">Open File</button>
|
|
17
|
+
</div>
|
|
18
|
+
</header>
|
|
19
|
+
|
|
20
|
+
<!-- Main layout -->
|
|
21
|
+
<div id="main">
|
|
22
|
+
<!-- Left panel: Tree view -->
|
|
23
|
+
<aside id="tree-panel">
|
|
24
|
+
<!-- Pages list -->
|
|
25
|
+
<div id="pages-section">
|
|
26
|
+
<div id="pages-header">
|
|
27
|
+
<span>Pages</span>
|
|
28
|
+
</div>
|
|
29
|
+
<div id="pages-list"></div>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<!-- Tree with search -->
|
|
33
|
+
<div id="tree-section">
|
|
34
|
+
<div id="tree-header">
|
|
35
|
+
<input type="text" id="search" placeholder="Search nodes..." />
|
|
36
|
+
</div>
|
|
37
|
+
<div id="tree-container">
|
|
38
|
+
<div id="tree"></div>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</aside>
|
|
42
|
+
|
|
43
|
+
<!-- Center: Canvas/Preview -->
|
|
44
|
+
<main id="canvas-panel">
|
|
45
|
+
<div id="canvas-toolbar">
|
|
46
|
+
<button id="zoom-in" title="Zoom in">+</button>
|
|
47
|
+
<span id="zoom-level">100%</span>
|
|
48
|
+
<button id="zoom-out" title="Zoom out">-</button>
|
|
49
|
+
<button id="zoom-fit" title="Fit to view">Fit</button>
|
|
50
|
+
</div>
|
|
51
|
+
<div id="canvas-container">
|
|
52
|
+
<div id="canvas">
|
|
53
|
+
<div id="canvas-placeholder">
|
|
54
|
+
Select a node to preview
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</main>
|
|
59
|
+
|
|
60
|
+
<!-- Right panel: Node details -->
|
|
61
|
+
<aside id="details-panel">
|
|
62
|
+
<div id="details-header">
|
|
63
|
+
<h2>Node Details</h2>
|
|
64
|
+
</div>
|
|
65
|
+
<div id="details-content">
|
|
66
|
+
<div id="no-selection">Select a node to see details</div>
|
|
67
|
+
<div id="node-details" class="hidden">
|
|
68
|
+
<div class="detail-section">
|
|
69
|
+
<div class="detail-row">
|
|
70
|
+
<label>ID</label>
|
|
71
|
+
<div class="detail-value">
|
|
72
|
+
<code id="node-id"></code>
|
|
73
|
+
<button id="copy-id" title="Copy ID">Copy</button>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
<div class="detail-row">
|
|
77
|
+
<label>Type</label>
|
|
78
|
+
<span id="node-type"></span>
|
|
79
|
+
</div>
|
|
80
|
+
<div class="detail-row">
|
|
81
|
+
<label>Name</label>
|
|
82
|
+
<span id="node-name"></span>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<div class="detail-section">
|
|
87
|
+
<h3>Bounds</h3>
|
|
88
|
+
<div class="detail-grid">
|
|
89
|
+
<div class="detail-cell">
|
|
90
|
+
<label>X</label>
|
|
91
|
+
<span id="node-x">-</span>
|
|
92
|
+
</div>
|
|
93
|
+
<div class="detail-cell">
|
|
94
|
+
<label>Y</label>
|
|
95
|
+
<span id="node-y">-</span>
|
|
96
|
+
</div>
|
|
97
|
+
<div class="detail-cell">
|
|
98
|
+
<label>W</label>
|
|
99
|
+
<span id="node-width">-</span>
|
|
100
|
+
</div>
|
|
101
|
+
<div class="detail-cell">
|
|
102
|
+
<label>H</label>
|
|
103
|
+
<span id="node-height">-</span>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<div class="detail-section" id="text-section">
|
|
109
|
+
<h3>Text</h3>
|
|
110
|
+
<div id="node-text"></div>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<div class="detail-section">
|
|
114
|
+
<h3>Raw JSON</h3>
|
|
115
|
+
<pre id="node-json"></pre>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
</aside>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<!-- File picker dialog (hidden by default) -->
|
|
124
|
+
<div id="file-dialog" class="dialog hidden">
|
|
125
|
+
<div class="dialog-content">
|
|
126
|
+
<h2>Open .fig File</h2>
|
|
127
|
+
<p>Enter the path to a .fig file on your local machine:</p>
|
|
128
|
+
<input type="text" id="file-path-input" placeholder="/path/to/design.fig" />
|
|
129
|
+
<div class="dialog-buttons">
|
|
130
|
+
<button id="cancel-open">Cancel</button>
|
|
131
|
+
<button id="confirm-open" class="primary">Open</button>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
<script src="/viewer.js"></script>
|
|
137
|
+
</body>
|
|
138
|
+
</html>
|