@marsbdigital/paperclip-content-sprint-plugin 0.1.1 → 0.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/README.md +11 -0
- package/dist/manifest.js +1 -1
- package/dist/manifest.js.map +1 -1
- package/dist/ui/index.js +190 -94
- package/dist/ui/index.js.map +4 -4
- package/package.json +1 -1
- package/plugin.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
npm package **`@marsbdigital/paperclip-content-sprint-plugin`** — generates five structured social posts from product context (two authority, two engagement, one conversion) for **LinkedIn** or **X (Twitter)**.
|
|
4
4
|
|
|
5
|
+
**Latest release:** `0.1.3` — labeled form fields, `id`/`htmlFor`, modal `aria-labelledby`, and explicit light-theme colors for readable UI on dark Paperclip shells. Upgrade from `0.1.1` / `0.1.2` via Install Plugin or reinstall the package.
|
|
6
|
+
|
|
5
7
|
## Paperclip manifest id
|
|
6
8
|
|
|
7
9
|
The host requires plugin ids to match `^[a-z0-9][a-z0-9._-]*$`. This plugin’s manifest id is **`marsbdigital.paperclip-content-sprint-plugin`** (see `plugin.json`). The scoped npm name stays **`@marsbdigital/paperclip-content-sprint-plugin`**.
|
|
@@ -20,6 +22,15 @@ This manifest does **not** set `minimumHostVersion`. That field is optional; off
|
|
|
20
22
|
| `src/ui/ToolbarButton.tsx` | `globalToolbarButton` slot — **⚡ Content Sprint** |
|
|
21
23
|
| `src/ui/ContentSprintPanel.tsx` | `dashboardWidget` — form, generate, loading, output |
|
|
22
24
|
|
|
25
|
+
## Where the UI appears (important)
|
|
26
|
+
|
|
27
|
+
**Instance Settings → Plugins** (and most operator / “settings-only” layouts) usually use a **different shell** than the main company workspace. The **`globalToolbarButton`** slot is wired to the **main app top bar** (the strip with breadcrumbs such as `Company > …`), not to the Plugin Manager screen.
|
|
28
|
+
|
|
29
|
+
- **⚡ Content Sprint (`globalToolbarButton`)** — Open a **company workspace** route (e.g. **Dashboard**, **Issues**, **Projects**, **Goals**) and check the **top bar** next to breadcrumbs. You should **not** expect this button on **Settings → Plugins** or other instance-admin pages that omit that chrome.
|
|
30
|
+
- **Content Sprint AI (`dashboardWidget`)** — Renders on the **company Dashboard** as a card/widget, not on the Plugin Manager list.
|
|
31
|
+
|
|
32
|
+
Official examples: [Hello World](https://github.com/paperclipai/paperclip/blob/master/packages/plugins/examples/plugin-hello-world-example/src/manifest.ts) only registers **`dashboardWidget`**. [Kitchen Sink](https://github.com/paperclipai/paperclip/blob/master/packages/plugins/examples/plugin-kitchen-sink-example/src/manifest.ts) registers **`toolbarButton`** on **project/issue** pages but does **not** use **`globalToolbarButton`**. This plugin’s manifest declares `exportName: "ToolbarButton"`, which matches `export { ToolbarButton }` from `src/ui/index.tsx`.
|
|
33
|
+
|
|
23
34
|
## Scripts
|
|
24
35
|
|
|
25
36
|
```bash
|
package/dist/manifest.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
var plugin_default = {
|
|
3
3
|
id: "marsbdigital.paperclip-content-sprint-plugin",
|
|
4
4
|
apiVersion: 1,
|
|
5
|
-
version: "0.1.
|
|
5
|
+
version: "0.1.3",
|
|
6
6
|
displayName: "Content Sprint AI",
|
|
7
7
|
description: "Generate five structured social posts (authority, engagement, conversion) from product context for LinkedIn or X.",
|
|
8
8
|
author: "Mars B Digital",
|
package/dist/manifest.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../plugin.json", "../src/manifest.ts"],
|
|
4
|
-
"sourcesContent": ["{\n \"id\": \"marsbdigital.paperclip-content-sprint-plugin\",\n \"apiVersion\": 1,\n \"version\": \"0.1.
|
|
4
|
+
"sourcesContent": ["{\n \"id\": \"marsbdigital.paperclip-content-sprint-plugin\",\n \"apiVersion\": 1,\n \"version\": \"0.1.3\",\n \"displayName\": \"Content Sprint AI\",\n \"description\": \"Generate five structured social posts (authority, engagement, conversion) from product context for LinkedIn or X.\",\n \"author\": \"Mars B Digital\",\n \"categories\": [\"automation\", \"ui\"],\n \"capabilities\": [\n \"agent.tools.register\",\n \"jobs.schedule\",\n \"ui.action.register\",\n \"ui.dashboardWidget.register\"\n ],\n \"entrypoints\": {\n \"worker\": \"dist/index.js\",\n \"ui\": \"dist/ui\"\n },\n \"tools\": [\n {\n \"name\": \"generate_content_batch\",\n \"displayName\": \"Generate content batch\",\n \"description\": \"Creates five social posts (2 authority, 2 engagement, 1 conversion) from product name, description, audience, and platform.\",\n \"parametersSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"productName\": { \"type\": \"string\", \"description\": \"Product or offer name\" },\n \"productDescription\": { \"type\": \"string\", \"description\": \"What the product does and why it matters\" },\n \"targetAudience\": { \"type\": \"string\", \"description\": \"Who you are writing for\" },\n \"platform\": {\n \"type\": \"string\",\n \"enum\": [\"linkedin\", \"twitter\"],\n \"description\": \"Target network\"\n }\n },\n \"required\": [\"productName\", \"productDescription\", \"targetAudience\", \"platform\"]\n }\n }\n ],\n \"jobs\": [\n {\n \"jobKey\": \"run_content_sprint\",\n \"displayName\": \"Run content sprint\",\n \"description\": \"Generates a sample batch using placeholder product input (for demos and smoke tests).\",\n \"schedule\": \"0 9 * * 1\"\n }\n ],\n \"ui\": {\n \"slots\": [\n {\n \"type\": \"globalToolbarButton\",\n \"id\": \"content-sprint-toolbar\",\n \"displayName\": \"Content Sprint\",\n \"exportName\": \"ToolbarButton\"\n },\n {\n \"type\": \"dashboardWidget\",\n \"id\": \"content-sprint-dashboard\",\n \"displayName\": \"Content Sprint AI\",\n \"exportName\": \"ContentSprintPanel\"\n }\n ]\n }\n}\n", "import type { PaperclipPluginManifestV1 } from \"@paperclipai/shared\";\nimport manifestJson from \"../plugin.json\" with { type: \"json\" };\n\nconst manifest = manifestJson as PaperclipPluginManifestV1;\n\nexport default manifest;\n"],
|
|
5
5
|
"mappings": ";AAAA;AAAA,EACE,IAAM;AAAA,EACN,YAAc;AAAA,EACd,SAAW;AAAA,EACX,aAAe;AAAA,EACf,aAAe;AAAA,EACf,QAAU;AAAA,EACV,YAAc,CAAC,cAAc,IAAI;AAAA,EACjC,cAAgB;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAe;AAAA,IACb,QAAU;AAAA,IACV,IAAM;AAAA,EACR;AAAA,EACA,OAAS;AAAA,IACP;AAAA,MACE,MAAQ;AAAA,MACR,aAAe;AAAA,MACf,aAAe;AAAA,MACf,kBAAoB;AAAA,QAClB,MAAQ;AAAA,QACR,YAAc;AAAA,UACZ,aAAe,EAAE,MAAQ,UAAU,aAAe,wBAAwB;AAAA,UAC1E,oBAAsB,EAAE,MAAQ,UAAU,aAAe,2CAA2C;AAAA,UACpG,gBAAkB,EAAE,MAAQ,UAAU,aAAe,0BAA0B;AAAA,UAC/E,UAAY;AAAA,YACV,MAAQ;AAAA,YACR,MAAQ,CAAC,YAAY,SAAS;AAAA,YAC9B,aAAe;AAAA,UACjB;AAAA,QACF;AAAA,QACA,UAAY,CAAC,eAAe,sBAAsB,kBAAkB,UAAU;AAAA,MAChF;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAQ;AAAA,IACN;AAAA,MACE,QAAU;AAAA,MACV,aAAe;AAAA,MACf,aAAe;AAAA,MACf,UAAY;AAAA,IACd;AAAA,EACF;AAAA,EACA,IAAM;AAAA,IACJ,OAAS;AAAA,MACP;AAAA,QACE,MAAQ;AAAA,QACR,IAAM;AAAA,QACN,aAAe;AAAA,QACf,YAAc;AAAA,MAChB;AAAA,MACA;AAAA,QACE,MAAQ;AAAA,QACR,IAAM;AAAA,QACN,aAAe;AAAA,QACf,YAAc;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AACF;;;AC5DA,IAAM,WAAW;AAEjB,IAAO,mBAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/ui/index.js
CHANGED
|
@@ -1,9 +1,41 @@
|
|
|
1
1
|
// src/ui/ToolbarButton.tsx
|
|
2
|
-
import { useCallback, useState } from "react";
|
|
2
|
+
import { useCallback, useId, useState } from "react";
|
|
3
3
|
import { usePluginAction } from "@paperclipai/plugin-sdk/ui";
|
|
4
|
+
|
|
5
|
+
// src/ui/formFieldStyles.ts
|
|
6
|
+
var sprintFieldStyle = {
|
|
7
|
+
padding: "8px 10px",
|
|
8
|
+
borderRadius: 8,
|
|
9
|
+
border: "1px solid #64748b",
|
|
10
|
+
fontSize: "0.88rem",
|
|
11
|
+
color: "#0f172a",
|
|
12
|
+
backgroundColor: "#ffffff"
|
|
13
|
+
};
|
|
14
|
+
var sprintLabelStyle = {
|
|
15
|
+
display: "grid",
|
|
16
|
+
gap: 6,
|
|
17
|
+
fontSize: "0.8125rem",
|
|
18
|
+
fontWeight: 600,
|
|
19
|
+
color: "#0f172a"
|
|
20
|
+
};
|
|
21
|
+
var SPRINT_FORM_PLACEHOLDER_CSS = `
|
|
22
|
+
.pcsprint-input::placeholder,
|
|
23
|
+
.pcsprint-input::-webkit-input-placeholder {
|
|
24
|
+
color: #64748b;
|
|
25
|
+
opacity: 1;
|
|
26
|
+
}
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
// src/ui/ToolbarButton.tsx
|
|
4
30
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
31
|
function ToolbarButton({ context }) {
|
|
6
32
|
const runGenerate = usePluginAction("generate_content_sprint");
|
|
33
|
+
const uid = useId();
|
|
34
|
+
const titleId = `${uid}-dialog-title`;
|
|
35
|
+
const productNameId = `${uid}-product-name`;
|
|
36
|
+
const productDescriptionId = `${uid}-product-description`;
|
|
37
|
+
const targetAudienceId = `${uid}-target-audience`;
|
|
38
|
+
const platformId = `${uid}-platform`;
|
|
7
39
|
const [open, setOpen] = useState(false);
|
|
8
40
|
const [productName, setProductName] = useState("");
|
|
9
41
|
const [productDescription, setProductDescription] = useState("");
|
|
@@ -32,6 +64,7 @@ function ToolbarButton({ context }) {
|
|
|
32
64
|
}
|
|
33
65
|
}, [runGenerate, context.companyId, productName, productDescription, targetAudience, platform]);
|
|
34
66
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
67
|
+
/* @__PURE__ */ jsx("style", { children: SPRINT_FORM_PLACEHOLDER_CSS }),
|
|
35
68
|
/* @__PURE__ */ jsx(
|
|
36
69
|
"button",
|
|
37
70
|
{
|
|
@@ -57,7 +90,7 @@ function ToolbarButton({ context }) {
|
|
|
57
90
|
{
|
|
58
91
|
role: "dialog",
|
|
59
92
|
"aria-modal": "true",
|
|
60
|
-
"aria-
|
|
93
|
+
"aria-labelledby": titleId,
|
|
61
94
|
style: {
|
|
62
95
|
position: "fixed",
|
|
63
96
|
inset: 0,
|
|
@@ -78,66 +111,97 @@ function ToolbarButton({ context }) {
|
|
|
78
111
|
overflow: "auto",
|
|
79
112
|
padding: 20,
|
|
80
113
|
borderRadius: 14,
|
|
81
|
-
background: "#
|
|
114
|
+
background: "#ffffff",
|
|
115
|
+
color: "#0f172a",
|
|
116
|
+
colorScheme: "light",
|
|
82
117
|
boxShadow: "0 20px 50px rgba(0,0,0,0.2)",
|
|
83
118
|
fontFamily: "system-ui, sans-serif"
|
|
84
119
|
},
|
|
85
120
|
onClick: (e) => e.stopPropagation(),
|
|
86
121
|
children: [
|
|
87
|
-
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom:
|
|
88
|
-
/* @__PURE__ */ jsx("h2", { style: { margin: 0, fontSize: "1.
|
|
122
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }, children: [
|
|
123
|
+
/* @__PURE__ */ jsx("h2", { id: titleId, style: { margin: 0, fontSize: "1.125rem", fontWeight: 700, color: "#020617" }, children: "Content Sprint" }),
|
|
89
124
|
/* @__PURE__ */ jsx(
|
|
90
125
|
"button",
|
|
91
126
|
{
|
|
92
127
|
type: "button",
|
|
93
128
|
onClick: () => setOpen(false),
|
|
94
129
|
disabled: loading,
|
|
95
|
-
style: {
|
|
130
|
+
style: {
|
|
131
|
+
border: "none",
|
|
132
|
+
background: "transparent",
|
|
133
|
+
cursor: loading ? "default" : "pointer",
|
|
134
|
+
fontSize: "1.35rem",
|
|
135
|
+
lineHeight: 1,
|
|
136
|
+
color: "#334155",
|
|
137
|
+
padding: "4px 8px"
|
|
138
|
+
},
|
|
96
139
|
"aria-label": "Close",
|
|
97
140
|
children: "\xD7"
|
|
98
141
|
}
|
|
99
142
|
)
|
|
100
143
|
] }),
|
|
101
|
-
/* @__PURE__ */ jsxs("div", { style: { display: "grid", gap:
|
|
102
|
-
/* @__PURE__ */
|
|
103
|
-
"
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
144
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "grid", gap: 14, marginBottom: 14 }, children: [
|
|
145
|
+
/* @__PURE__ */ jsxs("label", { htmlFor: productNameId, style: sprintLabelStyle, children: [
|
|
146
|
+
"Product name",
|
|
147
|
+
/* @__PURE__ */ jsx(
|
|
148
|
+
"input",
|
|
149
|
+
{
|
|
150
|
+
id: productNameId,
|
|
151
|
+
className: "pcsprint-input",
|
|
152
|
+
autoComplete: "off",
|
|
153
|
+
value: productName,
|
|
154
|
+
onChange: (e) => setProductName(e.target.value),
|
|
155
|
+
style: sprintFieldStyle,
|
|
156
|
+
placeholder: "e.g. Northwind CRM"
|
|
157
|
+
}
|
|
158
|
+
)
|
|
159
|
+
] }),
|
|
160
|
+
/* @__PURE__ */ jsxs("label", { htmlFor: productDescriptionId, style: sprintLabelStyle, children: [
|
|
161
|
+
"Product description",
|
|
162
|
+
/* @__PURE__ */ jsx(
|
|
163
|
+
"textarea",
|
|
164
|
+
{
|
|
165
|
+
id: productDescriptionId,
|
|
166
|
+
className: "pcsprint-input",
|
|
167
|
+
value: productDescription,
|
|
168
|
+
onChange: (e) => setProductDescription(e.target.value),
|
|
169
|
+
style: { ...sprintFieldStyle, minHeight: 72, resize: "vertical" },
|
|
170
|
+
placeholder: "What it does and the outcome for customers"
|
|
171
|
+
}
|
|
172
|
+
)
|
|
173
|
+
] }),
|
|
174
|
+
/* @__PURE__ */ jsxs("label", { htmlFor: targetAudienceId, style: sprintLabelStyle, children: [
|
|
175
|
+
"Target audience",
|
|
176
|
+
/* @__PURE__ */ jsx(
|
|
177
|
+
"input",
|
|
178
|
+
{
|
|
179
|
+
id: targetAudienceId,
|
|
180
|
+
className: "pcsprint-input",
|
|
181
|
+
autoComplete: "off",
|
|
182
|
+
value: targetAudience,
|
|
183
|
+
onChange: (e) => setTargetAudience(e.target.value),
|
|
184
|
+
style: sprintFieldStyle,
|
|
185
|
+
placeholder: "e.g. RevOps at Series B SaaS"
|
|
186
|
+
}
|
|
187
|
+
)
|
|
188
|
+
] }),
|
|
189
|
+
/* @__PURE__ */ jsxs("label", { htmlFor: platformId, style: sprintLabelStyle, children: [
|
|
190
|
+
"Platform",
|
|
191
|
+
/* @__PURE__ */ jsxs(
|
|
192
|
+
"select",
|
|
193
|
+
{
|
|
194
|
+
id: platformId,
|
|
195
|
+
value: platform,
|
|
196
|
+
onChange: (e) => setPlatform(e.target.value),
|
|
197
|
+
style: sprintFieldStyle,
|
|
198
|
+
children: [
|
|
199
|
+
/* @__PURE__ */ jsx("option", { value: "linkedin", children: "LinkedIn" }),
|
|
200
|
+
/* @__PURE__ */ jsx("option", { value: "twitter", children: "X (Twitter)" })
|
|
201
|
+
]
|
|
202
|
+
}
|
|
203
|
+
)
|
|
204
|
+
] })
|
|
141
205
|
] }),
|
|
142
206
|
/* @__PURE__ */ jsx(
|
|
143
207
|
"button",
|
|
@@ -151,20 +215,32 @@ function ToolbarButton({ context }) {
|
|
|
151
215
|
borderRadius: 8,
|
|
152
216
|
border: "none",
|
|
153
217
|
fontWeight: 600,
|
|
154
|
-
background: loading ? "#
|
|
155
|
-
color: "#
|
|
218
|
+
background: loading ? "#64748b" : "#0f172a",
|
|
219
|
+
color: "#ffffff",
|
|
156
220
|
cursor: loading ? "wait" : "pointer",
|
|
157
221
|
marginBottom: 12
|
|
158
222
|
},
|
|
159
223
|
children: loading ? "Generating\u2026" : "Generate 5 posts"
|
|
160
224
|
}
|
|
161
225
|
),
|
|
162
|
-
error ? /* @__PURE__ */ jsx("p", { style: { color: "#
|
|
163
|
-
result?.posts?.length ? /* @__PURE__ */ jsx(
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
226
|
+
error ? /* @__PURE__ */ jsx("p", { style: { color: "#b91c1c", fontSize: "0.85rem" }, role: "alert", children: error }) : null,
|
|
227
|
+
result?.posts?.length ? /* @__PURE__ */ jsx(
|
|
228
|
+
"ol",
|
|
229
|
+
{
|
|
230
|
+
style: {
|
|
231
|
+
margin: 0,
|
|
232
|
+
paddingLeft: 20,
|
|
233
|
+
fontSize: "0.82rem",
|
|
234
|
+
lineHeight: 1.45,
|
|
235
|
+
color: "#0f172a"
|
|
236
|
+
},
|
|
237
|
+
children: result.posts.map((p, i) => /* @__PURE__ */ jsxs("li", { style: { marginBottom: 10 }, children: [
|
|
238
|
+
/* @__PURE__ */ jsx("strong", { style: { color: "#020617" }, children: p.type }),
|
|
239
|
+
" \u2014 ",
|
|
240
|
+
p.hook
|
|
241
|
+
] }, i))
|
|
242
|
+
}
|
|
243
|
+
) : null
|
|
168
244
|
]
|
|
169
245
|
}
|
|
170
246
|
)
|
|
@@ -172,19 +248,19 @@ function ToolbarButton({ context }) {
|
|
|
172
248
|
) : null
|
|
173
249
|
] });
|
|
174
250
|
}
|
|
175
|
-
var field = {
|
|
176
|
-
padding: "8px 10px",
|
|
177
|
-
borderRadius: 8,
|
|
178
|
-
border: "1px solid #ccc",
|
|
179
|
-
fontSize: "0.88rem"
|
|
180
|
-
};
|
|
181
251
|
|
|
182
252
|
// src/ui/ContentSprintPanel.tsx
|
|
183
|
-
import { useCallback as useCallback2, useState as useState2 } from "react";
|
|
253
|
+
import { useCallback as useCallback2, useId as useId2, useState as useState2 } from "react";
|
|
184
254
|
import { usePluginAction as usePluginAction2 } from "@paperclipai/plugin-sdk/ui";
|
|
185
255
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
186
256
|
function ContentSprintPanel({ context }) {
|
|
187
257
|
const runGenerate = usePluginAction2("generate_content_sprint");
|
|
258
|
+
const uid = useId2();
|
|
259
|
+
const headingId = `${uid}-heading`;
|
|
260
|
+
const productNameId = `${uid}-product-name`;
|
|
261
|
+
const productDescriptionId = `${uid}-product-description`;
|
|
262
|
+
const targetAudienceId = `${uid}-target-audience`;
|
|
263
|
+
const platformId = `${uid}-platform`;
|
|
188
264
|
const [productName, setProductName] = useState2("");
|
|
189
265
|
const [productDescription, setProductDescription] = useState2("");
|
|
190
266
|
const [targetAudience, setTargetAudience] = useState2("");
|
|
@@ -214,66 +290,79 @@ function ContentSprintPanel({ context }) {
|
|
|
214
290
|
return /* @__PURE__ */ jsxs2(
|
|
215
291
|
"section",
|
|
216
292
|
{
|
|
293
|
+
"aria-labelledby": headingId,
|
|
217
294
|
style: {
|
|
218
295
|
display: "grid",
|
|
219
296
|
gap: 16,
|
|
220
297
|
padding: 16,
|
|
221
298
|
borderRadius: 12,
|
|
222
|
-
border: "1px solid
|
|
223
|
-
background: "
|
|
299
|
+
border: "1px solid #cbd5e1",
|
|
300
|
+
background: "#ffffff",
|
|
301
|
+
color: "#0f172a",
|
|
302
|
+
colorScheme: "light",
|
|
224
303
|
fontFamily: "system-ui, sans-serif",
|
|
225
304
|
maxWidth: 720
|
|
226
305
|
},
|
|
227
306
|
children: [
|
|
307
|
+
/* @__PURE__ */ jsx2("style", { children: SPRINT_FORM_PLACEHOLDER_CSS }),
|
|
228
308
|
/* @__PURE__ */ jsxs2("header", { children: [
|
|
229
|
-
/* @__PURE__ */ jsx2("h2", { style: { margin: 0, fontSize: "1.15rem", fontWeight:
|
|
230
|
-
/* @__PURE__ */ jsx2("p", { style: { margin: "6px 0 0", fontSize: "0.875rem", color: "#
|
|
309
|
+
/* @__PURE__ */ jsx2("h2", { id: headingId, style: { margin: 0, fontSize: "1.15rem", fontWeight: 700, color: "#020617" }, children: "Content Sprint AI" }),
|
|
310
|
+
/* @__PURE__ */ jsx2("p", { style: { margin: "6px 0 0", fontSize: "0.875rem", color: "#334155" }, children: "Five posts: two authority, two engagement, one conversion." })
|
|
231
311
|
] }),
|
|
232
|
-
/* @__PURE__ */ jsxs2("div", { style: { display: "grid", gap:
|
|
233
|
-
/* @__PURE__ */ jsxs2("label", {
|
|
234
|
-
|
|
312
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "grid", gap: 14 }, children: [
|
|
313
|
+
/* @__PURE__ */ jsxs2("label", { htmlFor: productNameId, style: sprintLabelStyle, children: [
|
|
314
|
+
"Product name",
|
|
235
315
|
/* @__PURE__ */ jsx2(
|
|
236
316
|
"input",
|
|
237
317
|
{
|
|
318
|
+
id: productNameId,
|
|
319
|
+
className: "pcsprint-input",
|
|
320
|
+
autoComplete: "off",
|
|
238
321
|
value: productName,
|
|
239
322
|
onChange: (e) => setProductName(e.target.value),
|
|
240
|
-
style:
|
|
323
|
+
style: sprintFieldStyle,
|
|
241
324
|
placeholder: "e.g. Northwind CRM"
|
|
242
325
|
}
|
|
243
326
|
)
|
|
244
327
|
] }),
|
|
245
|
-
/* @__PURE__ */ jsxs2("label", {
|
|
246
|
-
|
|
328
|
+
/* @__PURE__ */ jsxs2("label", { htmlFor: productDescriptionId, style: sprintLabelStyle, children: [
|
|
329
|
+
"Product description",
|
|
247
330
|
/* @__PURE__ */ jsx2(
|
|
248
331
|
"textarea",
|
|
249
332
|
{
|
|
333
|
+
id: productDescriptionId,
|
|
334
|
+
className: "pcsprint-input",
|
|
250
335
|
value: productDescription,
|
|
251
336
|
onChange: (e) => setProductDescription(e.target.value),
|
|
252
|
-
style: { ...
|
|
337
|
+
style: { ...sprintFieldStyle, minHeight: 88, resize: "vertical" },
|
|
253
338
|
placeholder: "What it does and the outcome for customers"
|
|
254
339
|
}
|
|
255
340
|
)
|
|
256
341
|
] }),
|
|
257
|
-
/* @__PURE__ */ jsxs2("label", {
|
|
258
|
-
|
|
342
|
+
/* @__PURE__ */ jsxs2("label", { htmlFor: targetAudienceId, style: sprintLabelStyle, children: [
|
|
343
|
+
"Target audience",
|
|
259
344
|
/* @__PURE__ */ jsx2(
|
|
260
345
|
"input",
|
|
261
346
|
{
|
|
347
|
+
id: targetAudienceId,
|
|
348
|
+
className: "pcsprint-input",
|
|
349
|
+
autoComplete: "off",
|
|
262
350
|
value: targetAudience,
|
|
263
351
|
onChange: (e) => setTargetAudience(e.target.value),
|
|
264
|
-
style:
|
|
352
|
+
style: sprintFieldStyle,
|
|
265
353
|
placeholder: "e.g. Heads of ops at mid-market manufacturers"
|
|
266
354
|
}
|
|
267
355
|
)
|
|
268
356
|
] }),
|
|
269
|
-
/* @__PURE__ */ jsxs2("label", {
|
|
270
|
-
|
|
357
|
+
/* @__PURE__ */ jsxs2("label", { htmlFor: platformId, style: sprintLabelStyle, children: [
|
|
358
|
+
"Platform",
|
|
271
359
|
/* @__PURE__ */ jsxs2(
|
|
272
360
|
"select",
|
|
273
361
|
{
|
|
362
|
+
id: platformId,
|
|
274
363
|
value: platform,
|
|
275
364
|
onChange: (e) => setPlatform(e.target.value),
|
|
276
|
-
style:
|
|
365
|
+
style: sprintFieldStyle,
|
|
277
366
|
children: [
|
|
278
367
|
/* @__PURE__ */ jsx2("option", { value: "linkedin", children: "LinkedIn" }),
|
|
279
368
|
/* @__PURE__ */ jsx2("option", { value: "twitter", children: "X (Twitter)" })
|
|
@@ -295,34 +384,47 @@ function ContentSprintPanel({ context }) {
|
|
|
295
384
|
border: "none",
|
|
296
385
|
fontWeight: 600,
|
|
297
386
|
cursor: loading ? "wait" : "pointer",
|
|
298
|
-
background: loading ? "#
|
|
299
|
-
color: "#
|
|
387
|
+
background: loading ? "#64748b" : "#0f172a",
|
|
388
|
+
color: "#ffffff"
|
|
300
389
|
},
|
|
301
390
|
children: loading ? "Generating\u2026" : "Generate 5 posts"
|
|
302
391
|
}
|
|
303
392
|
),
|
|
304
|
-
context.companyId == null ? /* @__PURE__ */ jsx2("span", { style: { fontSize: "0.8rem", color: "#
|
|
393
|
+
context.companyId == null ? /* @__PURE__ */ jsx2("span", { style: { fontSize: "0.8rem", color: "#b45309" }, children: "Select a company to run actions." }) : null
|
|
305
394
|
] }),
|
|
306
|
-
error ? /* @__PURE__ */ jsx2("p", { style: { margin: 0, color: "#
|
|
395
|
+
error ? /* @__PURE__ */ jsx2("p", { style: { margin: 0, color: "#b91c1c", fontSize: "0.875rem" }, role: "alert", children: error }) : null,
|
|
307
396
|
result?.posts?.length ? /* @__PURE__ */ jsx2("ul", { style: { margin: 0, padding: 0, listStyle: "none", display: "grid", gap: 14 }, children: result.posts.map((post, i) => /* @__PURE__ */ jsxs2(
|
|
308
397
|
"li",
|
|
309
398
|
{
|
|
310
399
|
style: {
|
|
311
400
|
padding: 12,
|
|
312
401
|
borderRadius: 10,
|
|
313
|
-
background: "#
|
|
314
|
-
border: "1px solid
|
|
402
|
+
background: "#f8fafc",
|
|
403
|
+
border: "1px solid #e2e8f0",
|
|
404
|
+
color: "#0f172a"
|
|
315
405
|
},
|
|
316
406
|
children: [
|
|
317
|
-
/* @__PURE__ */ jsx2(
|
|
318
|
-
|
|
407
|
+
/* @__PURE__ */ jsx2(
|
|
408
|
+
"div",
|
|
409
|
+
{
|
|
410
|
+
style: {
|
|
411
|
+
fontSize: "0.72rem",
|
|
412
|
+
textTransform: "uppercase",
|
|
413
|
+
letterSpacing: "0.04em",
|
|
414
|
+
color: "#475569",
|
|
415
|
+
fontWeight: 600
|
|
416
|
+
},
|
|
417
|
+
children: post.type
|
|
418
|
+
}
|
|
419
|
+
),
|
|
420
|
+
/* @__PURE__ */ jsx2("p", { style: { margin: "6px 0", fontWeight: 650, color: "#020617" }, children: post.hook }),
|
|
319
421
|
/* @__PURE__ */ jsx2("p", { style: { margin: "0 0 8px", whiteSpace: "pre-wrap", fontSize: "0.9rem", lineHeight: 1.45 }, children: post.body }),
|
|
320
|
-
/* @__PURE__ */ jsxs2("p", { style: { margin: 0, fontSize: "0.85rem", color: "#
|
|
422
|
+
/* @__PURE__ */ jsxs2("p", { style: { margin: 0, fontSize: "0.85rem", color: "#1e293b" }, children: [
|
|
321
423
|
/* @__PURE__ */ jsx2("strong", { children: "CTA:" }),
|
|
322
424
|
" ",
|
|
323
425
|
post.cta
|
|
324
426
|
] }),
|
|
325
|
-
post.hashtags?.length ? /* @__PURE__ */ jsx2("p", { style: { margin: "8px 0 0", fontSize: "0.8rem", color: "#
|
|
427
|
+
post.hashtags?.length ? /* @__PURE__ */ jsx2("p", { style: { margin: "8px 0 0", fontSize: "0.8rem", color: "#475569" }, children: post.hashtags.map((h) => `#${h}`).join(" ") }) : null
|
|
326
428
|
]
|
|
327
429
|
},
|
|
328
430
|
i
|
|
@@ -331,12 +433,6 @@ function ContentSprintPanel({ context }) {
|
|
|
331
433
|
}
|
|
332
434
|
);
|
|
333
435
|
}
|
|
334
|
-
var inputStyle = {
|
|
335
|
-
padding: "8px 10px",
|
|
336
|
-
borderRadius: 8,
|
|
337
|
-
border: "1px solid #ccc",
|
|
338
|
-
fontSize: "0.9rem"
|
|
339
|
-
};
|
|
340
436
|
export {
|
|
341
437
|
ContentSprintPanel,
|
|
342
438
|
ToolbarButton
|
package/dist/ui/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../src/ui/ToolbarButton.tsx", "../../src/ui/ContentSprintPanel.tsx"],
|
|
4
|
-
"sourcesContent": ["import { useCallback, useState, type CSSProperties } from \"react\";\nimport { usePluginAction, type PluginWidgetProps } from \"@paperclipai/plugin-sdk/ui\";\nimport type { ContentBatchResult } from \"../contentTypes.js\";\n\n/**\n * Global toolbar entry \u2014 opens a compact sprint panel in a host-style overlay.\n */\nexport function ToolbarButton({ context }: PluginWidgetProps) {\n const runGenerate = usePluginAction(\"generate_content_sprint\");\n const [open, setOpen] = useState(false);\n const [productName, setProductName] = useState(\"\");\n const [productDescription, setProductDescription] = useState(\"\");\n const [targetAudience, setTargetAudience] = useState(\"\");\n const [platform, setPlatform] = useState<\"linkedin\" | \"twitter\">(\"linkedin\");\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [result, setResult] = useState<ContentBatchResult | null>(null);\n\n const onGenerate = useCallback(async () => {\n setLoading(true);\n setError(null);\n setResult(null);\n try {\n const data = (await runGenerate({\n companyId: context.companyId,\n productName,\n productDescription,\n targetAudience,\n platform,\n })) as ContentBatchResult;\n setResult(data);\n } catch (e) {\n setError(e instanceof Error ? e.message : \"Generation failed\");\n } finally {\n setLoading(false);\n }\n }, [runGenerate, context.companyId, productName, productDescription, targetAudience, platform]);\n\n return (\n <>\n <button\n type=\"button\"\n onClick={() => setOpen(true)}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 6,\n padding: \"6px 12px\",\n borderRadius: 8,\n border: \"1px solid rgba(0,0,0,0.12)\",\n background: \"#fff\",\n fontWeight: 600,\n fontSize: \"0.85rem\",\n cursor: \"pointer\",\n }}\n >\n \u26A1 Content Sprint\n </button>\n\n {open ? (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Content Sprint\"\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 80,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: 16,\n background: \"rgba(0,0,0,0.35)\",\n }}\n onClick={() => !loading && setOpen(false)}\n >\n <div\n style={{\n width: \"min(560px, 100%)\",\n maxHeight: \"90vh\",\n overflow: \"auto\",\n padding: 20,\n borderRadius: 14,\n background: \"#fff\",\n boxShadow: \"0 20px 50px rgba(0,0,0,0.2)\",\n fontFamily: \"system-ui, sans-serif\",\n }}\n onClick={(e) => e.stopPropagation()}\n >\n <div style={{ display: \"flex\", justifyContent: \"space-between\", alignItems: \"center\", marginBottom: 14 }}>\n <h2 style={{ margin: 0, fontSize: \"1.1rem\" }}>Content Sprint</h2>\n <button\n type=\"button\"\n onClick={() => setOpen(false)}\n disabled={loading}\n style={{ border: \"none\", background: \"transparent\", cursor: \"pointer\", fontSize: \"1.2rem\" }}\n aria-label=\"Close\"\n >\n \u00D7\n </button>\n </div>\n\n <div style={{ display: \"grid\", gap: 10, marginBottom: 12 }}>\n <input\n placeholder=\"Product name\"\n value={productName}\n onChange={(e) => setProductName(e.target.value)}\n style={field}\n />\n <textarea\n placeholder=\"Product description\"\n value={productDescription}\n onChange={(e) => setProductDescription(e.target.value)}\n style={{ ...field, minHeight: 72 }}\n />\n <input\n placeholder=\"Target audience\"\n value={targetAudience}\n onChange={(e) => setTargetAudience(e.target.value)}\n style={field}\n />\n <select\n value={platform}\n onChange={(e) => setPlatform(e.target.value as \"linkedin\" | \"twitter\")}\n style={field}\n >\n <option value=\"linkedin\">LinkedIn</option>\n <option value=\"twitter\">X (Twitter)</option>\n </select>\n </div>\n\n <button\n type=\"button\"\n onClick={() => void onGenerate()}\n disabled={loading}\n style={{\n width: \"100%\",\n padding: \"10px\",\n borderRadius: 8,\n border: \"none\",\n fontWeight: 600,\n background: loading ? \"#999\" : \"#111\",\n color: \"#fff\",\n cursor: loading ? \"wait\" : \"pointer\",\n marginBottom: 12,\n }}\n >\n {loading ? \"Generating\u2026\" : \"Generate 5 posts\"}\n </button>\n\n {error ? (\n <p style={{ color: \"#b00020\", fontSize: \"0.85rem\" }} role=\"alert\">\n {error}\n </p>\n ) : null}\n\n {result?.posts?.length ? (\n <ol style={{ margin: 0, paddingLeft: 18, fontSize: \"0.82rem\", lineHeight: 1.4 }}>\n {result.posts.map((p, i) => (\n <li key={i} style={{ marginBottom: 10 }}>\n <strong>{p.type}</strong> \u2014 {p.hook}\n </li>\n ))}\n </ol>\n ) : null}\n </div>\n </div>\n ) : null}\n </>\n );\n}\n\nconst field: CSSProperties = {\n padding: \"8px 10px\",\n borderRadius: 8,\n border: \"1px solid #ccc\",\n fontSize: \"0.88rem\",\n};\n", "import { useCallback, useState, type CSSProperties } from \"react\";\nimport { usePluginAction, type PluginWidgetProps } from \"@paperclipai/plugin-sdk/ui\";\nimport type { ContentBatchResult } from \"../contentTypes.js\";\n\nexport function ContentSprintPanel({ context }: PluginWidgetProps) {\n const runGenerate = usePluginAction(\"generate_content_sprint\");\n const [productName, setProductName] = useState(\"\");\n const [productDescription, setProductDescription] = useState(\"\");\n const [targetAudience, setTargetAudience] = useState(\"\");\n const [platform, setPlatform] = useState<\"linkedin\" | \"twitter\">(\"linkedin\");\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [result, setResult] = useState<ContentBatchResult | null>(null);\n\n const onGenerate = useCallback(async () => {\n setLoading(true);\n setError(null);\n setResult(null);\n try {\n const data = (await runGenerate({\n companyId: context.companyId,\n productName,\n productDescription,\n targetAudience,\n platform,\n })) as ContentBatchResult;\n setResult(data);\n } catch (e) {\n setError(e instanceof Error ? e.message : \"Generation failed\");\n } finally {\n setLoading(false);\n }\n }, [runGenerate, context.companyId, productName, productDescription, targetAudience, platform]);\n\n return (\n <section\n style={{\n display: \"grid\",\n gap: 16,\n padding: 16,\n borderRadius: 12,\n border: \"1px solid rgba(0,0,0,0.08)\",\n background: \"linear-gradient(165deg, #fafafa 0%, #fff 45%)\",\n fontFamily: \"system-ui, sans-serif\",\n maxWidth: 720,\n }}\n >\n <header>\n <h2 style={{ margin: 0, fontSize: \"1.15rem\", fontWeight: 650 }}>Content Sprint AI</h2>\n <p style={{ margin: \"6px 0 0\", fontSize: \"0.875rem\", color: \"#444\" }}>\n Five posts: two authority, two engagement, one conversion.\n </p>\n </header>\n\n <div style={{ display: \"grid\", gap: 10 }}>\n <label style={{ display: \"grid\", gap: 4, fontSize: \"0.8rem\" }}>\n <span style={{ fontWeight: 600 }}>Product name</span>\n <input\n value={productName}\n onChange={(e) => setProductName(e.target.value)}\n style={inputStyle}\n placeholder=\"e.g. Northwind CRM\"\n />\n </label>\n <label style={{ display: \"grid\", gap: 4, fontSize: \"0.8rem\" }}>\n <span style={{ fontWeight: 600 }}>Product description</span>\n <textarea\n value={productDescription}\n onChange={(e) => setProductDescription(e.target.value)}\n style={{ ...inputStyle, minHeight: 88, resize: \"vertical\" }}\n placeholder=\"What it does and the outcome for customers\"\n />\n </label>\n <label style={{ display: \"grid\", gap: 4, fontSize: \"0.8rem\" }}>\n <span style={{ fontWeight: 600 }}>Target audience</span>\n <input\n value={targetAudience}\n onChange={(e) => setTargetAudience(e.target.value)}\n style={inputStyle}\n placeholder=\"e.g. Heads of ops at mid-market manufacturers\"\n />\n </label>\n <label style={{ display: \"grid\", gap: 4, fontSize: \"0.8rem\" }}>\n <span style={{ fontWeight: 600 }}>Platform</span>\n <select\n value={platform}\n onChange={(e) => setPlatform(e.target.value as \"linkedin\" | \"twitter\")}\n style={inputStyle}\n >\n <option value=\"linkedin\">LinkedIn</option>\n <option value=\"twitter\">X (Twitter)</option>\n </select>\n </label>\n </div>\n\n <div style={{ display: \"flex\", gap: 10, alignItems: \"center\" }}>\n <button\n type=\"button\"\n onClick={() => void onGenerate()}\n disabled={loading}\n style={{\n padding: \"10px 18px\",\n borderRadius: 8,\n border: \"none\",\n fontWeight: 600,\n cursor: loading ? \"wait\" : \"pointer\",\n background: loading ? \"#bbb\" : \"#111\",\n color: \"#fff\",\n }}\n >\n {loading ? \"Generating\u2026\" : \"Generate 5 posts\"}\n </button>\n {context.companyId == null ? (\n <span style={{ fontSize: \"0.8rem\", color: \"#a40\" }}>Select a company to run actions.</span>\n ) : null}\n </div>\n\n {error ? (\n <p style={{ margin: 0, color: \"#b00020\", fontSize: \"0.875rem\" }} role=\"alert\">\n {error}\n </p>\n ) : null}\n\n {result?.posts?.length ? (\n <ul style={{ margin: 0, padding: 0, listStyle: \"none\", display: \"grid\", gap: 14 }}>\n {result.posts.map((post, i) => (\n <li\n key={i}\n style={{\n padding: 12,\n borderRadius: 10,\n background: \"#fff\",\n border: \"1px solid rgba(0,0,0,0.06)\",\n }}\n >\n <div style={{ fontSize: \"0.72rem\", textTransform: \"uppercase\", letterSpacing: \"0.04em\", color: \"#666\" }}>\n {post.type}\n </div>\n <p style={{ margin: \"6px 0\", fontWeight: 650 }}>{post.hook}</p>\n <p style={{ margin: \"0 0 8px\", whiteSpace: \"pre-wrap\", fontSize: \"0.9rem\", lineHeight: 1.45 }}>\n {post.body}\n </p>\n <p style={{ margin: 0, fontSize: \"0.85rem\", color: \"#333\" }}>\n <strong>CTA:</strong> {post.cta}\n </p>\n {post.hashtags?.length ? (\n <p style={{ margin: \"8px 0 0\", fontSize: \"0.8rem\", color: \"#555\" }}>\n {post.hashtags.map((h) => `#${h}`).join(\" \")}\n </p>\n ) : null}\n </li>\n ))}\n </ul>\n ) : null}\n </section>\n );\n}\n\nconst inputStyle: CSSProperties = {\n padding: \"8px 10px\",\n borderRadius: 8,\n border: \"1px solid #ccc\",\n fontSize: \"0.9rem\",\n};\n"],
|
|
5
|
-
"mappings": ";AAAA,SAAS,aAAa,
|
|
6
|
-
"names": ["useCallback", "useState", "usePluginAction", "jsx", "jsxs"]
|
|
3
|
+
"sources": ["../../src/ui/ToolbarButton.tsx", "../../src/ui/formFieldStyles.ts", "../../src/ui/ContentSprintPanel.tsx"],
|
|
4
|
+
"sourcesContent": ["import { useCallback, useId, useState } from \"react\";\nimport { usePluginAction, type PluginWidgetProps } from \"@paperclipai/plugin-sdk/ui\";\nimport type { ContentBatchResult } from \"../contentTypes.js\";\nimport { SPRINT_FORM_PLACEHOLDER_CSS, sprintFieldStyle, sprintLabelStyle } from \"./formFieldStyles.js\";\n\n/**\n * Global toolbar entry \u2014 opens a compact sprint panel in a host-style overlay.\n */\nexport function ToolbarButton({ context }: PluginWidgetProps) {\n const runGenerate = usePluginAction(\"generate_content_sprint\");\n const uid = useId();\n const titleId = `${uid}-dialog-title`;\n const productNameId = `${uid}-product-name`;\n const productDescriptionId = `${uid}-product-description`;\n const targetAudienceId = `${uid}-target-audience`;\n const platformId = `${uid}-platform`;\n\n const [open, setOpen] = useState(false);\n const [productName, setProductName] = useState(\"\");\n const [productDescription, setProductDescription] = useState(\"\");\n const [targetAudience, setTargetAudience] = useState(\"\");\n const [platform, setPlatform] = useState<\"linkedin\" | \"twitter\">(\"linkedin\");\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [result, setResult] = useState<ContentBatchResult | null>(null);\n\n const onGenerate = useCallback(async () => {\n setLoading(true);\n setError(null);\n setResult(null);\n try {\n const data = (await runGenerate({\n companyId: context.companyId,\n productName,\n productDescription,\n targetAudience,\n platform,\n })) as ContentBatchResult;\n setResult(data);\n } catch (e) {\n setError(e instanceof Error ? e.message : \"Generation failed\");\n } finally {\n setLoading(false);\n }\n }, [runGenerate, context.companyId, productName, productDescription, targetAudience, platform]);\n\n return (\n <>\n <style>{SPRINT_FORM_PLACEHOLDER_CSS}</style>\n <button\n type=\"button\"\n onClick={() => setOpen(true)}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 6,\n padding: \"6px 12px\",\n borderRadius: 8,\n border: \"1px solid rgba(0,0,0,0.12)\",\n background: \"#fff\",\n fontWeight: 600,\n fontSize: \"0.85rem\",\n cursor: \"pointer\",\n }}\n >\n \u26A1 Content Sprint\n </button>\n\n {open ? (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 80,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: 16,\n background: \"rgba(0,0,0,0.35)\",\n }}\n onClick={() => !loading && setOpen(false)}\n >\n <div\n style={{\n width: \"min(560px, 100%)\",\n maxHeight: \"90vh\",\n overflow: \"auto\",\n padding: 20,\n borderRadius: 14,\n background: \"#ffffff\",\n color: \"#0f172a\",\n colorScheme: \"light\",\n boxShadow: \"0 20px 50px rgba(0,0,0,0.2)\",\n fontFamily: \"system-ui, sans-serif\",\n }}\n onClick={(e) => e.stopPropagation()}\n >\n <div style={{ display: \"flex\", justifyContent: \"space-between\", alignItems: \"center\", marginBottom: 16 }}>\n <h2 id={titleId} style={{ margin: 0, fontSize: \"1.125rem\", fontWeight: 700, color: \"#020617\" }}>\n Content Sprint\n </h2>\n <button\n type=\"button\"\n onClick={() => setOpen(false)}\n disabled={loading}\n style={{\n border: \"none\",\n background: \"transparent\",\n cursor: loading ? \"default\" : \"pointer\",\n fontSize: \"1.35rem\",\n lineHeight: 1,\n color: \"#334155\",\n padding: \"4px 8px\",\n }}\n aria-label=\"Close\"\n >\n \u00D7\n </button>\n </div>\n\n <div style={{ display: \"grid\", gap: 14, marginBottom: 14 }}>\n <label htmlFor={productNameId} style={sprintLabelStyle}>\n Product name\n <input\n id={productNameId}\n className=\"pcsprint-input\"\n autoComplete=\"off\"\n value={productName}\n onChange={(e) => setProductName(e.target.value)}\n style={sprintFieldStyle}\n placeholder=\"e.g. Northwind CRM\"\n />\n </label>\n <label htmlFor={productDescriptionId} style={sprintLabelStyle}>\n Product description\n <textarea\n id={productDescriptionId}\n className=\"pcsprint-input\"\n value={productDescription}\n onChange={(e) => setProductDescription(e.target.value)}\n style={{ ...sprintFieldStyle, minHeight: 72, resize: \"vertical\" }}\n placeholder=\"What it does and the outcome for customers\"\n />\n </label>\n <label htmlFor={targetAudienceId} style={sprintLabelStyle}>\n Target audience\n <input\n id={targetAudienceId}\n className=\"pcsprint-input\"\n autoComplete=\"off\"\n value={targetAudience}\n onChange={(e) => setTargetAudience(e.target.value)}\n style={sprintFieldStyle}\n placeholder=\"e.g. RevOps at Series B SaaS\"\n />\n </label>\n <label htmlFor={platformId} style={sprintLabelStyle}>\n Platform\n <select\n id={platformId}\n value={platform}\n onChange={(e) => setPlatform(e.target.value as \"linkedin\" | \"twitter\")}\n style={sprintFieldStyle}\n >\n <option value=\"linkedin\">LinkedIn</option>\n <option value=\"twitter\">X (Twitter)</option>\n </select>\n </label>\n </div>\n\n <button\n type=\"button\"\n onClick={() => void onGenerate()}\n disabled={loading}\n style={{\n width: \"100%\",\n padding: \"10px\",\n borderRadius: 8,\n border: \"none\",\n fontWeight: 600,\n background: loading ? \"#64748b\" : \"#0f172a\",\n color: \"#ffffff\",\n cursor: loading ? \"wait\" : \"pointer\",\n marginBottom: 12,\n }}\n >\n {loading ? \"Generating\u2026\" : \"Generate 5 posts\"}\n </button>\n\n {error ? (\n <p style={{ color: \"#b91c1c\", fontSize: \"0.85rem\" }} role=\"alert\">\n {error}\n </p>\n ) : null}\n\n {result?.posts?.length ? (\n <ol\n style={{\n margin: 0,\n paddingLeft: 20,\n fontSize: \"0.82rem\",\n lineHeight: 1.45,\n color: \"#0f172a\",\n }}\n >\n {result.posts.map((p, i) => (\n <li key={i} style={{ marginBottom: 10 }}>\n <strong style={{ color: \"#020617\" }}>{p.type}</strong> \u2014 {p.hook}\n </li>\n ))}\n </ol>\n ) : null}\n </div>\n </div>\n ) : null}\n </>\n );\n}\n", "import type { CSSProperties } from \"react\";\n\n/** Shared form control styles: explicit light-theme colors so dark host CSS does not wash out text. */\nexport const sprintFieldStyle: CSSProperties = {\n padding: \"8px 10px\",\n borderRadius: 8,\n border: \"1px solid #64748b\",\n fontSize: \"0.88rem\",\n color: \"#0f172a\",\n backgroundColor: \"#ffffff\",\n};\n\nexport const sprintLabelStyle: CSSProperties = {\n display: \"grid\",\n gap: 6,\n fontSize: \"0.8125rem\",\n fontWeight: 600,\n color: \"#0f172a\",\n};\n\n/** Injected once: placeholder contrast on white fields (inline styles cannot target ::placeholder). */\nexport const SPRINT_FORM_PLACEHOLDER_CSS = `\n.pcsprint-input::placeholder,\n.pcsprint-input::-webkit-input-placeholder {\n color: #64748b;\n opacity: 1;\n}\n`;\n", "import { useCallback, useId, useState } from \"react\";\nimport { usePluginAction, type PluginWidgetProps } from \"@paperclipai/plugin-sdk/ui\";\nimport type { ContentBatchResult } from \"../contentTypes.js\";\nimport { SPRINT_FORM_PLACEHOLDER_CSS, sprintFieldStyle, sprintLabelStyle } from \"./formFieldStyles.js\";\n\nexport function ContentSprintPanel({ context }: PluginWidgetProps) {\n const runGenerate = usePluginAction(\"generate_content_sprint\");\n const uid = useId();\n const headingId = `${uid}-heading`;\n const productNameId = `${uid}-product-name`;\n const productDescriptionId = `${uid}-product-description`;\n const targetAudienceId = `${uid}-target-audience`;\n const platformId = `${uid}-platform`;\n\n const [productName, setProductName] = useState(\"\");\n const [productDescription, setProductDescription] = useState(\"\");\n const [targetAudience, setTargetAudience] = useState(\"\");\n const [platform, setPlatform] = useState<\"linkedin\" | \"twitter\">(\"linkedin\");\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [result, setResult] = useState<ContentBatchResult | null>(null);\n\n const onGenerate = useCallback(async () => {\n setLoading(true);\n setError(null);\n setResult(null);\n try {\n const data = (await runGenerate({\n companyId: context.companyId,\n productName,\n productDescription,\n targetAudience,\n platform,\n })) as ContentBatchResult;\n setResult(data);\n } catch (e) {\n setError(e instanceof Error ? e.message : \"Generation failed\");\n } finally {\n setLoading(false);\n }\n }, [runGenerate, context.companyId, productName, productDescription, targetAudience, platform]);\n\n return (\n <section\n aria-labelledby={headingId}\n style={{\n display: \"grid\",\n gap: 16,\n padding: 16,\n borderRadius: 12,\n border: \"1px solid #cbd5e1\",\n background: \"#ffffff\",\n color: \"#0f172a\",\n colorScheme: \"light\",\n fontFamily: \"system-ui, sans-serif\",\n maxWidth: 720,\n }}\n >\n <style>{SPRINT_FORM_PLACEHOLDER_CSS}</style>\n <header>\n <h2 id={headingId} style={{ margin: 0, fontSize: \"1.15rem\", fontWeight: 700, color: \"#020617\" }}>\n Content Sprint AI\n </h2>\n <p style={{ margin: \"6px 0 0\", fontSize: \"0.875rem\", color: \"#334155\" }}>\n Five posts: two authority, two engagement, one conversion.\n </p>\n </header>\n\n <div style={{ display: \"grid\", gap: 14 }}>\n <label htmlFor={productNameId} style={sprintLabelStyle}>\n Product name\n <input\n id={productNameId}\n className=\"pcsprint-input\"\n autoComplete=\"off\"\n value={productName}\n onChange={(e) => setProductName(e.target.value)}\n style={sprintFieldStyle}\n placeholder=\"e.g. Northwind CRM\"\n />\n </label>\n <label htmlFor={productDescriptionId} style={sprintLabelStyle}>\n Product description\n <textarea\n id={productDescriptionId}\n className=\"pcsprint-input\"\n value={productDescription}\n onChange={(e) => setProductDescription(e.target.value)}\n style={{ ...sprintFieldStyle, minHeight: 88, resize: \"vertical\" }}\n placeholder=\"What it does and the outcome for customers\"\n />\n </label>\n <label htmlFor={targetAudienceId} style={sprintLabelStyle}>\n Target audience\n <input\n id={targetAudienceId}\n className=\"pcsprint-input\"\n autoComplete=\"off\"\n value={targetAudience}\n onChange={(e) => setTargetAudience(e.target.value)}\n style={sprintFieldStyle}\n placeholder=\"e.g. Heads of ops at mid-market manufacturers\"\n />\n </label>\n <label htmlFor={platformId} style={sprintLabelStyle}>\n Platform\n <select\n id={platformId}\n value={platform}\n onChange={(e) => setPlatform(e.target.value as \"linkedin\" | \"twitter\")}\n style={sprintFieldStyle}\n >\n <option value=\"linkedin\">LinkedIn</option>\n <option value=\"twitter\">X (Twitter)</option>\n </select>\n </label>\n </div>\n\n <div style={{ display: \"flex\", gap: 10, alignItems: \"center\" }}>\n <button\n type=\"button\"\n onClick={() => void onGenerate()}\n disabled={loading}\n style={{\n padding: \"10px 18px\",\n borderRadius: 8,\n border: \"none\",\n fontWeight: 600,\n cursor: loading ? \"wait\" : \"pointer\",\n background: loading ? \"#64748b\" : \"#0f172a\",\n color: \"#ffffff\",\n }}\n >\n {loading ? \"Generating\u2026\" : \"Generate 5 posts\"}\n </button>\n {context.companyId == null ? (\n <span style={{ fontSize: \"0.8rem\", color: \"#b45309\" }}>Select a company to run actions.</span>\n ) : null}\n </div>\n\n {error ? (\n <p style={{ margin: 0, color: \"#b91c1c\", fontSize: \"0.875rem\" }} role=\"alert\">\n {error}\n </p>\n ) : null}\n\n {result?.posts?.length ? (\n <ul style={{ margin: 0, padding: 0, listStyle: \"none\", display: \"grid\", gap: 14 }}>\n {result.posts.map((post, i) => (\n <li\n key={i}\n style={{\n padding: 12,\n borderRadius: 10,\n background: \"#f8fafc\",\n border: \"1px solid #e2e8f0\",\n color: \"#0f172a\",\n }}\n >\n <div\n style={{\n fontSize: \"0.72rem\",\n textTransform: \"uppercase\",\n letterSpacing: \"0.04em\",\n color: \"#475569\",\n fontWeight: 600,\n }}\n >\n {post.type}\n </div>\n <p style={{ margin: \"6px 0\", fontWeight: 650, color: \"#020617\" }}>{post.hook}</p>\n <p style={{ margin: \"0 0 8px\", whiteSpace: \"pre-wrap\", fontSize: \"0.9rem\", lineHeight: 1.45 }}>\n {post.body}\n </p>\n <p style={{ margin: 0, fontSize: \"0.85rem\", color: \"#1e293b\" }}>\n <strong>CTA:</strong> {post.cta}\n </p>\n {post.hashtags?.length ? (\n <p style={{ margin: \"8px 0 0\", fontSize: \"0.8rem\", color: \"#475569\" }}>\n {post.hashtags.map((h) => `#${h}`).join(\" \")}\n </p>\n ) : null}\n </li>\n ))}\n </ul>\n ) : null}\n </section>\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["useCallback", "useId", "useState", "usePluginAction", "jsx", "jsxs", "usePluginAction", "useId", "useState", "useCallback"]
|
|
7
7
|
}
|
package/package.json
CHANGED
package/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "marsbdigital.paperclip-content-sprint-plugin",
|
|
3
3
|
"apiVersion": 1,
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.3",
|
|
5
5
|
"displayName": "Content Sprint AI",
|
|
6
6
|
"description": "Generate five structured social posts (authority, engagement, conversion) from product context for LinkedIn or X.",
|
|
7
7
|
"author": "Mars B Digital",
|