@womp/mcp-ui 0.1.11 → 0.1.12
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/README.md +8 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +15 -6
- package/dist/openai-camera/index.html +332 -0
- package/package.json +6 -3
- package/src/openai-camera/index.html +258 -0
- package/src/openai-camera/main.ts +442 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@womp/mcp-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "MCP Apps widgets for Womp's MCP server — interactive cards rendered inline in Claude and other MCP hosts.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -15,11 +15,13 @@
|
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
17
|
"build": "yarn build:ui && yarn build:bake",
|
|
18
|
-
"build:ui": "yarn build:ui:image && yarn build:ui:mesh && yarn build:ui:print && yarn build:ui:cart && yarn build:ui:order && yarn build:ui:upload",
|
|
18
|
+
"build:ui": "yarn build:ui:image && yarn build:ui:mesh && yarn build:ui:print && yarn build:ui:cart && yarn build:ui:order && yarn build:ui:upload && yarn build:ui:openai-camera",
|
|
19
19
|
"build:bake": "node scripts/bake-html.mjs",
|
|
20
20
|
"dev": "vite",
|
|
21
21
|
"dev:host": "vite",
|
|
22
22
|
"dev:mcp": "node dev/server.mjs",
|
|
23
|
+
"dev:openai-mcp": "node dev/openai-mcp/index.mjs",
|
|
24
|
+
"test:openai-mcp": "node --test \"dev/openai-mcp/*.test.mjs\"",
|
|
23
25
|
"lint": "tsc --noEmit",
|
|
24
26
|
"clean": "rm -rf dist",
|
|
25
27
|
"prepublishOnly": "yarn clean && yarn build",
|
|
@@ -28,7 +30,8 @@
|
|
|
28
30
|
"build:ui:print": "CARD=print vite build",
|
|
29
31
|
"build:ui:cart": "CARD=cart vite build",
|
|
30
32
|
"build:ui:order": "CARD=order vite build",
|
|
31
|
-
"build:ui:upload": "CARD=upload vite build"
|
|
33
|
+
"build:ui:upload": "CARD=upload vite build",
|
|
34
|
+
"build:ui:openai-camera": "CARD=openai-camera vite build"
|
|
32
35
|
},
|
|
33
36
|
"devDependencies": {
|
|
34
37
|
"@modelcontextprotocol/ext-apps": "^1.7.5",
|
|
@@ -0,0 +1,258 @@
|
|
|
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" />
|
|
6
|
+
<title>Camera</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
color-scheme: light dark;
|
|
10
|
+
}
|
|
11
|
+
body {
|
|
12
|
+
margin: 0;
|
|
13
|
+
font-family: var(--font-sans, system-ui, -apple-system, "Segoe UI", sans-serif);
|
|
14
|
+
color: var(--color-text-primary, #1b1b1a);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.card {
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
max-width: 680px;
|
|
21
|
+
border-radius: var(--border-radius-lg, 14px);
|
|
22
|
+
overflow: hidden;
|
|
23
|
+
background: var(--color-background-secondary, #f6f6f4);
|
|
24
|
+
border: 1px solid var(--color-border-primary, rgba(0, 0, 0, 0.1));
|
|
25
|
+
box-sizing: border-box;
|
|
26
|
+
}
|
|
27
|
+
/* Fullscreen hands us the viewport: the viewer takes whatever the controls leave. */
|
|
28
|
+
:root[data-display-mode="fullscreen"] .card {
|
|
29
|
+
max-width: none;
|
|
30
|
+
height: 100vh;
|
|
31
|
+
border-radius: 0;
|
|
32
|
+
border: 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.stage {
|
|
36
|
+
position: relative;
|
|
37
|
+
height: 360px;
|
|
38
|
+
background: #d9d9d9;
|
|
39
|
+
}
|
|
40
|
+
:root[data-display-mode="fullscreen"] .stage {
|
|
41
|
+
flex: 1;
|
|
42
|
+
height: auto;
|
|
43
|
+
min-height: 0;
|
|
44
|
+
}
|
|
45
|
+
/* While ordering, the design stays in view but gives the form the room. */
|
|
46
|
+
.card[data-view="order"] .stage,
|
|
47
|
+
.card[data-view="done"] .stage {
|
|
48
|
+
height: 220px;
|
|
49
|
+
flex: none;
|
|
50
|
+
}
|
|
51
|
+
.stage iframe {
|
|
52
|
+
display: block;
|
|
53
|
+
width: 100%;
|
|
54
|
+
height: 100%;
|
|
55
|
+
border: 0;
|
|
56
|
+
}
|
|
57
|
+
.stage iframe[hidden] { display: none; }
|
|
58
|
+
|
|
59
|
+
.fallback {
|
|
60
|
+
position: absolute;
|
|
61
|
+
inset: 0;
|
|
62
|
+
overflow: auto;
|
|
63
|
+
padding: 16px;
|
|
64
|
+
box-sizing: border-box;
|
|
65
|
+
background: var(--color-background-tertiary, #ecebe6);
|
|
66
|
+
color: var(--color-text-primary, #1b1b1a);
|
|
67
|
+
font-size: var(--font-text-sm-size, 13px);
|
|
68
|
+
}
|
|
69
|
+
.fallback[hidden] { display: none; }
|
|
70
|
+
.fallback p { margin: 0 0 10px; }
|
|
71
|
+
.fallback dl {
|
|
72
|
+
display: grid;
|
|
73
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
74
|
+
gap: 2px 12px;
|
|
75
|
+
margin: 0;
|
|
76
|
+
font-size: var(--font-text-xs-size, 12px);
|
|
77
|
+
}
|
|
78
|
+
.fallback dt { color: var(--color-text-secondary, rgba(27, 27, 26, 0.62)); }
|
|
79
|
+
.fallback dd { margin: 0; font-variant-numeric: tabular-nums; }
|
|
80
|
+
|
|
81
|
+
.view[hidden] { display: none; }
|
|
82
|
+
|
|
83
|
+
.controls {
|
|
84
|
+
display: grid;
|
|
85
|
+
gap: 8px;
|
|
86
|
+
padding: 12px 14px 0;
|
|
87
|
+
}
|
|
88
|
+
.row {
|
|
89
|
+
display: flex;
|
|
90
|
+
align-items: center;
|
|
91
|
+
gap: 10px;
|
|
92
|
+
min-width: 0;
|
|
93
|
+
}
|
|
94
|
+
.row > span {
|
|
95
|
+
flex: none;
|
|
96
|
+
width: 48px;
|
|
97
|
+
font-size: var(--font-text-xs-size, 12px);
|
|
98
|
+
color: var(--color-text-secondary, rgba(27, 27, 26, 0.62));
|
|
99
|
+
}
|
|
100
|
+
.swatches {
|
|
101
|
+
display: flex;
|
|
102
|
+
flex-wrap: wrap;
|
|
103
|
+
gap: 6px;
|
|
104
|
+
min-width: 0;
|
|
105
|
+
}
|
|
106
|
+
.swatch {
|
|
107
|
+
width: 22px;
|
|
108
|
+
height: 22px;
|
|
109
|
+
padding: 0;
|
|
110
|
+
border-radius: 50%;
|
|
111
|
+
border: 1px solid rgba(0, 0, 0, 0.18);
|
|
112
|
+
cursor: pointer;
|
|
113
|
+
}
|
|
114
|
+
/* The clear resin gets a hint of glass rather than a flat swatch. */
|
|
115
|
+
.swatch.clear {
|
|
116
|
+
background-image: linear-gradient(135deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0) 55%) !important;
|
|
117
|
+
}
|
|
118
|
+
.swatch[aria-pressed="true"] {
|
|
119
|
+
outline: 2px solid var(--color-text-primary, #1b1b1a);
|
|
120
|
+
outline-offset: 2px;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.foot {
|
|
124
|
+
display: flex;
|
|
125
|
+
align-items: center;
|
|
126
|
+
gap: 8px;
|
|
127
|
+
padding: 12px 14px;
|
|
128
|
+
}
|
|
129
|
+
.price {
|
|
130
|
+
flex: 1;
|
|
131
|
+
min-width: 0;
|
|
132
|
+
font-size: var(--font-text-sm-size, 13px);
|
|
133
|
+
color: var(--color-text-secondary, rgba(27, 27, 26, 0.62));
|
|
134
|
+
}
|
|
135
|
+
button.action {
|
|
136
|
+
font: inherit;
|
|
137
|
+
font-size: var(--font-text-sm-size, 13px);
|
|
138
|
+
font-weight: 600;
|
|
139
|
+
border-radius: var(--border-radius-full, 999px);
|
|
140
|
+
padding: 8px 14px;
|
|
141
|
+
cursor: pointer;
|
|
142
|
+
border: 1px solid var(--color-border-primary, rgba(0, 0, 0, 0.14));
|
|
143
|
+
background: transparent;
|
|
144
|
+
color: var(--color-text-primary, #1b1b1a);
|
|
145
|
+
}
|
|
146
|
+
button.action.primary {
|
|
147
|
+
border-color: transparent;
|
|
148
|
+
background: var(--color-text-primary, #1b1b1a);
|
|
149
|
+
color: var(--color-background-primary, #ffffff);
|
|
150
|
+
}
|
|
151
|
+
button.action:disabled { opacity: 0.5; cursor: default; }
|
|
152
|
+
|
|
153
|
+
form {
|
|
154
|
+
display: grid;
|
|
155
|
+
gap: 8px;
|
|
156
|
+
padding: 12px 14px 0;
|
|
157
|
+
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
|
158
|
+
}
|
|
159
|
+
form .wide { grid-column: 1 / -1; }
|
|
160
|
+
form h2 {
|
|
161
|
+
margin: 0;
|
|
162
|
+
font-size: var(--font-text-sm-size, 14px);
|
|
163
|
+
}
|
|
164
|
+
form .note {
|
|
165
|
+
margin: 0;
|
|
166
|
+
font-size: var(--font-text-xs-size, 12px);
|
|
167
|
+
color: var(--color-text-secondary, rgba(27, 27, 26, 0.62));
|
|
168
|
+
}
|
|
169
|
+
label {
|
|
170
|
+
display: grid;
|
|
171
|
+
gap: 3px;
|
|
172
|
+
min-width: 0;
|
|
173
|
+
font-size: var(--font-text-xs-size, 12px);
|
|
174
|
+
color: var(--color-text-secondary, rgba(27, 27, 26, 0.62));
|
|
175
|
+
}
|
|
176
|
+
input {
|
|
177
|
+
width: 100%;
|
|
178
|
+
box-sizing: border-box;
|
|
179
|
+
font: inherit;
|
|
180
|
+
font-size: var(--font-text-sm-size, 13px);
|
|
181
|
+
color: var(--color-text-primary, #1b1b1a);
|
|
182
|
+
background: var(--color-background-primary, #ffffff);
|
|
183
|
+
border: 1px solid var(--color-border-primary, rgba(0, 0, 0, 0.14));
|
|
184
|
+
border-radius: 8px;
|
|
185
|
+
padding: 7px 9px;
|
|
186
|
+
}
|
|
187
|
+
input[aria-invalid="true"] { border-color: #c2410c; }
|
|
188
|
+
|
|
189
|
+
.done {
|
|
190
|
+
padding: 14px;
|
|
191
|
+
display: grid;
|
|
192
|
+
gap: 6px;
|
|
193
|
+
font-size: var(--font-text-sm-size, 13px);
|
|
194
|
+
}
|
|
195
|
+
.done h2 { margin: 0; font-size: var(--font-text-md-size, 15px); }
|
|
196
|
+
.done p { margin: 0; color: var(--color-text-secondary, rgba(27, 27, 26, 0.62)); }
|
|
197
|
+
|
|
198
|
+
.status {
|
|
199
|
+
padding: 0 14px 10px;
|
|
200
|
+
font-size: var(--font-text-xs-size, 11px);
|
|
201
|
+
color: var(--color-text-secondary, rgba(27, 27, 26, 0.62));
|
|
202
|
+
}
|
|
203
|
+
.status:empty { display: none; }
|
|
204
|
+
</style>
|
|
205
|
+
</head>
|
|
206
|
+
<body>
|
|
207
|
+
<div class="card" id="card" data-view="design">
|
|
208
|
+
<div class="stage">
|
|
209
|
+
<iframe id="viewer" title="3D preview of your camera" allow="fullscreen" hidden></iframe>
|
|
210
|
+
<div class="fallback" id="fallback" hidden></div>
|
|
211
|
+
</div>
|
|
212
|
+
|
|
213
|
+
<div class="view" id="view-design">
|
|
214
|
+
<div class="controls">
|
|
215
|
+
<div class="row"><span>Shell</span><div class="swatches" id="sw-shell"></div></div>
|
|
216
|
+
<div class="row"><span>Button</span><div class="swatches" id="sw-button"></div></div>
|
|
217
|
+
</div>
|
|
218
|
+
<div class="foot">
|
|
219
|
+
<div class="price" id="price"></div>
|
|
220
|
+
<button class="action" id="customize" type="button">Customize</button>
|
|
221
|
+
<button class="action primary" id="order" type="button">Order</button>
|
|
222
|
+
</div>
|
|
223
|
+
</div>
|
|
224
|
+
|
|
225
|
+
<div class="view" id="view-order" hidden>
|
|
226
|
+
<form id="order-form" novalidate>
|
|
227
|
+
<h2 class="wide">Where should we send it?</h2>
|
|
228
|
+
<p class="note wide" id="order-summary"></p>
|
|
229
|
+
<label class="wide">Full name<input name="name" autocomplete="name" maxlength="200" /></label>
|
|
230
|
+
<label class="wide">Email<input name="email" type="email" autocomplete="email" maxlength="200" /></label>
|
|
231
|
+
<label class="wide">Address<input name="address" autocomplete="street-address" maxlength="200" /></label>
|
|
232
|
+
<label>City<input name="city" autocomplete="address-level2" maxlength="200" /></label>
|
|
233
|
+
<label>Postcode / ZIP<input name="postcode" autocomplete="postal-code" maxlength="40" /></label>
|
|
234
|
+
<label class="wide">Country<input name="country" autocomplete="country-name" maxlength="100" /></label>
|
|
235
|
+
</form>
|
|
236
|
+
<div class="foot">
|
|
237
|
+
<div class="price">Test mode — nothing is charged.</div>
|
|
238
|
+
<button class="action" id="order-back" type="button">Back</button>
|
|
239
|
+
<button class="action primary" id="order-place" type="button">Place test order</button>
|
|
240
|
+
</div>
|
|
241
|
+
</div>
|
|
242
|
+
|
|
243
|
+
<div class="view" id="view-done" hidden>
|
|
244
|
+
<div class="done">
|
|
245
|
+
<h2>Order received</h2>
|
|
246
|
+
<p id="done-text"></p>
|
|
247
|
+
</div>
|
|
248
|
+
<div class="foot">
|
|
249
|
+
<div class="price"></div>
|
|
250
|
+
<button class="action" id="done-back" type="button">Back to design</button>
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
|
|
254
|
+
<div class="status" id="status">Connecting…</div>
|
|
255
|
+
</div>
|
|
256
|
+
<script type="module" src="./main.ts"></script>
|
|
257
|
+
</body>
|
|
258
|
+
</html>
|