@mevdragon/vidfarm-devcli 0.16.0 → 0.17.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/.agents/skills/farmville-saas-ux/SKILL.md +156 -0
- package/.agents/skills/farmville-saas-ux/assets/starter.html +294 -0
- package/.agents/skills/farmville-saas-ux/references/components.md +340 -0
- package/.agents/skills/farmville-saas-ux/references/porting-guide.md +121 -0
- package/.agents/skills/farmville-saas-ux/references/tokens.md +271 -0
- package/.agents/skills/vidfarm-media/SKILL.md +2 -1
- package/.agents/skills/vidfarm-media/references/tts.md +20 -1
- package/dist/src/account-pages-legacy.js +2 -2
- package/dist/src/app.js +441 -77
- package/dist/src/editor-chat.js +2 -2
- package/dist/src/frontend/homepage-client.js +162 -2
- package/dist/src/frontend/homepage-store.js +30 -1
- package/dist/src/frontend/homepage-view.js +111 -4
- package/dist/src/homepage.js +184 -1
- package/dist/src/landing-page.js +367 -0
- package/dist/src/primitive-registry.js +278 -2
- package/dist/src/reskin/agency-page.js +255 -0
- package/dist/src/reskin/calendar-page.js +252 -0
- package/dist/src/reskin/chat-page.js +414 -0
- package/dist/src/reskin/discover-page.js +380 -0
- package/dist/src/reskin/document.js +74 -0
- package/dist/src/reskin/help-page.js +318 -0
- package/dist/src/reskin/index-page.js +62 -0
- package/dist/src/reskin/job-runs-page.js +249 -0
- package/dist/src/reskin/library-page.js +515 -0
- package/dist/src/reskin/login-page.js +225 -0
- package/dist/src/reskin/pricing-page.js +359 -0
- package/dist/src/reskin/settings-page.js +353 -0
- package/dist/src/reskin/theme.js +265 -0
- package/dist/src/services/serverless-records.js +54 -0
- package/dist/src/services/swipe-customize.js +434 -0
- package/package.json +1 -1
- package/public/assets/homepage-client-app.js +22 -22
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
// /reskin/chat — the AI brainstorm chat, ported into the farmville design
|
|
2
|
+
// system as a CLEAN, CALM single-column conversation.
|
|
3
|
+
//
|
|
4
|
+
// The reskin app now has its own fixed LEFT sidebar nav (rendered by
|
|
5
|
+
// reskinDocument, chrome:"full"), so this page NO LONGER carries its own
|
|
6
|
+
// history sidebar or right-hand context panel — those were redundant and busy.
|
|
7
|
+
// Instead: one centered reading column (~800px) with a compact header, an
|
|
8
|
+
// alternating message thread (ink user bubbles + soft white assistant cards),
|
|
9
|
+
// a few starter chips, and a quiet sticky composer.
|
|
10
|
+
//
|
|
11
|
+
// Rich but restrained: a couple of short paragraphs, ONE bulleted hook list,
|
|
12
|
+
// and AT MOST ONE generated-template card with Open/Fork. Gold is used sparingly
|
|
13
|
+
// (Send button + a couple of small accents). Built with ONLY shared rk-*
|
|
14
|
+
// primitives + a page-scoped rk-chat- block + a small self-contained script.
|
|
15
|
+
// No app.ts imports; pure string → reskinDocument(...).
|
|
16
|
+
import { reskinDocument, rkEscape } from "./document.js";
|
|
17
|
+
// ── icons ───────────────────────────────────────────────────────────────────
|
|
18
|
+
const SEND = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 12l16-8-6 16-2.5-6.5L4 12Z"/></svg>`;
|
|
19
|
+
const CLIP = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 11.5l-8.4 8.4a5 5 0 0 1-7.1-7.1l8.5-8.5a3.3 3.3 0 0 1 4.7 4.7l-8.5 8.5a1.7 1.7 0 0 1-2.4-2.4l7.8-7.8"/></svg>`;
|
|
20
|
+
function p(html) {
|
|
21
|
+
return `<p class="rk-chat-p">${html}</p>`;
|
|
22
|
+
}
|
|
23
|
+
function hookList(items) {
|
|
24
|
+
return `<div class="rk-chat-hooks">${items
|
|
25
|
+
.map((h) => `<div class="rk-chat-hook">
|
|
26
|
+
<span class="rk-chat-hook-dot" aria-hidden="true"></span>
|
|
27
|
+
<span class="rk-chat-hook-text"><strong>${rkEscape(h.angle)}</strong> — “${rkEscape(h.text)}”</span>
|
|
28
|
+
</div>`)
|
|
29
|
+
.join("")}</div>`;
|
|
30
|
+
}
|
|
31
|
+
function note(label, text) {
|
|
32
|
+
return `<p class="rk-chat-note"><strong>${rkEscape(label)}</strong> ${rkEscape(text)}</p>`;
|
|
33
|
+
}
|
|
34
|
+
function artifact(a) {
|
|
35
|
+
return `<div class="rk-chat-art">
|
|
36
|
+
<div class="rk-chat-poster">
|
|
37
|
+
<span class="rk-chat-poster-dur">${rkEscape(a.dur)}</span>
|
|
38
|
+
<span class="rk-chat-poster-play" aria-hidden="true">▶</span>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="rk-chat-art-main">
|
|
41
|
+
<span class="rk-chat-art-eyebrow">${rkEscape(a.eyebrow)}</span>
|
|
42
|
+
<h4 class="rk-chat-art-title">${rkEscape(a.title)}</h4>
|
|
43
|
+
<p class="rk-chat-art-meta">${rkEscape(a.meta)}</p>
|
|
44
|
+
<p class="rk-chat-art-desc">${rkEscape(a.desc)}</p>
|
|
45
|
+
<div class="rk-chat-art-actions">
|
|
46
|
+
<button type="button" class="rk-btn rk-btn-ink rk-btn-sm">Open in editor <span class="rk-arrow">→</span></button>
|
|
47
|
+
<button type="button" class="rk-btn rk-btn-ghost rk-btn-sm">Fork</button>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</div>`;
|
|
51
|
+
}
|
|
52
|
+
const SAMPLE = [
|
|
53
|
+
{
|
|
54
|
+
role: "user",
|
|
55
|
+
time: "9:41 AM",
|
|
56
|
+
text: "I'm launching a $39 magnesium sleep gummy for stressed founders. Give me short-form ideas that'll convert cold TikTok traffic — I keep drawing a blank."
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
role: "assistant",
|
|
60
|
+
time: "9:41 AM",
|
|
61
|
+
body: p("Great starting point — a founder audience plus a sleep product is a hook goldmine. Here are the three angles I'd test first, each pulling a different psychological lever:") +
|
|
62
|
+
hookList([
|
|
63
|
+
{ angle: "Problem-aware", text: "POV: it's 2am and your brain won't stop pitching investors." },
|
|
64
|
+
{ angle: "Contrarian", text: "Melatonin is why you wake up groggy. Here's what founders take instead." },
|
|
65
|
+
{ angle: "Demo", text: "I swapped my nightcap for one gummy for 14 nights. Night 12 broke me." }
|
|
66
|
+
]) +
|
|
67
|
+
note("Format —", "talking-head UGC, 22–28s, hard cut every ~2s. Shoot vertical in natural light and read it like a voice memo, not an ad.")
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
role: "user",
|
|
71
|
+
time: "9:43 AM",
|
|
72
|
+
text: "The '2am' one is 🔥. Turn it into a full UGC ad script and spin up a template I can hand to a creator."
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
role: "assistant",
|
|
76
|
+
time: "9:43 AM",
|
|
77
|
+
body: p("Here's that hook as a ready-to-shoot 24-second cut — the emotional turn lands right before the CTA:") +
|
|
78
|
+
artifact({
|
|
79
|
+
dur: "0:24",
|
|
80
|
+
eyebrow: "Proposed template",
|
|
81
|
+
title: "The 2am Founder — UGC cut",
|
|
82
|
+
meta: "9:16 · 24s · Talking-head · word-by-word captions",
|
|
83
|
+
desc: "Wired to your hook and a five-beat script, with captions timed to the read. Fork it to swap the shot list or recut for a specific creator."
|
|
84
|
+
}) +
|
|
85
|
+
p("Want me to draft the on-screen captions and lock a trending sound? Say the word and I'll build the shot list.")
|
|
86
|
+
}
|
|
87
|
+
];
|
|
88
|
+
const STARTERS = [
|
|
89
|
+
{ label: "Pitch 5 hooks" },
|
|
90
|
+
{ label: "Turn this into a UGC ad" },
|
|
91
|
+
{ label: "Remix a trending format" },
|
|
92
|
+
{ label: "Write scroll-stopping captions" }
|
|
93
|
+
];
|
|
94
|
+
// recent brainstorms — surfaced only in the unobtrusive "History" menu now that
|
|
95
|
+
// the standing history sidebar is gone.
|
|
96
|
+
const RECENTS = [
|
|
97
|
+
{ title: "Magnesium sleep gummy — cold TikTok", when: "2m", active: true },
|
|
98
|
+
{ title: "Founder productivity app — launch week", when: "1h" },
|
|
99
|
+
{ title: "Skincare serum — before/after", when: "Yesterday" },
|
|
100
|
+
{ title: "AI notetaker — demo cuts", when: "Mon" }
|
|
101
|
+
];
|
|
102
|
+
// ── render ───────────────────────────────────────────────────────────────────
|
|
103
|
+
function renderMessage(m) {
|
|
104
|
+
if (m.role === "user") {
|
|
105
|
+
return `<div class="rk-chat-msg is-user">
|
|
106
|
+
<div class="rk-chat-meta">You <span class="rk-chat-time">${rkEscape(m.time)}</span></div>
|
|
107
|
+
<div class="rk-chat-bubble rk-chat-bubble-user">${rkEscape(m.text)}</div>
|
|
108
|
+
</div>`;
|
|
109
|
+
}
|
|
110
|
+
return `<div class="rk-chat-msg is-assistant">
|
|
111
|
+
<div class="rk-chat-meta"><span class="rk-chat-avatar" aria-hidden="true">V</span>Copilot <span class="rk-chat-time">${rkEscape(m.time)}</span></div>
|
|
112
|
+
<div class="rk-chat-bubble rk-chat-bubble-assistant">${m.body}</div>
|
|
113
|
+
</div>`;
|
|
114
|
+
}
|
|
115
|
+
export function renderReskinChat() {
|
|
116
|
+
const thread = SAMPLE.map(renderMessage).join("");
|
|
117
|
+
const starterChips = STARTERS.map((s) => `<button type="button" class="rk-chat-chip" data-rk-prompt="${rkEscape(s.label)}">${rkEscape(s.label)}</button>`).join("");
|
|
118
|
+
const historyItems = RECENTS.map((r) => `<button type="button" class="rk-chat-hist-item${r.active ? " is-active" : ""}" data-rk-title="${rkEscape(r.title)}">
|
|
119
|
+
<span class="rk-chat-hist-title">${rkEscape(r.title)}</span>
|
|
120
|
+
<span class="rk-chat-hist-when">${rkEscape(r.when)}</span>
|
|
121
|
+
</button>`).join("");
|
|
122
|
+
const body = `
|
|
123
|
+
<main class="rk-chat-page">
|
|
124
|
+
<div class="rk-chat-col">
|
|
125
|
+
<header class="rk-chat-head">
|
|
126
|
+
<div class="rk-chat-head-titles">
|
|
127
|
+
<span class="rk-chat-eyebrow">Brainstorm</span>
|
|
128
|
+
<h1 class="rk-chat-title" id="rk-chat-title">Magnesium sleep gummy — cold TikTok</h1>
|
|
129
|
+
<p class="rk-chat-subhead">Short-form angles, hooks & a ready-to-render template — brainstormed on your own AI keys.</p>
|
|
130
|
+
</div>
|
|
131
|
+
<div class="rk-chat-head-actions">
|
|
132
|
+
<div class="rk-chat-history">
|
|
133
|
+
<button type="button" class="rk-btn rk-btn-ghost rk-btn-sm" id="rk-chat-history-btn" aria-haspopup="true" aria-expanded="false">History <span class="rk-chat-caret" aria-hidden="true">▾</span></button>
|
|
134
|
+
<div class="rk-chat-hist-menu" id="rk-chat-history-menu" hidden>
|
|
135
|
+
<div class="rk-chat-hist-head">Recent brainstorms</div>
|
|
136
|
+
${historyItems}
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
<button type="button" class="rk-btn rk-btn-ghost rk-btn-sm rk-chat-new" id="rk-chat-new"><span class="rk-chat-plus" aria-hidden="true">+</span> New</button>
|
|
140
|
+
</div>
|
|
141
|
+
</header>
|
|
142
|
+
|
|
143
|
+
<div class="rk-chat-thread" id="rk-chat-thread">
|
|
144
|
+
${thread}
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<div class="rk-chat-dock">
|
|
148
|
+
<div class="rk-chat-starters" aria-label="Starter prompts">
|
|
149
|
+
${starterChips}
|
|
150
|
+
</div>
|
|
151
|
+
<div class="rk-chat-composer" id="rk-chat-composer">
|
|
152
|
+
<button type="button" class="rk-chat-attach" aria-label="Attach a file">${CLIP}</button>
|
|
153
|
+
<textarea id="rk-chat-input" class="rk-chat-input" rows="1"
|
|
154
|
+
placeholder="Describe your offer, audience, or the problem to solve…"></textarea>
|
|
155
|
+
<button type="button" class="rk-btn rk-btn-gold rk-chat-send" id="rk-chat-send">Send ${SEND}</button>
|
|
156
|
+
</div>
|
|
157
|
+
<p class="rk-chat-hint">Brainstormed on your own AI keys — never billed by vidfarm. <kbd>Enter</kbd> to send · <kbd>Shift</kbd>+<kbd>Enter</kbd> for a new line.</p>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
</main>`;
|
|
161
|
+
const pageCss = `
|
|
162
|
+
/* ── centered single-column chat ───────────────────────────────────────── */
|
|
163
|
+
.rk-chat-page{width:100%;padding:0 var(--rk-gutter);background:var(--rk-bg)}
|
|
164
|
+
.rk-chat-col{width:min(800px,100%);margin:0 auto;display:flex;flex-direction:column;
|
|
165
|
+
min-height:100vh;padding-top:34px}
|
|
166
|
+
|
|
167
|
+
/* compact header */
|
|
168
|
+
.rk-chat-head{display:flex;align-items:flex-start;justify-content:space-between;gap:18px;
|
|
169
|
+
padding-bottom:22px;margin-bottom:6px;border-bottom:1px solid var(--rk-border)}
|
|
170
|
+
.rk-chat-head-titles{display:grid;gap:6px;min-width:0}
|
|
171
|
+
.rk-chat-eyebrow{display:inline-flex;align-items:center;font-size:12px;font-weight:700;
|
|
172
|
+
letter-spacing:.06em;text-transform:uppercase;color:var(--rk-gold-700)}
|
|
173
|
+
.rk-chat-title{font-family:var(--rk-font-display);font-weight:800;font-size:1.7rem;letter-spacing:-.025em;
|
|
174
|
+
line-height:1.15;color:var(--rk-ink);min-width:0}
|
|
175
|
+
.rk-chat-subhead{font-size:14.5px;color:var(--rk-text-muted);line-height:1.5;max-width:56ch}
|
|
176
|
+
.rk-chat-head-actions{display:flex;align-items:center;gap:9px;flex:none}
|
|
177
|
+
.rk-chat-plus{font-size:14px;font-weight:700;line-height:1;margin-right:1px}
|
|
178
|
+
.rk-chat-caret{font-size:11px;color:var(--rk-text-faint)}
|
|
179
|
+
|
|
180
|
+
/* history popover */
|
|
181
|
+
.rk-chat-history{position:relative}
|
|
182
|
+
.rk-chat-hist-menu{position:absolute;top:calc(100% + 8px);right:0;z-index:20;width:min(300px,80vw);
|
|
183
|
+
background:var(--rk-surface);border:1px solid var(--rk-border);border-radius:var(--rk-r-2xl);
|
|
184
|
+
box-shadow:var(--rk-shadow-lg);padding:8px;display:grid;gap:2px}
|
|
185
|
+
.rk-chat-hist-menu[hidden]{display:none}
|
|
186
|
+
.rk-chat-hist-head{font-size:11px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;
|
|
187
|
+
color:var(--rk-text-faint);padding:8px 10px 6px}
|
|
188
|
+
.rk-chat-hist-item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;
|
|
189
|
+
text-align:left;cursor:pointer;font-family:var(--rk-font-body);background:transparent;border:1px solid transparent;
|
|
190
|
+
border-radius:var(--rk-r-lg);padding:9px 11px;transition:background var(--rk-dur) var(--rk-ease)}
|
|
191
|
+
.rk-chat-hist-item:hover{background:var(--rk-n-100)}
|
|
192
|
+
.rk-chat-hist-item.is-active{background:var(--rk-gold-tint)}
|
|
193
|
+
.rk-chat-hist-title{font-size:13px;font-weight:600;color:var(--rk-ink);min-width:0;white-space:nowrap;
|
|
194
|
+
overflow:hidden;text-overflow:ellipsis}
|
|
195
|
+
.rk-chat-hist-when{flex:none;font-size:11px;font-weight:600;color:var(--rk-text-faint)}
|
|
196
|
+
|
|
197
|
+
/* thread — flex:1 pushes the dock to the bottom when the page is short */
|
|
198
|
+
.rk-chat-thread{flex:1;display:grid;gap:28px;align-content:start;padding:30px 0 26px}
|
|
199
|
+
.rk-chat-msg{display:grid;gap:8px;min-width:0}
|
|
200
|
+
.rk-chat-msg.is-user{justify-items:end}
|
|
201
|
+
.rk-chat-meta{display:flex;align-items:center;gap:7px;font-size:11.5px;font-weight:700;letter-spacing:.05em;
|
|
202
|
+
text-transform:uppercase;color:var(--rk-text-faint);padding:0 4px}
|
|
203
|
+
.rk-chat-time{font-weight:600;letter-spacing:.02em;color:var(--rk-n-300);text-transform:none;font-size:11px}
|
|
204
|
+
.rk-chat-avatar{width:20px;height:20px;border-radius:6px;flex:none;display:grid;place-items:center;color:#fff;
|
|
205
|
+
font-family:var(--rk-font-display);font-weight:800;font-size:11px;line-height:1;
|
|
206
|
+
background:linear-gradient(142deg,var(--rk-gold-500),var(--rk-violet))}
|
|
207
|
+
|
|
208
|
+
/* bubbles — uniform 1px hairline on all four sides, no colored side stripes */
|
|
209
|
+
.rk-chat-bubble{border-radius:var(--rk-r-2xl);padding:16px 20px;font-size:15px;line-height:1.65}
|
|
210
|
+
.rk-chat-bubble-user{max-width:min(78%,560px);background:var(--rk-ink);color:#f4f4f5;
|
|
211
|
+
border:1px solid var(--rk-n-800);box-shadow:var(--rk-shadow-sm)}
|
|
212
|
+
.rk-chat-bubble-assistant{width:100%;background:var(--rk-surface);color:var(--rk-n-700);
|
|
213
|
+
border:1px solid var(--rk-border);box-shadow:var(--rk-shadow-card)}
|
|
214
|
+
|
|
215
|
+
/* rich (but calm) assistant content */
|
|
216
|
+
.rk-chat-p{margin:0}
|
|
217
|
+
.rk-chat-p + *{margin-top:14px}
|
|
218
|
+
.rk-chat-bubble-assistant strong{color:var(--rk-ink);font-weight:700}
|
|
219
|
+
.rk-chat-hooks{display:grid;gap:12px}
|
|
220
|
+
.rk-chat-hook{display:grid;grid-template-columns:auto minmax(0,1fr);gap:11px;align-items:start}
|
|
221
|
+
.rk-chat-hook-dot{width:7px;height:7px;border-radius:50%;background:var(--rk-gold-500);
|
|
222
|
+
box-shadow:0 0 0 3px var(--rk-gold-tint);margin-top:8px}
|
|
223
|
+
.rk-chat-hook-text{color:var(--rk-n-700);line-height:1.55}
|
|
224
|
+
.rk-chat-note{margin-top:16px;font-size:13.5px;color:var(--rk-text-muted);line-height:1.6}
|
|
225
|
+
.rk-chat-note strong{color:var(--rk-ink);font-weight:700}
|
|
226
|
+
|
|
227
|
+
/* generated-template card (nested card keeps its own full hairline) */
|
|
228
|
+
.rk-chat-art{display:flex;gap:16px;margin-top:16px;padding:15px;border-radius:var(--rk-r-2xl);
|
|
229
|
+
background:var(--rk-n-50);border:1px solid var(--rk-border)}
|
|
230
|
+
.rk-chat-art-main{display:grid;gap:7px;align-content:start;min-width:0}
|
|
231
|
+
.rk-chat-art-eyebrow{font-size:11px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:var(--rk-gold-700)}
|
|
232
|
+
.rk-chat-art-title{font-family:var(--rk-font-display);font-weight:800;font-size:16px;color:var(--rk-ink);letter-spacing:-.01em}
|
|
233
|
+
.rk-chat-art-meta{font-size:12.5px;color:var(--rk-text-faint);font-weight:500}
|
|
234
|
+
.rk-chat-art-desc{font-size:13.5px;color:var(--rk-text-muted);line-height:1.55}
|
|
235
|
+
.rk-chat-art-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:4px}
|
|
236
|
+
|
|
237
|
+
/* 9:16 poster tile */
|
|
238
|
+
.rk-chat-poster{position:relative;width:116px;aspect-ratio:9/16;flex:none;overflow:hidden;
|
|
239
|
+
border-radius:var(--rk-r-xl);box-shadow:var(--rk-shadow-sm);
|
|
240
|
+
background:linear-gradient(160deg,#3b2f73,#8256c9)}
|
|
241
|
+
.rk-chat-poster-dur{position:absolute;top:8px;right:8px;font-size:10px;font-weight:700;color:#fff;
|
|
242
|
+
background:rgba(0,0,0,.42);padding:2px 7px;border-radius:var(--rk-r-full);letter-spacing:.02em}
|
|
243
|
+
.rk-chat-poster-play{position:absolute;inset:0;margin:auto;width:34px;height:34px;border-radius:50%;
|
|
244
|
+
background:rgba(255,255,255,.94);color:var(--rk-ink);display:grid;place-items:center;font-size:11px;
|
|
245
|
+
padding-left:2px;box-shadow:var(--rk-shadow-sm)}
|
|
246
|
+
|
|
247
|
+
/* ── quiet sticky composer dock ── */
|
|
248
|
+
.rk-chat-dock{position:sticky;bottom:0;z-index:10;background:var(--rk-bg);
|
|
249
|
+
padding:16px 0 22px;display:grid;gap:12px}
|
|
250
|
+
.rk-chat-dock::before{content:"";position:absolute;left:0;right:0;top:-26px;height:26px;pointer-events:none;
|
|
251
|
+
background:linear-gradient(to top,var(--rk-bg),transparent)}
|
|
252
|
+
.rk-chat-starters{display:flex;flex-wrap:wrap;gap:9px}
|
|
253
|
+
.rk-chat-chip{display:inline-flex;align-items:center;gap:7px;padding:8px 14px;border-radius:var(--rk-r-full);
|
|
254
|
+
font-family:var(--rk-font-body);font-size:13px;font-weight:600;color:var(--rk-n-700);cursor:pointer;
|
|
255
|
+
background:var(--rk-surface);border:1px solid var(--rk-border);box-shadow:var(--rk-shadow-xs);
|
|
256
|
+
transition:transform var(--rk-dur) var(--rk-ease),box-shadow var(--rk-dur) var(--rk-ease),border-color var(--rk-dur) var(--rk-ease),background var(--rk-dur) var(--rk-ease)}
|
|
257
|
+
.rk-chat-chip:hover{border-color:var(--rk-gold-600);background:var(--rk-gold-tint);color:var(--rk-ink);
|
|
258
|
+
transform:translateY(-1px);box-shadow:var(--rk-shadow-sm)}
|
|
259
|
+
.rk-chat-composer{display:flex;align-items:flex-end;gap:9px;background:var(--rk-surface);
|
|
260
|
+
border:1px solid var(--rk-border-strong);border-radius:var(--rk-r-3xl);padding:9px 9px 9px 12px;
|
|
261
|
+
box-shadow:var(--rk-shadow-card);transition:border-color var(--rk-dur) var(--rk-ease),box-shadow var(--rk-dur) var(--rk-ease)}
|
|
262
|
+
.rk-chat-composer:focus-within{border-color:var(--rk-gold-600);box-shadow:var(--rk-ring-gold)}
|
|
263
|
+
.rk-chat-attach{flex:none;width:40px;height:40px;border-radius:var(--rk-r-full);border:0;cursor:pointer;
|
|
264
|
+
display:grid;place-items:center;background:var(--rk-n-100);color:var(--rk-n-600);
|
|
265
|
+
transition:background var(--rk-dur) var(--rk-ease),color var(--rk-dur) var(--rk-ease)}
|
|
266
|
+
.rk-chat-attach:hover{background:var(--rk-n-200);color:var(--rk-ink)}
|
|
267
|
+
.rk-chat-attach svg{width:19px;height:19px}
|
|
268
|
+
.rk-chat-input{flex:1;min-width:0;border:0;background:transparent;resize:none;font-family:var(--rk-font-body);
|
|
269
|
+
font-size:15px;line-height:1.5;color:var(--rk-ink);padding:10px 2px;max-height:148px}
|
|
270
|
+
.rk-chat-input:focus{outline:none;box-shadow:none}
|
|
271
|
+
.rk-chat-input::placeholder{color:var(--rk-n-400)}
|
|
272
|
+
.rk-chat-send{flex:none;padding:11px 18px}
|
|
273
|
+
.rk-chat-send svg{width:16px;height:16px}
|
|
274
|
+
.rk-chat-hint{text-align:center;font-size:11.5px;color:var(--rk-text-faint);line-height:1.5}
|
|
275
|
+
.rk-chat-hint kbd{font-family:var(--rk-font-mono);font-size:10.5px;background:var(--rk-n-100);
|
|
276
|
+
border:1px solid var(--rk-border);border-radius:5px;padding:1px 5px;color:var(--rk-n-600)}
|
|
277
|
+
|
|
278
|
+
/* typing indicator (appended on send) */
|
|
279
|
+
.rk-chat-typing{display:inline-flex;gap:4px;align-items:center;padding:2px 0}
|
|
280
|
+
.rk-chat-typing span{width:7px;height:7px;border-radius:50%;background:var(--rk-n-400);
|
|
281
|
+
animation:rk-chat-blink 1.2s var(--rk-ease) infinite}
|
|
282
|
+
.rk-chat-typing span:nth-child(2){animation-delay:.18s}
|
|
283
|
+
.rk-chat-typing span:nth-child(3){animation-delay:.36s}
|
|
284
|
+
@keyframes rk-chat-blink{0%,80%,100%{opacity:.28;transform:translateY(0)}40%{opacity:1;transform:translateY(-2px)}}
|
|
285
|
+
|
|
286
|
+
/* ── narrow: bubbles go full-width, header stacks ── */
|
|
287
|
+
@media(max-width:720px){
|
|
288
|
+
.rk-chat-col{padding-top:24px}
|
|
289
|
+
.rk-chat-head{flex-direction:column;gap:14px}
|
|
290
|
+
.rk-chat-head-actions{align-self:flex-start}
|
|
291
|
+
.rk-chat-title{font-size:1.5rem}
|
|
292
|
+
.rk-chat-bubble-user{max-width:100%}
|
|
293
|
+
}
|
|
294
|
+
@media(max-width:560px){
|
|
295
|
+
.rk-chat-art{flex-direction:column}
|
|
296
|
+
.rk-chat-poster{width:132px}
|
|
297
|
+
.rk-chat-thread{gap:22px}
|
|
298
|
+
}
|
|
299
|
+
`;
|
|
300
|
+
const script = `
|
|
301
|
+
(function(){
|
|
302
|
+
var root=document;
|
|
303
|
+
var input=root.getElementById('rk-chat-input');
|
|
304
|
+
var send=root.getElementById('rk-chat-send');
|
|
305
|
+
var thread=root.getElementById('rk-chat-thread');
|
|
306
|
+
var title=root.getElementById('rk-chat-title');
|
|
307
|
+
var AVATAR='V';
|
|
308
|
+
var REPLIES=[
|
|
309
|
+
"On it. Give me a beat — I'll shape that into hooks, a tight script, and a template you can render.",
|
|
310
|
+
"Good direction. I'll pull a trending format that fits and draft the on-screen captions to match.",
|
|
311
|
+
"Love it. Let me turn that into three testable angles and flag which one is cheapest to shoot first."
|
|
312
|
+
];
|
|
313
|
+
var replyTurn=0;
|
|
314
|
+
|
|
315
|
+
function autosize(){ if(!input)return; input.style.height='auto'; input.style.height=Math.min(input.scrollHeight,148)+'px'; }
|
|
316
|
+
function toBottom(){ try{ window.scrollTo({top:document.body.scrollHeight,behavior:'smooth'}); }catch(e){ window.scrollTo(0,document.body.scrollHeight); } }
|
|
317
|
+
function nowLabel(){ try{ return new Date().toLocaleTimeString([], {hour:'numeric', minute:'2-digit'}); }catch(e){ return ''; } }
|
|
318
|
+
function el(cls){ var d=root.createElement('div'); d.className=cls; return d; }
|
|
319
|
+
|
|
320
|
+
function appendUser(text){
|
|
321
|
+
var msg=el('rk-chat-msg is-user');
|
|
322
|
+
var meta=el('rk-chat-meta'); meta.innerHTML='You <span class="rk-chat-time">'+nowLabel()+'</span>';
|
|
323
|
+
var bub=el('rk-chat-bubble rk-chat-bubble-user'); bub.textContent=text;
|
|
324
|
+
msg.appendChild(meta); msg.appendChild(bub);
|
|
325
|
+
if(thread) thread.appendChild(msg);
|
|
326
|
+
}
|
|
327
|
+
function appendAssistant(){
|
|
328
|
+
var msg=el('rk-chat-msg is-assistant');
|
|
329
|
+
var meta=el('rk-chat-meta');
|
|
330
|
+
meta.innerHTML='<span class="rk-chat-avatar" aria-hidden="true">'+AVATAR+'</span>Copilot <span class="rk-chat-time">'+nowLabel()+'</span>';
|
|
331
|
+
var bub=el('rk-chat-bubble rk-chat-bubble-assistant');
|
|
332
|
+
bub.innerHTML='<span class="rk-chat-typing"><span></span><span></span><span></span></span>';
|
|
333
|
+
msg.appendChild(meta); msg.appendChild(bub);
|
|
334
|
+
if(thread) thread.appendChild(msg);
|
|
335
|
+
return bub;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function sendMessage(){
|
|
339
|
+
if(!input) return;
|
|
340
|
+
var text=input.value.trim();
|
|
341
|
+
if(!text) return;
|
|
342
|
+
appendUser(text);
|
|
343
|
+
input.value=''; autosize(); toBottom();
|
|
344
|
+
var bub=appendAssistant(); toBottom();
|
|
345
|
+
var line=REPLIES[replyTurn % REPLIES.length]; replyTurn++;
|
|
346
|
+
setTimeout(function(){
|
|
347
|
+
if(bub){ bub.innerHTML='<p class="rk-chat-p"></p>'; bub.firstChild.textContent=line; toBottom(); }
|
|
348
|
+
}, 850);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if(input){ input.addEventListener('input',autosize); autosize(); }
|
|
352
|
+
if(send){ send.addEventListener('click',sendMessage); }
|
|
353
|
+
if(input){
|
|
354
|
+
input.addEventListener('keydown',function(ev){
|
|
355
|
+
if(ev.key==='Enter' && !ev.shiftKey){ ev.preventDefault(); sendMessage(); }
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// starter chips fill + focus the composer
|
|
360
|
+
root.querySelectorAll('[data-rk-prompt]').forEach(function(chip){
|
|
361
|
+
chip.addEventListener('click',function(){
|
|
362
|
+
if(!input)return;
|
|
363
|
+
input.value=chip.getAttribute('data-rk-prompt')+': ';
|
|
364
|
+
autosize(); input.focus();
|
|
365
|
+
try{ input.setSelectionRange(input.value.length,input.value.length); }catch(e){}
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
// "New" resets the thread to a warm empty state
|
|
370
|
+
root.getElementById('rk-chat-new') && root.getElementById('rk-chat-new').addEventListener('click',function(){
|
|
371
|
+
if(thread){
|
|
372
|
+
thread.innerHTML='<div class="rk-chat-msg is-assistant">'+
|
|
373
|
+
'<div class="rk-chat-meta"><span class="rk-chat-avatar" aria-hidden="true">'+AVATAR+'</span>Copilot <span class="rk-chat-time">'+nowLabel()+'</span></div>'+
|
|
374
|
+
'<div class="rk-chat-bubble rk-chat-bubble-assistant"><p class="rk-chat-p">Fresh page. Tell me the offer, who it\\u2019s for, and where the traffic is cold \\u2014 I\\u2019ll come back with angles, hooks, and a template you can render.</p></div>'+
|
|
375
|
+
'</div>';
|
|
376
|
+
}
|
|
377
|
+
if(title) title.textContent='New brainstorm';
|
|
378
|
+
if(input){ input.focus(); }
|
|
379
|
+
window.scrollTo(0,0);
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
// unobtrusive history popover
|
|
383
|
+
var histBtn=root.getElementById('rk-chat-history-btn');
|
|
384
|
+
var histMenu=root.getElementById('rk-chat-history-menu');
|
|
385
|
+
function closeHist(){ if(histMenu){ histMenu.hidden=true; } if(histBtn){ histBtn.setAttribute('aria-expanded','false'); } }
|
|
386
|
+
if(histBtn && histMenu){
|
|
387
|
+
histBtn.addEventListener('click',function(ev){
|
|
388
|
+
ev.stopPropagation();
|
|
389
|
+
var open=histMenu.hidden;
|
|
390
|
+
histMenu.hidden=!open; histBtn.setAttribute('aria-expanded', open?'true':'false');
|
|
391
|
+
});
|
|
392
|
+
histMenu.querySelectorAll('[data-rk-title]').forEach(function(it){
|
|
393
|
+
it.addEventListener('click',function(){
|
|
394
|
+
histMenu.querySelectorAll('[data-rk-title]').forEach(function(x){ x.classList.toggle('is-active',x===it); });
|
|
395
|
+
if(title){ var t=it.getAttribute('data-rk-title'); if(t) title.textContent=t; }
|
|
396
|
+
closeHist();
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
root.addEventListener('click',function(ev){
|
|
400
|
+
if(histMenu.hidden) return;
|
|
401
|
+
if(!histMenu.contains(ev.target) && ev.target!==histBtn) closeHist();
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
})();`;
|
|
405
|
+
return reskinDocument({
|
|
406
|
+
title: "vidfarm reskin — Brainstorm",
|
|
407
|
+
description: "Reskinned vidfarm AI brainstorm chat — a clean, calm single-column conversation with a compact header, starter chips, and a quiet composer.",
|
|
408
|
+
activeSlug: "chat",
|
|
409
|
+
pageCss,
|
|
410
|
+
body,
|
|
411
|
+
script
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
//# sourceMappingURL=chat-page.js.map
|