@mevdragon/vidfarm-devcli 0.15.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.
Files changed (37) hide show
  1. package/.agents/skills/farmville-saas-ux/SKILL.md +156 -0
  2. package/.agents/skills/farmville-saas-ux/assets/starter.html +294 -0
  3. package/.agents/skills/farmville-saas-ux/references/components.md +340 -0
  4. package/.agents/skills/farmville-saas-ux/references/porting-guide.md +121 -0
  5. package/.agents/skills/farmville-saas-ux/references/tokens.md +271 -0
  6. package/.agents/skills/vidfarm-media/SKILL.md +2 -1
  7. package/.agents/skills/vidfarm-media/references/tts.md +20 -1
  8. package/demo/dist/app.css +1 -1
  9. package/demo/dist/app.js +74 -74
  10. package/dist/src/account-pages-legacy.js +2 -2
  11. package/dist/src/app.js +682 -12
  12. package/dist/src/config.js +13 -0
  13. package/dist/src/editor-chat.js +3 -2
  14. package/dist/src/frontend/homepage-client.js +211 -2
  15. package/dist/src/frontend/homepage-shared.js +197 -0
  16. package/dist/src/frontend/homepage-store.js +39 -1
  17. package/dist/src/frontend/homepage-view.js +150 -5
  18. package/dist/src/homepage.js +234 -18
  19. package/dist/src/landing-page.js +367 -0
  20. package/dist/src/primitive-registry.js +278 -2
  21. package/dist/src/reskin/agency-page.js +255 -0
  22. package/dist/src/reskin/calendar-page.js +252 -0
  23. package/dist/src/reskin/chat-page.js +414 -0
  24. package/dist/src/reskin/discover-page.js +380 -0
  25. package/dist/src/reskin/document.js +74 -0
  26. package/dist/src/reskin/help-page.js +318 -0
  27. package/dist/src/reskin/index-page.js +62 -0
  28. package/dist/src/reskin/job-runs-page.js +249 -0
  29. package/dist/src/reskin/library-page.js +515 -0
  30. package/dist/src/reskin/login-page.js +225 -0
  31. package/dist/src/reskin/pricing-page.js +359 -0
  32. package/dist/src/reskin/settings-page.js +353 -0
  33. package/dist/src/reskin/theme.js +265 -0
  34. package/dist/src/services/serverless-records.js +63 -0
  35. package/dist/src/services/swipe-customize.js +434 -0
  36. package/package.json +1 -1
  37. package/public/assets/homepage-client-app.js +23 -23
