@dataimago/interview 0.2.0-alpha.0
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/dist/index.cjs +397 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +225 -0
- package/dist/index.d.ts +225 -0
- package/dist/index.js +367 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
AnswerSidebar: () => AnswerSidebar,
|
|
24
|
+
ProgressBar: () => ProgressBar,
|
|
25
|
+
QuestionCard: () => QuestionCard,
|
|
26
|
+
ReviewSummary: () => ReviewSummary
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(index_exports);
|
|
29
|
+
|
|
30
|
+
// src/ProgressBar.tsx
|
|
31
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
32
|
+
function ProgressBar({ current, total, estimatedMinutesRemaining }) {
|
|
33
|
+
const percent = Math.round(current / total * 100);
|
|
34
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "border-b border-stone-200 bg-stone-100 py-3 px-6", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mx-auto max-w-3xl", children: [
|
|
35
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between text-sm", children: [
|
|
36
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "font-mono text-xs uppercase tracking-wider text-stone-700", children: [
|
|
37
|
+
"Question ",
|
|
38
|
+
current,
|
|
39
|
+
" of ",
|
|
40
|
+
total
|
|
41
|
+
] }),
|
|
42
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "font-mono text-xs text-stone-500", children: [
|
|
43
|
+
"~",
|
|
44
|
+
estimatedMinutesRemaining,
|
|
45
|
+
" min remaining"
|
|
46
|
+
] })
|
|
47
|
+
] }),
|
|
48
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
49
|
+
"div",
|
|
50
|
+
{
|
|
51
|
+
className: "mt-2 h-1 w-full overflow-hidden rounded-full bg-stone-200",
|
|
52
|
+
role: "progressbar",
|
|
53
|
+
"aria-valuenow": percent,
|
|
54
|
+
"aria-valuemin": 0,
|
|
55
|
+
"aria-valuemax": 100,
|
|
56
|
+
"aria-label": `Interview progress: ${percent}% complete`,
|
|
57
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
58
|
+
"div",
|
|
59
|
+
{
|
|
60
|
+
className: "h-full bg-forest-700 transition-all duration-300 ease-out",
|
|
61
|
+
style: { width: `${percent}%` }
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
] }) });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/QuestionCard.tsx
|
|
70
|
+
var import_react = require("react");
|
|
71
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
72
|
+
function QuestionCard({
|
|
73
|
+
question,
|
|
74
|
+
existingAnswer,
|
|
75
|
+
onAnswerSubmit,
|
|
76
|
+
onNext,
|
|
77
|
+
onBack,
|
|
78
|
+
isFirst,
|
|
79
|
+
isLast
|
|
80
|
+
}) {
|
|
81
|
+
const [localValue, setLocalValue] = (0, import_react.useState)(
|
|
82
|
+
existingAnswer ?? (question.inputType === "multi-select" || question.inputType === "list" ? [] : "")
|
|
83
|
+
);
|
|
84
|
+
(0, import_react.useEffect)(() => {
|
|
85
|
+
const current = existingAnswer ?? (question.inputType === "multi-select" || question.inputType === "list" ? [] : "");
|
|
86
|
+
setLocalValue(current);
|
|
87
|
+
}, [question.id, existingAnswer, question.inputType]);
|
|
88
|
+
const handleSubmit = (e) => {
|
|
89
|
+
e.preventDefault();
|
|
90
|
+
onAnswerSubmit(question.id, localValue);
|
|
91
|
+
onNext();
|
|
92
|
+
};
|
|
93
|
+
const canAdvance = question.required ? Array.isArray(localValue) ? localValue.length > 0 : localValue.trim().length > 0 : true;
|
|
94
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { onSubmit: handleSubmit, className: "animate-slide-up", children: [
|
|
95
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { className: "font-display text-3xl font-medium text-stone-900 sm:text-4xl", children: question.prompt }),
|
|
96
|
+
question.subprompt && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "mt-4 text-lg text-stone-700", children: question.subprompt }),
|
|
97
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mt-8", children: [
|
|
98
|
+
question.inputType === "short-text" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
99
|
+
"input",
|
|
100
|
+
{
|
|
101
|
+
type: "text",
|
|
102
|
+
value: localValue,
|
|
103
|
+
onChange: (e) => setLocalValue(e.target.value),
|
|
104
|
+
autoFocus: true,
|
|
105
|
+
className: "w-full rounded-lg border-2 border-stone-200 bg-stone-50 px-4 py-3 text-lg text-stone-900 focus:border-forest-700 focus:outline-none",
|
|
106
|
+
placeholder: "Type your answer\u2026"
|
|
107
|
+
}
|
|
108
|
+
),
|
|
109
|
+
question.inputType === "long-text" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
110
|
+
"textarea",
|
|
111
|
+
{
|
|
112
|
+
value: localValue,
|
|
113
|
+
onChange: (e) => setLocalValue(e.target.value),
|
|
114
|
+
autoFocus: true,
|
|
115
|
+
rows: 5,
|
|
116
|
+
className: "w-full rounded-lg border-2 border-stone-200 bg-stone-50 px-4 py-3 text-lg text-stone-900 focus:border-forest-700 focus:outline-none",
|
|
117
|
+
placeholder: "Type your answer\u2026"
|
|
118
|
+
}
|
|
119
|
+
),
|
|
120
|
+
question.inputType === "select" && question.options && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "space-y-3", role: "radiogroup", "aria-labelledby": `q-${question.id}`, children: question.options.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
121
|
+
"label",
|
|
122
|
+
{
|
|
123
|
+
className: `flex cursor-pointer items-start gap-3 rounded-lg border-2 p-4 transition-colors
|
|
124
|
+
${localValue === opt.value ? "border-forest-700 bg-forest-50" : "border-stone-200 bg-stone-50 hover:border-stone-400"}`,
|
|
125
|
+
children: [
|
|
126
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
127
|
+
"input",
|
|
128
|
+
{
|
|
129
|
+
type: "radio",
|
|
130
|
+
name: question.id,
|
|
131
|
+
value: opt.value,
|
|
132
|
+
checked: localValue === opt.value,
|
|
133
|
+
onChange: (e) => setLocalValue(e.target.value),
|
|
134
|
+
className: "mt-1 h-4 w-4 text-forest-700"
|
|
135
|
+
}
|
|
136
|
+
),
|
|
137
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
138
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "font-medium text-stone-900", children: opt.label }),
|
|
139
|
+
opt.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "mt-1 text-sm text-stone-700", children: opt.description })
|
|
140
|
+
] })
|
|
141
|
+
]
|
|
142
|
+
},
|
|
143
|
+
opt.value
|
|
144
|
+
)) }),
|
|
145
|
+
question.inputType === "multi-select" && question.options && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "space-y-2", role: "group", "aria-labelledby": `q-${question.id}`, children: question.options.map((opt) => {
|
|
146
|
+
const values = localValue || [];
|
|
147
|
+
const checked = values.includes(opt.value);
|
|
148
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
149
|
+
"label",
|
|
150
|
+
{
|
|
151
|
+
className: `flex cursor-pointer items-start gap-3 rounded-lg border-2 p-4 transition-colors
|
|
152
|
+
${checked ? "border-forest-700 bg-forest-50" : "border-stone-200 bg-stone-50 hover:border-stone-400"}`,
|
|
153
|
+
children: [
|
|
154
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
155
|
+
"input",
|
|
156
|
+
{
|
|
157
|
+
type: "checkbox",
|
|
158
|
+
value: opt.value,
|
|
159
|
+
checked,
|
|
160
|
+
onChange: (e) => {
|
|
161
|
+
if (e.target.checked) {
|
|
162
|
+
setLocalValue([...values, opt.value]);
|
|
163
|
+
} else {
|
|
164
|
+
setLocalValue(values.filter((v) => v !== opt.value));
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
className: "mt-1 h-4 w-4 text-forest-700"
|
|
168
|
+
}
|
|
169
|
+
),
|
|
170
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
171
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "font-medium text-stone-900", children: opt.label }),
|
|
172
|
+
opt.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "mt-1 text-sm text-stone-700", children: opt.description })
|
|
173
|
+
] })
|
|
174
|
+
]
|
|
175
|
+
},
|
|
176
|
+
opt.value
|
|
177
|
+
);
|
|
178
|
+
}) }),
|
|
179
|
+
question.inputType === "list" && question.listRange && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
180
|
+
ListInput,
|
|
181
|
+
{
|
|
182
|
+
values: localValue || [],
|
|
183
|
+
onChange: setLocalValue,
|
|
184
|
+
min: question.listRange.min,
|
|
185
|
+
max: question.listRange.max
|
|
186
|
+
}
|
|
187
|
+
)
|
|
188
|
+
] }),
|
|
189
|
+
question.examples && question.examples.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("details", { className: "mt-8", children: [
|
|
190
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("summary", { className: "cursor-pointer text-sm font-medium text-forest-700 hover:text-forest-800", children: "Show examples from different fields" }),
|
|
191
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { className: "mt-4 space-y-3 border-l-2 border-copper-200 pl-5", children: question.examples.map((ex, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { className: "text-sm italic text-stone-700", children: [
|
|
192
|
+
"\u201C",
|
|
193
|
+
ex,
|
|
194
|
+
"\u201D"
|
|
195
|
+
] }, i)) })
|
|
196
|
+
] }),
|
|
197
|
+
!question.required && question.skipConsequence && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "mt-6 text-sm text-stone-500", children: [
|
|
198
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-medium", children: "If you skip this:" }),
|
|
199
|
+
" ",
|
|
200
|
+
question.skipConsequence
|
|
201
|
+
] }),
|
|
202
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mt-10 flex items-center justify-between", children: [
|
|
203
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
204
|
+
"button",
|
|
205
|
+
{
|
|
206
|
+
type: "button",
|
|
207
|
+
onClick: onBack,
|
|
208
|
+
disabled: isFirst,
|
|
209
|
+
className: "btn-ghost disabled:opacity-40",
|
|
210
|
+
children: "\u2190 Back"
|
|
211
|
+
}
|
|
212
|
+
),
|
|
213
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex gap-3", children: [
|
|
214
|
+
!question.required && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", onClick: onNext, className: "btn-ghost", children: "Skip" }),
|
|
215
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "submit", disabled: !canAdvance, className: "btn-primary", children: isLast ? "Review answers" : "Continue \u2192" })
|
|
216
|
+
] })
|
|
217
|
+
] })
|
|
218
|
+
] });
|
|
219
|
+
}
|
|
220
|
+
function ListInput({
|
|
221
|
+
values,
|
|
222
|
+
onChange,
|
|
223
|
+
min,
|
|
224
|
+
max
|
|
225
|
+
}) {
|
|
226
|
+
const items = values.length > 0 ? values : [""];
|
|
227
|
+
const setItem = (i, v) => {
|
|
228
|
+
const next = [...items];
|
|
229
|
+
next[i] = v;
|
|
230
|
+
onChange(next);
|
|
231
|
+
};
|
|
232
|
+
const addItem = () => {
|
|
233
|
+
if (items.length < max) onChange([...items, ""]);
|
|
234
|
+
};
|
|
235
|
+
const removeItem = (i) => {
|
|
236
|
+
if (items.length <= 1) return;
|
|
237
|
+
onChange(items.filter((_, idx) => idx !== i));
|
|
238
|
+
};
|
|
239
|
+
const validCount = items.filter((v) => v.trim().length > 0).length;
|
|
240
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
241
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { className: "space-y-2", children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { className: "flex items-center gap-2", children: [
|
|
242
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "w-6 text-right font-mono text-xs text-stone-400", children: [
|
|
243
|
+
i + 1,
|
|
244
|
+
"."
|
|
245
|
+
] }),
|
|
246
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
247
|
+
"input",
|
|
248
|
+
{
|
|
249
|
+
type: "text",
|
|
250
|
+
value: item,
|
|
251
|
+
onChange: (e) => setItem(i, e.target.value),
|
|
252
|
+
className: "flex-grow rounded-lg border-2 border-stone-200 bg-stone-50 px-3 py-2 text-stone-900 focus:border-forest-700 focus:outline-none",
|
|
253
|
+
placeholder: `Term ${i + 1}`
|
|
254
|
+
}
|
|
255
|
+
),
|
|
256
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
257
|
+
"button",
|
|
258
|
+
{
|
|
259
|
+
type: "button",
|
|
260
|
+
onClick: () => removeItem(i),
|
|
261
|
+
disabled: items.length <= 1,
|
|
262
|
+
className: "btn-ghost text-stone-500 disabled:opacity-30",
|
|
263
|
+
"aria-label": `Remove term ${i + 1}`,
|
|
264
|
+
children: "\xD7"
|
|
265
|
+
}
|
|
266
|
+
)
|
|
267
|
+
] }, i)) }),
|
|
268
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mt-3 flex items-center justify-between", children: [
|
|
269
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
270
|
+
"button",
|
|
271
|
+
{
|
|
272
|
+
type: "button",
|
|
273
|
+
onClick: addItem,
|
|
274
|
+
disabled: items.length >= max,
|
|
275
|
+
className: "text-sm font-medium text-forest-700 hover:text-forest-800 disabled:opacity-40",
|
|
276
|
+
children: "+ Add term"
|
|
277
|
+
}
|
|
278
|
+
),
|
|
279
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-mono text-xs text-stone-500", children: [
|
|
280
|
+
validCount,
|
|
281
|
+
" / ",
|
|
282
|
+
min,
|
|
283
|
+
"\u2013",
|
|
284
|
+
max
|
|
285
|
+
] })
|
|
286
|
+
] })
|
|
287
|
+
] });
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// src/AnswerSidebar.tsx
|
|
291
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
292
|
+
function AnswerSidebar({ questions, currentIndex, answers, onSelectQuestion }) {
|
|
293
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
294
|
+
"aside",
|
|
295
|
+
{
|
|
296
|
+
className: "sticky top-24 hidden max-h-[calc(100vh-6rem)] overflow-y-auto lg:block",
|
|
297
|
+
"aria-label": "Completed answers",
|
|
298
|
+
children: [
|
|
299
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "mb-3 font-mono text-xs uppercase tracking-wider text-stone-500", children: "Your answers" }),
|
|
300
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ol", { className: "space-y-3", children: questions.map((q, i) => {
|
|
301
|
+
const answer = answers[q.id];
|
|
302
|
+
const answered = answer !== void 0 && answer !== "" && !(Array.isArray(answer) && answer.length === 0);
|
|
303
|
+
const isCurrent = i === currentIndex;
|
|
304
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
305
|
+
"button",
|
|
306
|
+
{
|
|
307
|
+
type: "button",
|
|
308
|
+
onClick: () => onSelectQuestion(i),
|
|
309
|
+
className: `w-full rounded-lg border p-3 text-left transition-colors
|
|
310
|
+
${isCurrent ? "border-forest-700 bg-forest-50" : answered ? "border-stone-200 bg-stone-50 hover:border-stone-400" : "border-stone-200/50 bg-stone-50/50 hover:border-stone-300"}`,
|
|
311
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-start gap-2", children: [
|
|
312
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
313
|
+
"span",
|
|
314
|
+
{
|
|
315
|
+
className: `mt-0.5 font-mono text-xs
|
|
316
|
+
${isCurrent ? "text-forest-700" : answered ? "text-stone-500" : "text-stone-400"}`,
|
|
317
|
+
children: [
|
|
318
|
+
String(i + 1).padStart(2, "0"),
|
|
319
|
+
"."
|
|
320
|
+
]
|
|
321
|
+
}
|
|
322
|
+
),
|
|
323
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex-grow", children: [
|
|
324
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
325
|
+
"div",
|
|
326
|
+
{
|
|
327
|
+
className: `text-xs font-medium
|
|
328
|
+
${answered ? "text-stone-900" : "text-stone-500"}`,
|
|
329
|
+
children: q.prompt.length > 50 ? q.prompt.slice(0, 50) + "\u2026" : q.prompt
|
|
330
|
+
}
|
|
331
|
+
),
|
|
332
|
+
answered && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mt-1 text-xs italic text-stone-500 line-clamp-1", children: Array.isArray(answer) ? answer.join(", ") : answer })
|
|
333
|
+
] })
|
|
334
|
+
] })
|
|
335
|
+
}
|
|
336
|
+
) }, q.id);
|
|
337
|
+
}) })
|
|
338
|
+
]
|
|
339
|
+
}
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// src/ReviewSummary.tsx
|
|
344
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
345
|
+
function ReviewSummary({ questions, answers, onGenerate, onEdit, generating }) {
|
|
346
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "animate-slide-up", children: [
|
|
347
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { className: "font-display text-3xl font-medium text-stone-900 sm:text-4xl", children: "Review your answers" }),
|
|
348
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "mt-4 text-lg text-stone-700", children: "These become the seed content of your project. You can edit anything now, or continue and edit later through the platform." }),
|
|
349
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("dl", { className: "mt-10 space-y-6 border-t border-stone-200 pt-6", children: questions.map((q, i) => {
|
|
350
|
+
const answer = answers[q.id];
|
|
351
|
+
const display = Array.isArray(answer) ? answer.length > 0 ? answer.join(", ") : "(not answered)" : answer || "(not answered)";
|
|
352
|
+
const isEmpty = !answer || typeof answer === "string" && answer.trim() === "" || Array.isArray(answer) && answer.length === 0;
|
|
353
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex gap-4 border-b border-stone-200 pb-6", children: [
|
|
354
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "font-mono text-sm text-stone-400 pt-1", children: String(i + 1).padStart(2, "0") }),
|
|
355
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex-grow", children: [
|
|
356
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("dt", { className: "text-sm font-medium text-stone-900", children: q.prompt }),
|
|
357
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("dd", { className: "mt-2 text-stone-900 whitespace-pre-wrap", children: isEmpty ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "italic text-stone-400", children: "Not answered" }) : display })
|
|
358
|
+
] }),
|
|
359
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
360
|
+
"button",
|
|
361
|
+
{
|
|
362
|
+
type: "button",
|
|
363
|
+
onClick: () => onEdit(i),
|
|
364
|
+
className: "btn-ghost text-sm self-start",
|
|
365
|
+
children: "Edit"
|
|
366
|
+
}
|
|
367
|
+
)
|
|
368
|
+
] }, q.id);
|
|
369
|
+
}) }),
|
|
370
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mt-10 rounded-lg border border-copper-300 bg-copper-50 p-6", children: [
|
|
371
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { className: "font-display text-xl text-stone-900", children: "What happens next" }),
|
|
372
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "mt-2 text-stone-900", children: "When you click Generate, the platform will create a GitHub repository in your account, populate it with your personalized CLAUDE.md, KNOWLEDGE.md, and wiki, and give you the URL. This takes about 30\u201390 seconds. You can edit everything afterward through the platform or through your repo." }),
|
|
373
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "mt-3 text-sm text-stone-700", children: [
|
|
374
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "font-medium", children: "MVP note:" }),
|
|
375
|
+
" In this phase, GitHub repo creation is mocked for demonstration. Once OAuth credentials are configured, real repos will be created on your behalf."
|
|
376
|
+
] })
|
|
377
|
+
] }),
|
|
378
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mt-8 flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
379
|
+
"button",
|
|
380
|
+
{
|
|
381
|
+
type: "button",
|
|
382
|
+
onClick: onGenerate,
|
|
383
|
+
disabled: generating,
|
|
384
|
+
className: "btn-primary text-lg",
|
|
385
|
+
children: generating ? "Generating your project\u2026" : "Generate my platform"
|
|
386
|
+
}
|
|
387
|
+
) })
|
|
388
|
+
] });
|
|
389
|
+
}
|
|
390
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
391
|
+
0 && (module.exports = {
|
|
392
|
+
AnswerSidebar,
|
|
393
|
+
ProgressBar,
|
|
394
|
+
QuestionCard,
|
|
395
|
+
ReviewSummary
|
|
396
|
+
});
|
|
397
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/ProgressBar.tsx","../src/QuestionCard.tsx","../src/AnswerSidebar.tsx","../src/ReviewSummary.tsx"],"sourcesContent":["/**\n * @dataimago/interview — public surface barrel.\n *\n * Components (named exports — note the original apps/hub components\n * were default exports; the package exposes them as named exports for\n * tree-shaking and to make the import surface symmetric with @dataimago/ui):\n */\nexport { ProgressBar } from './ProgressBar';\nexport { QuestionCard } from './QuestionCard';\nexport { AnswerSidebar } from './AnswerSidebar';\nexport { ReviewSummary } from './ReviewSummary';\n\n/**\n * Schema contract — the public type surface that consumers populate with\n * their domain-specific question content.\n */\nexport type {\n QuestionInputType,\n InterviewQuestion,\n InterviewAnswers,\n} from './types';\n","'use client';\n\ninterface Props {\n current: number;\n total: number;\n estimatedMinutesRemaining: number;\n}\n\n/**\n * Linear progress indicator for the interview flow. Renders the\n * \"Question N of M\" caption, the estimated minutes remaining, and a\n * forest-700 fill bar at `(current / total) * 100%`.\n *\n * Iteration-1 visual identity (Phase B.2, 2026-05-06):\n * stone-100 surface with stone-200 border; forest-700 fill bar; stone-700\n * caption text. Pure-render component — no state-management dependency.\n *\n * Extracted from `apps/hub/src/components/interview/ProgressBar.tsx`\n * during iteration-3-B.1 (2026-05-07). No prop API change.\n */\nexport function ProgressBar({ current, total, estimatedMinutesRemaining }: Props) {\n const percent = Math.round((current / total) * 100);\n\n return (\n <div className=\"border-b border-stone-200 bg-stone-100 py-3 px-6\">\n <div className=\"mx-auto max-w-3xl\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"font-mono text-xs uppercase tracking-wider text-stone-700\">\n Question {current} of {total}\n </span>\n <span className=\"font-mono text-xs text-stone-500\">\n ~{estimatedMinutesRemaining} min remaining\n </span>\n </div>\n <div\n className=\"mt-2 h-1 w-full overflow-hidden rounded-full bg-stone-200\"\n role=\"progressbar\"\n aria-valuenow={percent}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={`Interview progress: ${percent}% complete`}\n >\n <div\n className=\"h-full bg-forest-700 transition-all duration-300 ease-out\"\n style={{ width: `${percent}%` }}\n />\n </div>\n </div>\n </div>\n );\n}\n","'use client';\n\nimport { useState, useEffect } from 'react';\nimport type { InterviewQuestion } from './types';\n\ninterface Props {\n question: InterviewQuestion;\n /**\n * The currently-saved answer for this question (from the consumer's\n * state container). The component initializes its local form state\n * from this value and re-syncs when the question id changes.\n */\n existingAnswer?: string | string[];\n /**\n * Called when the user submits a non-empty answer (or any answer if\n * the question is `required: false`). The consumer is expected to\n * persist the answer into its state container and then advance via\n * `onNext`.\n */\n onAnswerSubmit: (questionId: string, value: string | string[]) => void;\n /** Called after `onAnswerSubmit` to advance to the next question. */\n onNext: () => void;\n /** Called when the user clicks the Back button. */\n onBack: () => void;\n isFirst: boolean;\n isLast: boolean;\n}\n\n/**\n * Single question renderer. Handles all input types: short-text, long-text,\n * select, multi-select, scale, list. Keyboard-navigable and screen-reader\n * safe.\n *\n * **Decoupled from any state-management library.** The original\n * apps/hub implementation imported `useInterviewStore` directly; this\n * extracted version receives the existing answer + change handler as\n * props, leaving the consumer free to use Zustand, Redux, useState,\n * server-side session state, or any other approach.\n *\n * Iteration-1 visual identity (Phase B.2, 2026-05-06):\n * Form input fields use stone-50 elevated surface + stone-200 default border\n * + forest-700 focus border (interactive-primary focus indicator). Selected\n * radio/checkbox option states use forest-700 border + forest-50 background.\n * The examples disclosure has its border-l-2 frame preserved as\n * border-copper-200 — same decorative-emphasis role as HeroSection's\n * etymology box and ReviewSummary's \"what happens next\" callout, per\n * iteration-1 §5.2's preserved-decorative-copper governance.\n *\n * Iteration-2 role-shift (2026-05-07): copper is no longer the brand-accent\n * moral-weight scale (the brand accent moved to sky-blue accent-500 #1f618d).\n * Copper survives as the \"warm decorative framing on the editorial scale\" —\n * a distinct decorative palette, not subordinate to the brand accent. The\n * border-copper-200 site below continues to serve its visual role (warm\n * framing for examples-list editorial content); its semantic relationship\n * to the brand accent is now zero. See wiki/decisions/iteration-2-blue-accent.md.\n *\n * Extracted from `apps/hub/src/components/interview/QuestionCard.tsx`\n * during iteration-3-B.1 (2026-05-07). Decoupled from `useInterviewStore`.\n */\nexport function QuestionCard({\n question,\n existingAnswer,\n onAnswerSubmit,\n onNext,\n onBack,\n isFirst,\n isLast,\n}: Props) {\n const [localValue, setLocalValue] = useState<string | string[]>(\n existingAnswer ?? (question.inputType === 'multi-select' || question.inputType === 'list' ? [] : '')\n );\n\n // Sync when question changes (consumer flipped to a different question;\n // local form state should reflect that question's existing answer).\n useEffect(() => {\n const current =\n existingAnswer ??\n (question.inputType === 'multi-select' || question.inputType === 'list' ? [] : '');\n setLocalValue(current);\n }, [question.id, existingAnswer, question.inputType]);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n onAnswerSubmit(question.id, localValue);\n onNext();\n };\n\n const canAdvance = question.required\n ? Array.isArray(localValue)\n ? localValue.length > 0\n : localValue.trim().length > 0\n : true;\n\n return (\n <form onSubmit={handleSubmit} className=\"animate-slide-up\">\n {/* Prompt */}\n <h2 className=\"font-display text-3xl font-medium text-stone-900 sm:text-4xl\">\n {question.prompt}\n </h2>\n {question.subprompt && (\n <p className=\"mt-4 text-lg text-stone-700\">{question.subprompt}</p>\n )}\n\n {/* Input */}\n <div className=\"mt-8\">\n {question.inputType === 'short-text' && (\n <input\n type=\"text\"\n value={localValue as string}\n onChange={(e) => setLocalValue(e.target.value)}\n autoFocus\n className=\"w-full rounded-lg border-2 border-stone-200 bg-stone-50 px-4 py-3 text-lg text-stone-900 focus:border-forest-700 focus:outline-none\"\n placeholder=\"Type your answer…\"\n />\n )}\n\n {question.inputType === 'long-text' && (\n <textarea\n value={localValue as string}\n onChange={(e) => setLocalValue(e.target.value)}\n autoFocus\n rows={5}\n className=\"w-full rounded-lg border-2 border-stone-200 bg-stone-50 px-4 py-3 text-lg text-stone-900 focus:border-forest-700 focus:outline-none\"\n placeholder=\"Type your answer…\"\n />\n )}\n\n {question.inputType === 'select' && question.options && (\n <div className=\"space-y-3\" role=\"radiogroup\" aria-labelledby={`q-${question.id}`}>\n {question.options.map((opt) => (\n <label\n key={opt.value}\n className={`flex cursor-pointer items-start gap-3 rounded-lg border-2 p-4 transition-colors\n ${\n localValue === opt.value\n ? 'border-forest-700 bg-forest-50'\n : 'border-stone-200 bg-stone-50 hover:border-stone-400'\n }`}\n >\n <input\n type=\"radio\"\n name={question.id}\n value={opt.value}\n checked={localValue === opt.value}\n onChange={(e) => setLocalValue(e.target.value)}\n className=\"mt-1 h-4 w-4 text-forest-700\"\n />\n <div>\n <div className=\"font-medium text-stone-900\">{opt.label}</div>\n {opt.description && (\n <div className=\"mt-1 text-sm text-stone-700\">{opt.description}</div>\n )}\n </div>\n </label>\n ))}\n </div>\n )}\n\n {question.inputType === 'multi-select' && question.options && (\n <div className=\"space-y-2\" role=\"group\" aria-labelledby={`q-${question.id}`}>\n {question.options.map((opt) => {\n const values = (localValue as string[]) || [];\n const checked = values.includes(opt.value);\n return (\n <label\n key={opt.value}\n className={`flex cursor-pointer items-start gap-3 rounded-lg border-2 p-4 transition-colors\n ${\n checked\n ? 'border-forest-700 bg-forest-50'\n : 'border-stone-200 bg-stone-50 hover:border-stone-400'\n }`}\n >\n <input\n type=\"checkbox\"\n value={opt.value}\n checked={checked}\n onChange={(e) => {\n if (e.target.checked) {\n setLocalValue([...values, opt.value]);\n } else {\n setLocalValue(values.filter((v) => v !== opt.value));\n }\n }}\n className=\"mt-1 h-4 w-4 text-forest-700\"\n />\n <div>\n <div className=\"font-medium text-stone-900\">{opt.label}</div>\n {opt.description && (\n <div className=\"mt-1 text-sm text-stone-700\">{opt.description}</div>\n )}\n </div>\n </label>\n );\n })}\n </div>\n )}\n\n {question.inputType === 'list' && question.listRange && (\n <ListInput\n values={(localValue as string[]) || []}\n onChange={setLocalValue}\n min={question.listRange.min}\n max={question.listRange.max}\n />\n )}\n </div>\n\n {/* Examples */}\n {question.examples && question.examples.length > 0 && (\n <details className=\"mt-8\">\n <summary className=\"cursor-pointer text-sm font-medium text-forest-700 hover:text-forest-800\">\n Show examples from different fields\n </summary>\n {/* border-copper-200 PRESERVED: decorative-emphasis frame around\n illustrative content, same role as HeroSection's etymology box. */}\n <ul className=\"mt-4 space-y-3 border-l-2 border-copper-200 pl-5\">\n {question.examples.map((ex, i) => (\n <li key={i} className=\"text-sm italic text-stone-700\">\n “{ex}”\n </li>\n ))}\n </ul>\n </details>\n )}\n\n {/* Skip consequence (if applicable) */}\n {!question.required && question.skipConsequence && (\n <p className=\"mt-6 text-sm text-stone-500\">\n <span className=\"font-medium\">If you skip this:</span> {question.skipConsequence}\n </p>\n )}\n\n {/* Nav */}\n <div className=\"mt-10 flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={onBack}\n disabled={isFirst}\n className=\"btn-ghost disabled:opacity-40\"\n >\n ← Back\n </button>\n <div className=\"flex gap-3\">\n {!question.required && (\n <button type=\"button\" onClick={onNext} className=\"btn-ghost\">\n Skip\n </button>\n )}\n <button type=\"submit\" disabled={!canAdvance} className=\"btn-primary\">\n {isLast ? 'Review answers' : 'Continue →'}\n </button>\n </div>\n </div>\n </form>\n );\n}\n\n/** List input (for glossary terms) — add/remove rows */\nfunction ListInput({\n values,\n onChange,\n min,\n max,\n}: {\n values: string[];\n onChange: (v: string[]) => void;\n min: number;\n max: number;\n}) {\n const items = values.length > 0 ? values : [''];\n\n const setItem = (i: number, v: string) => {\n const next = [...items];\n next[i] = v;\n onChange(next);\n };\n\n const addItem = () => {\n if (items.length < max) onChange([...items, '']);\n };\n\n const removeItem = (i: number) => {\n if (items.length <= 1) return;\n onChange(items.filter((_, idx) => idx !== i));\n };\n\n const validCount = items.filter((v) => v.trim().length > 0).length;\n\n return (\n <div>\n <ul className=\"space-y-2\">\n {items.map((item, i) => (\n <li key={i} className=\"flex items-center gap-2\">\n <span className=\"w-6 text-right font-mono text-xs text-stone-400\">{i + 1}.</span>\n <input\n type=\"text\"\n value={item}\n onChange={(e) => setItem(i, e.target.value)}\n className=\"flex-grow rounded-lg border-2 border-stone-200 bg-stone-50 px-3 py-2 text-stone-900 focus:border-forest-700 focus:outline-none\"\n placeholder={`Term ${i + 1}`}\n />\n <button\n type=\"button\"\n onClick={() => removeItem(i)}\n disabled={items.length <= 1}\n className=\"btn-ghost text-stone-500 disabled:opacity-30\"\n aria-label={`Remove term ${i + 1}`}\n >\n ×\n </button>\n </li>\n ))}\n </ul>\n <div className=\"mt-3 flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={addItem}\n disabled={items.length >= max}\n className=\"text-sm font-medium text-forest-700 hover:text-forest-800 disabled:opacity-40\"\n >\n + Add term\n </button>\n <span className=\"font-mono text-xs text-stone-500\">\n {validCount} / {min}–{max}\n </span>\n </div>\n </div>\n );\n}\n","'use client';\n\nimport type { InterviewAnswers, InterviewQuestion } from './types';\n\ninterface Props {\n questions: InterviewQuestion[];\n currentIndex: number;\n /** Consumer's current answer record (read-only — engine doesn't write). */\n answers: InterviewAnswers;\n /** Called when the user clicks a sidebar item to jump to that question. */\n onSelectQuestion: (index: number) => void;\n}\n\n/**\n * Sidebar showing all answered questions. Clicking any returns to edit that\n * question without losing later answers. Implements the wiki's pattern:\n * \"Edit any prior answer — a sidebar shows all answered questions.\"\n *\n * **Decoupled from any state-management library.** The original\n * apps/hub implementation imported `useInterviewStore` directly; this\n * extracted version receives the answers + jump handler as props.\n *\n * Iteration-1 visual identity (Phase B.2, 2026-05-06):\n * Three item states with distinct token tiers:\n * - current → forest-700 border + forest-50 bg (interactive primary)\n * - answered → stone-200 border + stone-50 bg (default, hover stone-400)\n * - unanswered → stone-200/50 + stone-50/50 (muted via opacity preservation)\n *\n * Extracted from `apps/hub/src/components/interview/AnswerSidebar.tsx`\n * during iteration-3-B.1 (2026-05-07). Decoupled from `useInterviewStore`.\n */\nexport function AnswerSidebar({ questions, currentIndex, answers, onSelectQuestion }: Props) {\n return (\n <aside\n className=\"sticky top-24 hidden max-h-[calc(100vh-6rem)] overflow-y-auto lg:block\"\n aria-label=\"Completed answers\"\n >\n <h3 className=\"mb-3 font-mono text-xs uppercase tracking-wider text-stone-500\">\n Your answers\n </h3>\n <ol className=\"space-y-3\">\n {questions.map((q, i) => {\n const answer = answers[q.id];\n const answered =\n answer !== undefined &&\n answer !== '' &&\n !(Array.isArray(answer) && answer.length === 0);\n const isCurrent = i === currentIndex;\n\n return (\n <li key={q.id}>\n <button\n type=\"button\"\n onClick={() => onSelectQuestion(i)}\n className={`w-full rounded-lg border p-3 text-left transition-colors\n ${\n isCurrent\n ? 'border-forest-700 bg-forest-50'\n : answered\n ? 'border-stone-200 bg-stone-50 hover:border-stone-400'\n : 'border-stone-200/50 bg-stone-50/50 hover:border-stone-300'\n }`}\n >\n <div className=\"flex items-start gap-2\">\n <span\n className={`mt-0.5 font-mono text-xs\n ${\n isCurrent\n ? 'text-forest-700'\n : answered\n ? 'text-stone-500'\n : 'text-stone-400'\n }`}\n >\n {String(i + 1).padStart(2, '0')}.\n </span>\n <div className=\"flex-grow\">\n <div\n className={`text-xs font-medium\n ${answered ? 'text-stone-900' : 'text-stone-500'}`}\n >\n {q.prompt.length > 50 ? q.prompt.slice(0, 50) + '…' : q.prompt}\n </div>\n {answered && (\n <div className=\"mt-1 text-xs italic text-stone-500 line-clamp-1\">\n {Array.isArray(answer) ? answer.join(', ') : answer}\n </div>\n )}\n </div>\n </div>\n </button>\n </li>\n );\n })}\n </ol>\n </aside>\n );\n}\n","'use client';\n\nimport type { InterviewAnswers, InterviewQuestion } from './types';\n\ninterface Props {\n questions: InterviewQuestion[];\n /** Consumer's current answer record (read-only — engine doesn't write). */\n answers: InterviewAnswers;\n onGenerate: () => void;\n onEdit: (questionIndex: number) => void;\n generating: boolean;\n}\n\n/**\n * Final review screen — the penultimate step before generation.\n * Shows all answers so the user can confirm ownership of the output before\n * committing.\n *\n * **Decoupled from any state-management library.** The original\n * apps/hub implementation imported `useInterviewStore` directly; this\n * extracted version receives the answer record as a prop.\n *\n * Iteration-1 visual identity (Phase B.2, 2026-05-06):\n * Editorial Josefin display family on the heading and the \"What happens next\"\n * callout title. Stone-tier surfaces and content text throughout. The\n * \"What happens next\" callout box preserves border-copper-300 + bg-copper-50 —\n * iteration-1 §5.2's preserved-decorative-copper role applied to the\n * informational/forward-looking callout, same pattern as HeroSection's\n * etymology box.\n *\n * Iteration-2 role-shift (2026-05-07): copper is no longer subordinate to\n * the brand accent (which moved to sky-blue accent-500 #1f618d). Copper is\n * its own \"warm decorative framing on the editorial scale\" — distinct from\n * the brand-accent role. The \"What happens next\" callout continues to serve\n * its visual function (warm forward-looking framing); its semantic relation\n * to the brand accent is now zero. See wiki/decisions/iteration-2-blue-accent.md.\n *\n * Extracted from `apps/hub/src/components/interview/ReviewSummary.tsx`\n * during iteration-3-B.1 (2026-05-07). Decoupled from `useInterviewStore`.\n */\nexport function ReviewSummary({ questions, answers, onGenerate, onEdit, generating }: Props) {\n return (\n <div className=\"animate-slide-up\">\n <h2 className=\"font-display text-3xl font-medium text-stone-900 sm:text-4xl\">\n Review your answers\n </h2>\n <p className=\"mt-4 text-lg text-stone-700\">\n These become the seed content of your project. You can edit anything now, or continue and\n edit later through the platform.\n </p>\n\n <dl className=\"mt-10 space-y-6 border-t border-stone-200 pt-6\">\n {questions.map((q, i) => {\n const answer = answers[q.id];\n const display = Array.isArray(answer)\n ? answer.length > 0\n ? answer.join(', ')\n : '(not answered)'\n : (answer as string) || '(not answered)';\n const isEmpty =\n !answer ||\n (typeof answer === 'string' && answer.trim() === '') ||\n (Array.isArray(answer) && answer.length === 0);\n\n return (\n <div key={q.id} className=\"flex gap-4 border-b border-stone-200 pb-6\">\n <span className=\"font-mono text-sm text-stone-400 pt-1\">\n {String(i + 1).padStart(2, '0')}\n </span>\n <div className=\"flex-grow\">\n <dt className=\"text-sm font-medium text-stone-900\">{q.prompt}</dt>\n <dd className=\"mt-2 text-stone-900 whitespace-pre-wrap\">\n {isEmpty ? (\n <span className=\"italic text-stone-400\">Not answered</span>\n ) : (\n display\n )}\n </dd>\n </div>\n <button\n type=\"button\"\n onClick={() => onEdit(i)}\n className=\"btn-ghost text-sm self-start\"\n >\n Edit\n </button>\n </div>\n );\n })}\n </dl>\n\n {/* \"What happens next\" callout — copper PRESERVED as decorative\n informational frame, same role as HeroSection's etymology box.\n Per iteration-1 §5.2's preserved-decorative-copper governance. */}\n <div className=\"mt-10 rounded-lg border border-copper-300 bg-copper-50 p-6\">\n <h3 className=\"font-display text-xl text-stone-900\">What happens next</h3>\n <p className=\"mt-2 text-stone-900\">\n When you click Generate, the platform will create a GitHub repository in your account,\n populate it with your personalized CLAUDE.md, KNOWLEDGE.md, and wiki, and give you the\n URL. This takes about 30–90 seconds. You can edit everything afterward through the\n platform or through your repo.\n </p>\n <p className=\"mt-3 text-sm text-stone-700\">\n <span className=\"font-medium\">MVP note:</span> In this phase, GitHub repo creation is\n mocked for demonstration. Once OAuth credentials are configured, real repos will be\n created on your behalf.\n </p>\n </div>\n\n <div className=\"mt-8 flex justify-end\">\n <button\n type=\"button\"\n onClick={onGenerate}\n disabled={generating}\n className=\"btn-primary text-lg\"\n >\n {generating ? 'Generating your project…' : 'Generate my platform'}\n </button>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC2BU;AAPH,SAAS,YAAY,EAAE,SAAS,OAAO,0BAA0B,GAAU;AAChF,QAAM,UAAU,KAAK,MAAO,UAAU,QAAS,GAAG;AAElD,SACE,4CAAC,SAAI,WAAU,oDACb,uDAAC,SAAI,WAAU,qBACb;AAAA,iDAAC,SAAI,WAAU,6CACb;AAAA,mDAAC,UAAK,WAAU,6DAA4D;AAAA;AAAA,QAChE;AAAA,QAAQ;AAAA,QAAK;AAAA,SACzB;AAAA,MACA,6CAAC,UAAK,WAAU,oCAAmC;AAAA;AAAA,QAC/C;AAAA,QAA0B;AAAA,SAC9B;AAAA,OACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,MAAK;AAAA,QACL,iBAAe;AAAA,QACf,iBAAe;AAAA,QACf,iBAAe;AAAA,QACf,cAAY,uBAAuB,OAAO;AAAA,QAE1C;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI;AAAA;AAAA,QAChC;AAAA;AAAA,IACF;AAAA,KACF,GACF;AAEJ;;;AChDA,mBAAoC;AA8F9B,IAAAA,sBAAA;AArCC,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAU;AACR,QAAM,CAAC,YAAY,aAAa,QAAI;AAAA,IAClC,mBAAmB,SAAS,cAAc,kBAAkB,SAAS,cAAc,SAAS,CAAC,IAAI;AAAA,EACnG;AAIA,8BAAU,MAAM;AACd,UAAM,UACJ,mBACC,SAAS,cAAc,kBAAkB,SAAS,cAAc,SAAS,CAAC,IAAI;AACjF,kBAAc,OAAO;AAAA,EACvB,GAAG,CAAC,SAAS,IAAI,gBAAgB,SAAS,SAAS,CAAC;AAEpD,QAAM,eAAe,CAAC,MAAuB;AAC3C,MAAE,eAAe;AACjB,mBAAe,SAAS,IAAI,UAAU;AACtC,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,SAAS,WACxB,MAAM,QAAQ,UAAU,IACtB,WAAW,SAAS,IACpB,WAAW,KAAK,EAAE,SAAS,IAC7B;AAEJ,SACE,8CAAC,UAAK,UAAU,cAAc,WAAU,oBAEtC;AAAA,iDAAC,QAAG,WAAU,gEACX,mBAAS,QACZ;AAAA,IACC,SAAS,aACR,6CAAC,OAAE,WAAU,+BAA+B,mBAAS,WAAU;AAAA,IAIjE,8CAAC,SAAI,WAAU,QACZ;AAAA,eAAS,cAAc,gBACtB;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,cAAc,EAAE,OAAO,KAAK;AAAA,UAC7C,WAAS;AAAA,UACT,WAAU;AAAA,UACV,aAAY;AAAA;AAAA,MACd;AAAA,MAGD,SAAS,cAAc,eACtB;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,cAAc,EAAE,OAAO,KAAK;AAAA,UAC7C,WAAS;AAAA,UACT,MAAM;AAAA,UACN,WAAU;AAAA,UACV,aAAY;AAAA;AAAA,MACd;AAAA,MAGD,SAAS,cAAc,YAAY,SAAS,WAC3C,6CAAC,SAAI,WAAU,aAAY,MAAK,cAAa,mBAAiB,KAAK,SAAS,EAAE,IAC3E,mBAAS,QAAQ,IAAI,CAAC,QACrB;AAAA,QAAC;AAAA;AAAA,UAEC,WAAW;AAAA,oBAEP,eAAe,IAAI,QACf,mCACA,qDACN;AAAA,UAEF;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,MAAM,SAAS;AAAA,gBACf,OAAO,IAAI;AAAA,gBACX,SAAS,eAAe,IAAI;AAAA,gBAC5B,UAAU,CAAC,MAAM,cAAc,EAAE,OAAO,KAAK;AAAA,gBAC7C,WAAU;AAAA;AAAA,YACZ;AAAA,YACA,8CAAC,SACC;AAAA,2DAAC,SAAI,WAAU,8BAA8B,cAAI,OAAM;AAAA,cACtD,IAAI,eACH,6CAAC,SAAI,WAAU,+BAA+B,cAAI,aAAY;AAAA,eAElE;AAAA;AAAA;AAAA,QArBK,IAAI;AAAA,MAsBX,CACD,GACH;AAAA,MAGD,SAAS,cAAc,kBAAkB,SAAS,WACjD,6CAAC,SAAI,WAAU,aAAY,MAAK,SAAQ,mBAAiB,KAAK,SAAS,EAAE,IACtE,mBAAS,QAAQ,IAAI,CAAC,QAAQ;AAC7B,cAAM,SAAU,cAA2B,CAAC;AAC5C,cAAM,UAAU,OAAO,SAAS,IAAI,KAAK;AACzC,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,WAAW;AAAA,sBAEP,UACI,mCACA,qDACN;AAAA,YAEF;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,OAAO,IAAI;AAAA,kBACX;AAAA,kBACA,UAAU,CAAC,MAAM;AACf,wBAAI,EAAE,OAAO,SAAS;AACpB,oCAAc,CAAC,GAAG,QAAQ,IAAI,KAAK,CAAC;AAAA,oBACtC,OAAO;AACL,oCAAc,OAAO,OAAO,CAAC,MAAM,MAAM,IAAI,KAAK,CAAC;AAAA,oBACrD;AAAA,kBACF;AAAA,kBACA,WAAU;AAAA;AAAA,cACZ;AAAA,cACA,8CAAC,SACC;AAAA,6DAAC,SAAI,WAAU,8BAA8B,cAAI,OAAM;AAAA,gBACtD,IAAI,eACH,6CAAC,SAAI,WAAU,+BAA+B,cAAI,aAAY;AAAA,iBAElE;AAAA;AAAA;AAAA,UA1BK,IAAI;AAAA,QA2BX;AAAA,MAEJ,CAAC,GACH;AAAA,MAGD,SAAS,cAAc,UAAU,SAAS,aACzC;AAAA,QAAC;AAAA;AAAA,UACC,QAAS,cAA2B,CAAC;AAAA,UACrC,UAAU;AAAA,UACV,KAAK,SAAS,UAAU;AAAA,UACxB,KAAK,SAAS,UAAU;AAAA;AAAA,MAC1B;AAAA,OAEJ;AAAA,IAGC,SAAS,YAAY,SAAS,SAAS,SAAS,KAC/C,8CAAC,aAAQ,WAAU,QACjB;AAAA,mDAAC,aAAQ,WAAU,4EAA2E,iDAE9F;AAAA,MAGA,6CAAC,QAAG,WAAU,oDACX,mBAAS,SAAS,IAAI,CAAC,IAAI,MAC1B,8CAAC,QAAW,WAAU,iCAAgC;AAAA;AAAA,QAClD;AAAA,QAAG;AAAA,WADE,CAET,CACD,GACH;AAAA,OACF;AAAA,IAID,CAAC,SAAS,YAAY,SAAS,mBAC9B,8CAAC,OAAE,WAAU,+BACX;AAAA,mDAAC,UAAK,WAAU,eAAc,+BAAiB;AAAA,MAAO;AAAA,MAAE,SAAS;AAAA,OACnE;AAAA,IAIF,8CAAC,SAAI,WAAU,2CACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,UAAU;AAAA,UACV,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,MACA,8CAAC,SAAI,WAAU,cACZ;AAAA,SAAC,SAAS,YACT,6CAAC,YAAO,MAAK,UAAS,SAAS,QAAQ,WAAU,aAAY,kBAE7D;AAAA,QAEF,6CAAC,YAAO,MAAK,UAAS,UAAU,CAAC,YAAY,WAAU,eACpD,mBAAS,mBAAmB,mBAC/B;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAEJ;AAGA,SAAS,UAAU;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,QAAQ,OAAO,SAAS,IAAI,SAAS,CAAC,EAAE;AAE9C,QAAM,UAAU,CAAC,GAAW,MAAc;AACxC,UAAM,OAAO,CAAC,GAAG,KAAK;AACtB,SAAK,CAAC,IAAI;AACV,aAAS,IAAI;AAAA,EACf;AAEA,QAAM,UAAU,MAAM;AACpB,QAAI,MAAM,SAAS,IAAK,UAAS,CAAC,GAAG,OAAO,EAAE,CAAC;AAAA,EACjD;AAEA,QAAM,aAAa,CAAC,MAAc;AAChC,QAAI,MAAM,UAAU,EAAG;AACvB,aAAS,MAAM,OAAO,CAAC,GAAG,QAAQ,QAAQ,CAAC,CAAC;AAAA,EAC9C;AAEA,QAAM,aAAa,MAAM,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE;AAE5D,SACE,8CAAC,SACC;AAAA,iDAAC,QAAG,WAAU,aACX,gBAAM,IAAI,CAAC,MAAM,MAChB,8CAAC,QAAW,WAAU,2BACpB;AAAA,oDAAC,UAAK,WAAU,mDAAmD;AAAA,YAAI;AAAA,QAAE;AAAA,SAAC;AAAA,MAC1E;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,QAAQ,GAAG,EAAE,OAAO,KAAK;AAAA,UAC1C,WAAU;AAAA,UACV,aAAa,QAAQ,IAAI,CAAC;AAAA;AAAA,MAC5B;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,WAAW,CAAC;AAAA,UAC3B,UAAU,MAAM,UAAU;AAAA,UAC1B,WAAU;AAAA,UACV,cAAY,eAAe,IAAI,CAAC;AAAA,UACjC;AAAA;AAAA,MAED;AAAA,SAjBO,CAkBT,CACD,GACH;AAAA,IACA,8CAAC,SAAI,WAAU,0CACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,UAAU,MAAM,UAAU;AAAA,UAC1B,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,MACA,8CAAC,UAAK,WAAU,oCACb;AAAA;AAAA,QAAW;AAAA,QAAI;AAAA,QAAI;AAAA,QAAE;AAAA,SACxB;AAAA,OACF;AAAA,KACF;AAEJ;;;ACpSM,IAAAC,sBAAA;AANC,SAAS,cAAc,EAAE,WAAW,cAAc,SAAS,iBAAiB,GAAU;AAC3F,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,cAAW;AAAA,MAEX;AAAA,qDAAC,QAAG,WAAU,kEAAiE,0BAE/E;AAAA,QACA,6CAAC,QAAG,WAAU,aACX,oBAAU,IAAI,CAAC,GAAG,MAAM;AACvB,gBAAM,SAAS,QAAQ,EAAE,EAAE;AAC3B,gBAAM,WACJ,WAAW,UACX,WAAW,MACX,EAAE,MAAM,QAAQ,MAAM,KAAK,OAAO,WAAW;AAC/C,gBAAM,YAAY,MAAM;AAExB,iBACE,6CAAC,QACC;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM,iBAAiB,CAAC;AAAA,cACjC,WAAW;AAAA,oBAEP,YACI,mCACA,WACA,wDACA,2DACN;AAAA,cAEF,wDAAC,SAAI,WAAU,0BACb;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAW;AAAA,wBAEP,YACI,oBACA,WACA,mBACA,gBACN;AAAA,oBAED;AAAA,6BAAO,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,sBAAE;AAAA;AAAA;AAAA,gBAClC;AAAA,gBACA,8CAAC,SAAI,WAAU,aACb;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,WAAW;AAAA,0BACP,WAAW,mBAAmB,gBAAgB;AAAA,sBAEjD,YAAE,OAAO,SAAS,KAAK,EAAE,OAAO,MAAM,GAAG,EAAE,IAAI,WAAM,EAAE;AAAA;AAAA,kBAC1D;AAAA,kBACC,YACC,6CAAC,SAAI,WAAU,mDACZ,gBAAM,QAAQ,MAAM,IAAI,OAAO,KAAK,IAAI,IAAI,QAC/C;AAAA,mBAEJ;AAAA,iBACF;AAAA;AAAA,UACF,KAxCO,EAAE,EAyCX;AAAA,QAEJ,CAAC,GACH;AAAA;AAAA;AAAA,EACF;AAEJ;;;ACtDM,IAAAC,sBAAA;AAHC,SAAS,cAAc,EAAE,WAAW,SAAS,YAAY,QAAQ,WAAW,GAAU;AAC3F,SACE,8CAAC,SAAI,WAAU,oBACb;AAAA,iDAAC,QAAG,WAAU,gEAA+D,iCAE7E;AAAA,IACA,6CAAC,OAAE,WAAU,+BAA8B,wIAG3C;AAAA,IAEA,6CAAC,QAAG,WAAU,kDACX,oBAAU,IAAI,CAAC,GAAG,MAAM;AACvB,YAAM,SAAS,QAAQ,EAAE,EAAE;AAC3B,YAAM,UAAU,MAAM,QAAQ,MAAM,IAChC,OAAO,SAAS,IACd,OAAO,KAAK,IAAI,IAChB,mBACD,UAAqB;AAC1B,YAAM,UACJ,CAAC,UACA,OAAO,WAAW,YAAY,OAAO,KAAK,MAAM,MAChD,MAAM,QAAQ,MAAM,KAAK,OAAO,WAAW;AAE9C,aACE,8CAAC,SAAe,WAAU,6CACxB;AAAA,qDAAC,UAAK,WAAU,yCACb,iBAAO,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG,GAChC;AAAA,QACA,8CAAC,SAAI,WAAU,aACb;AAAA,uDAAC,QAAG,WAAU,sCAAsC,YAAE,QAAO;AAAA,UAC7D,6CAAC,QAAG,WAAU,2CACX,oBACC,6CAAC,UAAK,WAAU,yBAAwB,0BAAY,IAEpD,SAEJ;AAAA,WACF;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS,MAAM,OAAO,CAAC;AAAA,YACvB,WAAU;AAAA,YACX;AAAA;AAAA,QAED;AAAA,WApBQ,EAAE,EAqBZ;AAAA,IAEJ,CAAC,GACH;AAAA,IAKA,8CAAC,SAAI,WAAU,8DACb;AAAA,mDAAC,QAAG,WAAU,uCAAsC,+BAAiB;AAAA,MACrE,6CAAC,OAAE,WAAU,uBAAsB,kTAKnC;AAAA,MACA,8CAAC,OAAE,WAAU,+BACX;AAAA,qDAAC,UAAK,WAAU,eAAc,uBAAS;AAAA,QAAO;AAAA,SAGhD;AAAA,OACF;AAAA,IAEA,6CAAC,SAAI,WAAU,yBACb;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAU;AAAA,QAET,uBAAa,kCAA6B;AAAA;AAAA,IAC7C,GACF;AAAA,KACF;AAEJ;","names":["import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
|