@@ -0,0 +1,252 @@
1
+ // /reskin/calendar — the scheduled-posts calendar ported into the farmville
2
+ // design system. A calm, full-width month board where each day holds simple
3
+ // post chips (platform swatch + title + time) with a small status dot, today
4
+ // highlighted, and a compact status legend beneath the grid.
5
+ //
6
+ // SIMPLIFIED layout: the earlier version paired the month grid with a right-hand
7
+ // side rail (Channels card + "Up next" agenda) plus a legend and a Month/Week/Day
8
+ // toggle. That was too busy, so the board is now the full-width hero of the page
9
+ // and the rail is gone — more whitespace, fewer competing elements per cell.
10
+ //
11
+ // Renders with representative SAMPLE data (a full month of scheduled short-form
12
+ // posts) so it can be viewed without auth or a FlockPoster connection. Uses ONLY
13
+ // shared rk-* primitives + a small page-scoped `rk-calendar-` CSS block.
14
+ import { reskinDocument, rkEscape } from "./document.js";
15
+ // ── The month we're rendering. today = Jul 7, 2026 (deterministic snapshot). ──
16
+ const YEAR = 2026;
17
+ const MONTH = 6; // 0-indexed → July
18
+ const TODAY_DOM = 7;
19
+ const MONTH_LABEL = "July 2026";
20
+ const WEEKDAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
21
+ const PLATFORM = {
22
+ TikTok: { initial: "T", swatch: "tiktok", label: "TikTok" },
23
+ Instagram: { initial: "I", swatch: "instagram", label: "Instagram" },
24
+ YouTube: { initial: "Y", swatch: "youtube", label: "YouTube" },
25
+ Email: { initial: "E", swatch: "email", label: "Email" }
26
+ };
27
+ const STATUS = {
28
+ draft: { label: "Draft", pill: "rk-pill" },
29
+ review: { label: "Review", pill: "rk-pill-gold" },
30
+ ready: { label: "Ready", pill: "rk-pill-green" },
31
+ scheduled: { label: "Scheduled", pill: "rk-pill-sky" },
32
+ sent: { label: "Sent", pill: "rk-pill-violet" },
33
+ error: { label: "Failed", pill: "rk-pill-red" }
34
+ };
35
+ // day-of-month → scheduled posts (in-month only).
36
+ const POSTS_BY_DOM = {
37
+ 1: [
38
+ { title: "Cold open hook A/B", platform: "TikTok", status: "scheduled", time: "9:00 AM" },
39
+ { title: "Behind the build", platform: "Instagram", status: "draft", time: "12:30 PM" }
40
+ ],
41
+ 2: [{ title: "3 mistakes founders make", platform: "YouTube", status: "review", time: "2:00 PM" }],
42
+ 6: [{ title: "Monday momentum", platform: "TikTok", status: "scheduled", time: "8:30 AM" }],
43
+ 7: [
44
+ { title: "Feature reveal teaser", platform: "Instagram", status: "ready", time: "11:00 AM" },
45
+ { title: "Newsletter: ship week", platform: "Email", status: "scheduled", time: "4:00 PM" },
46
+ { title: "POV: launch day", platform: "TikTok", status: "scheduled", time: "6:00 PM" }
47
+ ],
48
+ 8: [{ title: "Testimonial cut", platform: "YouTube", status: "scheduled", time: "1:00 PM" }],
49
+ 9: [{ title: "Duet reply to @acme", platform: "TikTok", status: "draft", time: "5:15 PM" }],
50
+ 10: [
51
+ { title: "Weekly recap", platform: "Email", status: "scheduled", time: "9:00 AM" },
52
+ { title: "Founder Q&A reel", platform: "Instagram", status: "review", time: "3:00 PM" }
53
+ ],
54
+ 13: [{ title: "Hook test v4", platform: "TikTok", status: "scheduled", time: "8:00 AM" }],
55
+ 14: [
56
+ { title: "Case study reel", platform: "Instagram", status: "scheduled", time: "12:00 PM" },
57
+ { title: "Shorts: 60s explainer", platform: "YouTube", status: "ready", time: "5:00 PM" }
58
+ ],
59
+ 15: [{ title: "Mid-month drop", platform: "Email", status: "sent", time: "9:00 AM" }],
60
+ 16: [{ title: "Trend jack: sound #4127", platform: "TikTok", status: "error", time: "7:00 PM" }],
61
+ 17: [{ title: "Behind the numbers", platform: "YouTube", status: "scheduled", time: "2:00 PM" }],
62
+ 20: [
63
+ { title: "Monday reset", platform: "TikTok", status: "scheduled", time: "8:30 AM" },
64
+ { title: "Carousel: 5 tips", platform: "Instagram", status: "draft", time: "1:00 PM" }
65
+ ],
66
+ 21: [{ title: "Founder story pt.2", platform: "Instagram", status: "scheduled", time: "11:00 AM" }],
67
+ 23: [{ title: "Live recap", platform: "YouTube", status: "review", time: "4:00 PM" }],
68
+ 24: [
69
+ { title: "Weekly drop", platform: "Email", status: "scheduled", time: "9:00 AM" },
70
+ { title: "Friday feature", platform: "TikTok", status: "scheduled", time: "5:00 PM" }
71
+ ],
72
+ 27: [{ title: "Hook test v5", platform: "TikTok", status: "scheduled", time: "8:00 AM" }],
73
+ 28: [
74
+ { title: "Product deep-dive", platform: "YouTube", status: "scheduled", time: "1:00 PM" },
75
+ { title: "Reel: real results", platform: "Instagram", status: "ready", time: "6:00 PM" }
76
+ ],
77
+ 30: [
78
+ { title: "Month-end recap", platform: "Email", status: "scheduled", time: "10:00 AM" },
79
+ { title: "TikTok trend remix", platform: "TikTok", status: "draft", time: "3:00 PM" },
80
+ { title: "Teaser: August drop", platform: "Instagram", status: "scheduled", time: "7:00 PM" }
81
+ ],
82
+ 31: [{ title: "Final Friday push", platform: "TikTok", status: "scheduled", time: "5:00 PM" }]
83
+ };
84
+ const CHANNELS = [
85
+ { name: "Vidfarm Daily", handle: "@vidfarm", platform: "TikTok", active: true },
86
+ { name: "Founder Reels", handle: "@dylan.builds", platform: "Instagram" },
87
+ { name: "Studio Shorts", handle: "@vidfarm.studio", platform: "YouTube" },
88
+ { name: "Weekly Drop", handle: "dylan@studio.co", platform: "Email" }
89
+ ];
90
+ function allPosts() {
91
+ const out = [];
92
+ for (const [dom, posts] of Object.entries(POSTS_BY_DOM)) {
93
+ for (const p of posts)
94
+ out.push({ ...p, dom: Number(dom) });
95
+ }
96
+ return out;
97
+ }
98
+ function platformSwatch(platform) {
99
+ const meta = PLATFORM[platform];
100
+ return `<span class="rk-calendar-swatch rk-calendar-swatch-${meta.swatch}" aria-hidden="true">${meta.initial}</span>`;
101
+ }
102
+ // One calm chip: platform swatch + title + a small status dot beside the time.
103
+ // No colored borders — status lives in the dot (mapped by the legend below).
104
+ function chip(p) {
105
+ const st = STATUS[p.status];
106
+ const meta = PLATFORM[p.platform];
107
+ return `<button type="button" class="rk-calendar-chip" title="${rkEscape(`${p.title} · ${meta.label} · ${st.label} · ${p.time}`)}">
108
+ ${platformSwatch(p.platform)}
109
+ <span class="rk-calendar-chip-body">
110
+ <span class="rk-calendar-chip-title">${rkEscape(p.title)}</span>
111
+ <span class="rk-calendar-chip-foot">
112
+ <span class="rk-calendar-dot" data-status="${p.status}" aria-hidden="true"></span>
113
+ <span class="rk-calendar-chip-time">${rkEscape(p.time)}</span>
114
+ </span>
115
+ </span>
116
+ </button>`;
117
+ }
118
+ function monthCells() {
119
+ const firstWeekday = new Date(Date.UTC(YEAR, MONTH, 1)).getUTCDay();
120
+ const daysInMonth = new Date(Date.UTC(YEAR, MONTH + 1, 0)).getUTCDate();
121
+ const rows = Math.ceil((firstWeekday + daysInMonth) / 7);
122
+ const total = rows * 7;
123
+ const cells = [];
124
+ for (let i = 0; i < total; i++) {
125
+ const offset = i - firstWeekday; // 0 → the 1st
126
+ const d = new Date(Date.UTC(YEAR, MONTH, 1 + offset));
127
+ const inMonth = d.getUTCMonth() === MONTH;
128
+ const dom = d.getUTCDate();
129
+ const isToday = inMonth && dom === TODAY_DOM;
130
+ const posts = inMonth ? POSTS_BY_DOM[dom] ?? [] : [];
131
+ const shown = posts.slice(0, 3);
132
+ const overflow = posts.length - shown.length;
133
+ const cls = ["rk-calendar-cell"];
134
+ if (!inMonth)
135
+ cls.push("is-out");
136
+ if (isToday)
137
+ cls.push("is-today");
138
+ const badge = isToday ? `<span class="rk-calendar-today">Today</span>` : "";
139
+ const chips = shown.map(chip).join("");
140
+ const more = overflow > 0 ? `<span class="rk-calendar-more">+${overflow} more</span>` : "";
141
+ cells.push(`<div class="${cls.join(" ")}">
142
+ <div class="rk-calendar-cell-head">
143
+ <span class="rk-calendar-daynum">${dom}</span>
144
+ ${badge}
145
+ </div>
146
+ <div class="rk-calendar-cell-posts">${chips}${more}</div>
147
+ </div>`);
148
+ }
149
+ return cells.join("");
150
+ }
151
+ export function renderReskinCalendar() {
152
+ const posts = allPosts();
153
+ const totalPosts = posts.length;
154
+ // weekday header
155
+ const weekdayHead = WEEKDAYS.map((w) => `<div class="rk-calendar-weekday">${w}</div>`).join("");
156
+ // compact one-line status legend under the grid (explains the chip dots)
157
+ const legendOrder = ["draft", "review", "ready", "scheduled", "sent", "error"];
158
+ const legend = legendOrder.map((s) => `<span class="rk-calendar-legend-item"><span class="rk-calendar-dot" data-status="${s}"></span>${STATUS[s].label}</span>`).join("");
159
+ const body = `
160
+ <main class="rk-container-wide rk-page">
161
+ <div class="rk-page-head">
162
+ <span class="rk-badge">Publishing calendar</span>
163
+ <h1 class="rk-h1">Calendar</h1>
164
+ <p class="rk-sub">${totalPosts} scheduled short-form posts across ${CHANNELS.length} channels this July.</p>
165
+ </div>
166
+
167
+ <div class="rk-calendar-toolbar">
168
+ <div class="rk-calendar-monthnav">
169
+ <button type="button" class="rk-btn rk-btn-ghost rk-calendar-navbtn" aria-label="Previous month">←</button>
170
+ <span class="rk-calendar-month">${MONTH_LABEL}</span>
171
+ <button type="button" class="rk-btn rk-btn-ghost rk-calendar-navbtn" aria-label="Next month">→</button>
172
+ <button type="button" class="rk-btn rk-btn-ghost rk-btn-sm rk-calendar-today-btn">Today</button>
173
+ </div>
174
+ <button type="button" class="rk-btn rk-btn-gold">+ Schedule post</button>
175
+ </div>
176
+
177
+ <div class="rk-card rk-calendar-grid-card">
178
+ <div class="rk-calendar-scroll">
179
+ <div class="rk-calendar-weekdays">${weekdayHead}</div>
180
+ <div class="rk-calendar-grid">${monthCells()}</div>
181
+ </div>
182
+ </div>
183
+
184
+ <div class="rk-calendar-legend">${legend}</div>
185
+ </main>`;
186
+ const pageCss = `
187
+ .rk-calendar-toolbar{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;margin-bottom:24px}
188
+ .rk-calendar-monthnav{display:flex;align-items:center;gap:10px}
189
+ .rk-calendar-month{font-family:var(--rk-font-display);font-weight:800;font-size:var(--rk-text-2xl);letter-spacing:-.02em;color:var(--rk-ink);min-width:8.6rem}
190
+ .rk-calendar-navbtn{width:40px;height:40px;padding:0;font-size:16px;line-height:1}
191
+ .rk-calendar-today-btn{margin-left:4px}
192
+
193
+ /* month board — the full-width hero */
194
+ .rk-calendar-grid-card{padding:0;overflow:hidden}
195
+ .rk-calendar-scroll{overflow-x:auto}
196
+ .rk-calendar-weekdays{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));background:var(--rk-n-50);border-bottom:1px solid var(--rk-border)}
197
+ .rk-calendar-weekday{padding:14px 10px;text-align:center;font-size:11px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--rk-text-muted)}
198
+ .rk-calendar-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:1px;background:var(--rk-border)}
199
+ .rk-calendar-cell{background:#fff;min-height:152px;padding:12px 11px;display:flex;flex-direction:column;gap:9px;transition:background var(--rk-dur) var(--rk-ease)}
200
+ .rk-calendar-cell:hover{background:var(--rk-n-50)}
201
+ .rk-calendar-cell.is-out{background:var(--rk-n-50)}
202
+ .rk-calendar-cell.is-out:hover{background:var(--rk-n-100)}
203
+ .rk-calendar-cell.is-today{background:var(--rk-gold-tint);box-shadow:inset 0 0 0 2px var(--rk-gold-500)}
204
+ .rk-calendar-cell-head{display:flex;align-items:center;justify-content:space-between;gap:6px;min-height:28px}
205
+ .rk-calendar-daynum{width:28px;height:28px;border-radius:var(--rk-r-full);display:grid;place-items:center;font-family:var(--rk-font-display);font-weight:700;font-size:14px;color:var(--rk-n-700)}
206
+ .rk-calendar-cell.is-out .rk-calendar-daynum{color:var(--rk-n-400);font-weight:600}
207
+ .rk-calendar-cell.is-today .rk-calendar-daynum{background:var(--rk-gold-500);color:var(--rk-ink);box-shadow:var(--rk-shadow-xs)}
208
+ .rk-calendar-today{display:inline-flex;align-items:center;padding:3px 9px;border-radius:var(--rk-r-full);background:var(--rk-gold-500);color:var(--rk-ink);font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase}
209
+ .rk-calendar-cell-posts{display:flex;flex-direction:column;gap:7px}
210
+
211
+ /* post chip — uniform hairline, airy, status shown by the dot (not a border) */
212
+ .rk-calendar-chip{display:flex;gap:9px;align-items:center;width:100%;text-align:left;padding:8px 10px;border-radius:12px;background:#fff;border:1px solid var(--rk-border);box-shadow:var(--rk-shadow-xs);cursor:pointer;transition:transform var(--rk-dur) var(--rk-ease),box-shadow var(--rk-dur) var(--rk-ease)}
213
+ .rk-calendar-chip:hover{transform:translateY(-1px);box-shadow:var(--rk-shadow-sm)}
214
+ .rk-calendar-chip-body{min-width:0;display:flex;flex-direction:column;gap:3px;flex:1}
215
+ .rk-calendar-chip-title{font-size:12.5px;font-weight:700;color:var(--rk-ink);line-height:1.25;letter-spacing:-.01em;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
216
+ .rk-calendar-chip-foot{display:flex;align-items:center;gap:6px}
217
+ .rk-calendar-chip-time{font-size:11px;font-weight:600;color:var(--rk-text-muted)}
218
+ .rk-calendar-more{font-size:11px;font-weight:700;color:var(--rk-text-muted);padding:1px 2px}
219
+
220
+ /* platform swatch */
221
+ .rk-calendar-swatch{width:26px;height:26px;border-radius:9px;display:grid;place-items:center;font-family:var(--rk-font-display);font-size:13px;font-weight:800;line-height:1;flex:none;box-shadow:var(--rk-shadow-xs)}
222
+ .rk-calendar-swatch-tiktok{background:var(--rk-ink);color:#fff}
223
+ .rk-calendar-swatch-instagram{background:linear-gradient(135deg,#f9ce34,#ee2a7b 55%,#6228d7);color:#fff}
224
+ .rk-calendar-swatch-youtube{background:#ff3b30;color:#fff}
225
+ .rk-calendar-swatch-email{background:var(--rk-sky-tint);color:#1d6fb8}
226
+
227
+ /* status dot — used inside chips AND in the legend */
228
+ .rk-calendar-dot{width:8px;height:8px;border-radius:var(--rk-r-full);background:var(--rk-n-400);flex:none}
229
+ .rk-calendar-dot[data-status="review"]{background:var(--rk-gold-700)}
230
+ .rk-calendar-dot[data-status="ready"]{background:var(--rk-green)}
231
+ .rk-calendar-dot[data-status="scheduled"]{background:var(--rk-sky)}
232
+ .rk-calendar-dot[data-status="sent"]{background:var(--rk-violet)}
233
+ .rk-calendar-dot[data-status="error"]{background:var(--rk-red)}
234
+
235
+ /* compact one-line legend */
236
+ .rk-calendar-legend{display:flex;flex-wrap:wrap;gap:18px;margin-top:18px;padding:0 6px}
237
+ .rk-calendar-legend-item{display:inline-flex;align-items:center;gap:7px;font-size:12px;font-weight:600;color:var(--rk-text-muted)}
238
+
239
+ @media(max-width:760px){
240
+ .rk-calendar-weekdays,.rk-calendar-grid{min-width:660px}
241
+ .rk-calendar-toolbar{gap:12px}
242
+ }
243
+ `;
244
+ return reskinDocument({
245
+ title: "vidfarm reskin — Calendar",
246
+ description: "Reskinned vidfarm calendar — a calm, full-width month of scheduled short-form posts.",
247
+ activeSlug: "calendar",
248
+ pageCss,
249
+ body
250
+ });
251
+ }
252
+ //# sourceMappingURL=calendar-page.js.map