@mevdragon/vidfarm-devcli 0.2.8 → 0.2.10

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 (98) hide show
  1. package/.env.example +9 -0
  2. package/GETTING_STARTED.developers.md +1 -26
  3. package/README.md +3 -0
  4. package/SKILL.developer.md +419 -8
  5. package/auto-create-templates/AUTO_CREATE_TEMPLATES.md +475 -0
  6. package/auto-create-templates/extractor-system-prompt.md +113 -0
  7. package/auto-create-templates/production-graph.schema.json +276 -0
  8. package/auto-create-templates/runbook.md +140 -0
  9. package/auto-create-templates/template-plan.schema.json +230 -0
  10. package/auto-create-templates/template-planner-prompt.md +75 -0
  11. package/dist/src/account-pages-legacy.js +9064 -0
  12. package/dist/src/account-pages.js +41 -620
  13. package/dist/src/app.js +6627 -244
  14. package/dist/src/cli.js +386 -26
  15. package/dist/src/config.js +12 -2
  16. package/dist/src/context.js +35 -35
  17. package/dist/src/db.js +1016 -53
  18. package/dist/src/dev-app-legacy.js +693 -0
  19. package/dist/src/dev-app.js +4 -904
  20. package/dist/src/domain.js +1 -1
  21. package/dist/src/editor-chat-history.js +72 -0
  22. package/dist/src/editor-chat.js +202 -0
  23. package/dist/src/frontend/flockposter-cache-store.js +116 -0
  24. package/dist/src/frontend/homepage-client.js +114 -0
  25. package/dist/src/frontend/homepage-shared.js +3 -0
  26. package/dist/src/frontend/homepage-store.js +27 -0
  27. package/dist/src/frontend/homepage-view.js +147 -0
  28. package/dist/src/frontend/page-runtime-client.js +100 -0
  29. package/dist/src/frontend/page-runtime-store.js +8 -0
  30. package/dist/src/frontend/template-editor-chat.js +2261 -0
  31. package/dist/src/homepage.js +695 -371
  32. package/dist/src/lib/template-style-options.js +95 -15
  33. package/dist/src/page-runtime.js +1 -0
  34. package/dist/src/page-shell.js +941 -0
  35. package/dist/src/primitive-context.js +163 -0
  36. package/dist/src/primitive-registry.js +340 -0
  37. package/dist/src/primitive-sdk.js +3 -0
  38. package/dist/src/primitives/remotion/html-image.js +28 -0
  39. package/dist/src/react-page-shell.js +34 -0
  40. package/dist/src/ready-post-schedule-component.js +1514 -0
  41. package/dist/src/registry.js +36 -17
  42. package/dist/src/runtime.js +6 -1
  43. package/dist/src/services/api-call-history.js +245 -0
  44. package/dist/src/services/auth.js +25 -3
  45. package/dist/src/services/billing.js +248 -9
  46. package/dist/src/services/chat-threads.js +88 -0
  47. package/dist/src/services/job-logs.js +14 -7
  48. package/dist/src/services/jobs.js +13 -2
  49. package/dist/src/services/providers.js +552 -133
  50. package/dist/src/services/rate-limits.js +236 -0
  51. package/dist/src/services/remotion.js +143 -16
  52. package/dist/src/services/storage.js +10 -8
  53. package/dist/src/services/template-certification.js +11 -2
  54. package/dist/src/services/template-loader.js +3 -1
  55. package/dist/src/services/template-sources.js +68 -3
  56. package/dist/src/template-editor-pages.js +2309 -0
  57. package/dist/src/template-editor-shell.js +1507 -0
  58. package/dist/src/worker.js +120 -22
  59. package/package.json +27 -4
  60. package/public/assets/homepage-app.js +54 -0
  61. package/public/assets/homepage-client-app.js +54 -0
  62. package/public/assets/page-runtime-client-app.js +68 -0
  63. package/dist/templates/vidfarm_template_0000/src/lib/images.js +0 -202
  64. package/dist/templates/vidfarm_template_0000/src/remotion/Root.js +0 -34
  65. package/dist/templates/vidfarm_template_0000/src/remotion/index.js +0 -3
  66. package/dist/templates/vidfarm_template_0000/src/sdk.js +0 -3
  67. package/dist/templates/vidfarm_template_0000/src/style-options.js +0 -51
  68. package/dist/templates/vidfarm_template_0000/src/template-dna.js +0 -9
  69. package/dist/templates/vidfarm_template_0000/src/template.js +0 -1447
  70. package/templates/vidfarm_template_0000/README.md +0 -100
  71. package/templates/vidfarm_template_0000/SKILL.md +0 -225
  72. package/templates/vidfarm_template_0000/assets/Abel-Regular.ttf +0 -0
  73. package/templates/vidfarm_template_0000/assets/DMSerifDisplay-Regular.ttf +0 -0
  74. package/templates/vidfarm_template_0000/assets/Montserrat[wght].ttf +0 -0
  75. package/templates/vidfarm_template_0000/assets/SourceCodePro[wght].ttf +0 -0
  76. package/templates/vidfarm_template_0000/assets/TikTokSans-SemiBold.ttf +0 -0
  77. package/templates/vidfarm_template_0000/assets/Yesteryear-Regular.ttf +0 -0
  78. package/templates/vidfarm_template_0000/composition.json +0 -11
  79. package/templates/vidfarm_template_0000/package.json +0 -27
  80. package/templates/vidfarm_template_0000/research/preview/.gitkeep +0 -1
  81. package/templates/vidfarm_template_0000/research/source_notes.md +0 -7
  82. package/templates/vidfarm_template_0000/src/lib/images.js +0 -202
  83. package/templates/vidfarm_template_0000/src/lib/images.ts +0 -241
  84. package/templates/vidfarm_template_0000/src/remotion/Root.js +0 -33
  85. package/templates/vidfarm_template_0000/src/remotion/Root.tsx +0 -75
  86. package/templates/vidfarm_template_0000/src/remotion/index.js +0 -3
  87. package/templates/vidfarm_template_0000/src/remotion/index.tsx +0 -4
  88. package/templates/vidfarm_template_0000/src/sdk.js +0 -3
  89. package/templates/vidfarm_template_0000/src/sdk.ts +0 -140
  90. package/templates/vidfarm_template_0000/src/style-options.js +0 -51
  91. package/templates/vidfarm_template_0000/src/style-options.ts +0 -60
  92. package/templates/vidfarm_template_0000/src/template-dna.js +0 -9
  93. package/templates/vidfarm_template_0000/src/template-dna.ts +0 -15
  94. package/templates/vidfarm_template_0000/src/template.js +0 -1447
  95. package/templates/vidfarm_template_0000/src/template.ts +0 -2049
  96. package/templates/vidfarm_template_0000/template.config.json +0 -21
  97. package/templates/vidfarm_template_0000/tmp/solobacterium-moorei-slideshow.request.json +0 -31
  98. package/templates/vidfarm_template_0000/tsconfig.json +0 -19
@@ -1,473 +1,797 @@
1
- function escapeHtml(value) {
2
- return value
3
- .replace(/&/g, "&")
4
- .replace(/</g, "&lt;")
5
- .replace(/>/g, "&gt;")
6
- .replace(/"/g, "&quot;");
7
- }
8
- function escapeJsonForHtml(value) {
9
- return JSON.stringify(value)
10
- .replace(/</g, "\\u003c")
11
- .replace(/>/g, "\\u003e")
12
- .replace(/&/g, "\\u0026");
13
- }
14
- function formatApprovedAt(value) {
15
- if (!value) {
16
- return "No release timestamp";
17
- }
18
- const date = new Date(value);
19
- if (Number.isNaN(date.getTime())) {
20
- return value;
21
- }
22
- return new Intl.DateTimeFormat("en-US", {
23
- dateStyle: "medium",
24
- timeStyle: "short"
25
- }).format(date);
26
- }
27
- function isVideoPreview(url) {
28
- return Boolean(url && /\.(mp4|webm|ogg|mov)(\?|#|$)/i.test(url));
29
- }
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { renderToString } from "react-dom/server";
3
+ import { HomepageShell } from "./frontend/homepage-view.js";
4
+ import { escapeJsonForHtml, renderPageShell, resolveAccountDisplayName } from "./page-shell.js";
5
+ const HOMEPAGE_CLIENT_ASSET = "/assets/homepage-client-app.js";
30
6
  export function renderHomepage(input) {
31
- const boot = escapeJsonForHtml({
32
- skills: Object.fromEntries(input.templates.map((template) => [template.templateId, template.skillContent]))
33
- });
34
- const rows = input.templates.map((template) => {
35
- const search = `${template.templateId} ${template.title} ${template.slugId}`.toLowerCase();
36
- const media = template.previewUrl
37
- ? isVideoPreview(template.previewUrl)
38
- ? `<video class="preview" data-lazy-video data-src="${escapeHtml(template.previewUrl)}" preload="metadata" muted playsinline controls></video>`
39
- : `<img class="preview" src="${escapeHtml(template.previewUrl)}" alt="${escapeHtml(template.title)} preview" loading="lazy" decoding="async" />`
40
- : `<div class="preview preview-empty">No preview</div>`;
41
- return `
42
- <li class="row" data-search="${escapeHtml(search)}">
43
- <div class="media">${media}</div>
44
- <div class="details">
45
- <div class="meta-line">
46
- <h2>${escapeHtml(template.title)}</h2>
47
- <button class="copy-button" type="button" data-copy-text="${escapeHtml(template.skillContent)}" data-default-label="SKILL.md">SKILL.md</button>
48
- </div>
49
- <dl class="meta-grid">
50
- <div>
51
- <dt>template_id</dt>
52
- <dd><button class="copy-inline" type="button" data-copy-text="${escapeHtml(template.templateId)}" data-default-label="${escapeHtml(template.templateId)}"><code>${escapeHtml(template.templateId)}</code></button></dd>
53
- </div>
54
- <div>
55
- <dt>slug_id</dt>
56
- <dd><button class="copy-inline" type="button" data-copy-text="${escapeHtml(template.slugId)}" data-default-label="${escapeHtml(template.slugId)}"><code>${escapeHtml(template.slugId)}</code></button></dd>
57
- </div>
58
- <div>
59
- <dt>approved</dt>
60
- <dd>${escapeHtml(formatApprovedAt(template.approvedAt))}</dd>
61
- </div>
62
- </dl>
63
- <div class="viral-block">
64
- <span class="eyebrow">Viral DNA</span>
65
- <p>${escapeHtml(template.viralDna)}</p>
66
- </div>
67
- </div>
68
- </li>
69
- `;
70
- }).join("");
71
- const accountLink = input.account.isLoggedIn
72
- ? `<a class="account-link" href="/settings">Settings</a>`
73
- : `<a class="account-link" href="/login">Login</a>`;
74
- return `<!doctype html>
75
- <html lang="en">
76
- <head>
77
- <meta charset="utf-8" />
78
- <meta name="viewport" content="width=device-width, initial-scale=1" />
79
- <title>Approved Templates</title>
80
- <style>
81
- :root {
82
- --bg: #f4f1e8;
83
- --panel: rgba(255, 252, 246, 0.88);
84
- --line: rgba(37, 32, 27, 0.12);
85
- --ink: #171311;
86
- --muted: #64584d;
87
- --accent: #9f3d24;
88
- --accent-soft: rgba(159, 61, 36, 0.12);
89
- --shadow: 0 24px 70px rgba(36, 24, 15, 0.09);
90
- }
91
-
92
- * {
93
- box-sizing: border-box;
94
- }
95
-
96
- body {
97
- margin: 0;
98
- min-height: 100vh;
99
- color: var(--ink);
100
- font-family: Georgia, "Times New Roman", serif;
101
- background:
102
- radial-gradient(circle at top left, rgba(159, 61, 36, 0.14), transparent 24%),
103
- linear-gradient(180deg, #f8f5ed 0%, #f1ebde 100%);
7
+ const boot = {
8
+ templates: input.templates,
9
+ account: input.account,
10
+ loadEndpoint: input.loadEndpoint,
11
+ skillEndpointPrefix: "/discover/skills/"
12
+ };
13
+ return renderPageShell({
14
+ title: input.account.isLoggedIn
15
+ ? resolveAccountDisplayName({ displayName: input.account.displayName, email: input.account.email }) || "VidFarm AI"
16
+ : "Discover Formats",
17
+ mainClass: "is-wide",
18
+ body: `
19
+ <div id="homepage-root">${renderToString(_jsx(HomepageShell, { account: input.account, templates: input.templates, visibleTemplates: input.templates, searchQuery: "", bookmarksOnly: false, bookmarks: new Set(), loading: input.templates.length === 0, error: null, onSearchQueryChange: undefined, onBookmarksOnlyChange: undefined, onToggleBookmark: undefined, skillEndpointPrefix: boot.skillEndpointPrefix }))}</div>
20
+ <script type="application/json" id="homepage-boot">${escapeJsonForHtml(boot)}</script>
21
+ <script type="module" src="${HOMEPAGE_CLIENT_ASSET}"></script>
22
+ `,
23
+ style: `
24
+ #homepage-root {
25
+ display: grid;
26
+ height: 100%;
27
+ min-height: 0;
104
28
  }
105
29
 
106
- body::before {
107
- content: "";
108
- position: fixed;
109
- inset: 0;
110
- pointer-events: none;
111
- background-image:
112
- linear-gradient(rgba(23, 19, 17, 0.035) 1px, transparent 1px),
113
- linear-gradient(90deg, rgba(23, 19, 17, 0.035) 1px, transparent 1px);
114
- background-size: 28px 28px;
115
- mask-image: linear-gradient(180deg, rgba(0, 0, 0, 0.5), transparent 85%);
30
+ .discover-frame {
31
+ height: 100%;
32
+ min-height: 0;
116
33
  }
117
34
 
118
- main {
119
- width: min(1180px, calc(100vw - 32px));
120
- margin: 0 auto;
121
- padding: 32px 0 48px;
35
+ .discover-frame .frame-body {
36
+ grid-template-rows: minmax(0, 1fr);
37
+ height: 100%;
38
+ min-height: 0;
39
+ overflow: hidden;
122
40
  }
123
41
 
124
- .shell {
125
- background: var(--panel);
126
- border: 1px solid var(--line);
42
+ .discover-shell {
43
+ display: grid;
44
+ min-height: 0;
45
+ height: 100%;
46
+ gap: 0;
47
+ overflow: hidden;
48
+ border: 1px solid rgba(255, 255, 255, 0.82);
49
+ border-radius: 32px;
50
+ background: rgba(255, 251, 245, 0.84);
127
51
  box-shadow: var(--shadow);
128
- backdrop-filter: blur(18px);
52
+ grid-template-columns: 360px minmax(0, 1fr);
53
+ grid-template-rows: minmax(0, 1fr);
129
54
  }
130
55
 
131
- .topbar {
132
- padding: 24px;
133
- border-bottom: 1px solid var(--line);
56
+ .discover-sidebar {
57
+ display: grid;
58
+ align-content: start;
59
+ min-height: 0;
60
+ gap: 24px;
61
+ padding: 26px 26px 30px;
62
+ border-right: 1px solid rgba(209, 219, 233, 0.8);
63
+ background: linear-gradient(180deg, rgba(255, 251, 245, 0.96), rgba(255, 248, 239, 0.88));
64
+ }
65
+
66
+ .discover-filter-block,
67
+ .discover-filter-group,
68
+ .discover-filter-panel-body {
69
+ display: grid;
70
+ gap: 10px;
71
+ }
72
+
73
+ .discover-filter-panel {
74
+ display: contents;
75
+ }
76
+
77
+ .discover-filter-panel > summary {
78
+ display: none;
79
+ }
80
+
81
+ .discover-filter-panel:not([open]) > .discover-filter-panel-body {
134
82
  display: grid;
135
- gap: 16px;
136
83
  }
137
84
 
138
- .topline {
85
+ .discover-filter-block p {
86
+ max-width: 30ch;
87
+ }
88
+
89
+ .search-field {
90
+ position: relative;
91
+ }
92
+
93
+ .search-icon {
94
+ position: absolute;
95
+ left: 16px;
96
+ top: 50%;
97
+ width: 20px;
98
+ height: 20px;
99
+ color: #9aa6ba;
100
+ transform: translateY(-50%);
101
+ }
102
+
103
+ .search-icon svg {
104
+ width: 20px;
105
+ height: 20px;
106
+ }
107
+
108
+ .search-field input {
109
+ padding-left: 54px;
110
+ }
111
+
112
+ .bookmarks-row {
139
113
  display: flex;
140
114
  align-items: center;
141
115
  justify-content: space-between;
142
- gap: 16px;
116
+ min-height: 60px;
117
+ padding: 0 18px;
118
+ border: 1px solid var(--line);
119
+ border-radius: 999px;
120
+ background: rgba(255, 255, 255, 0.9);
121
+ color: #58667e;
143
122
  }
144
123
 
145
- .eyebrow {
146
- display: inline-block;
147
- letter-spacing: 0.18em;
148
- text-transform: uppercase;
149
- font-size: 11px;
150
- color: var(--muted);
124
+ .switch-label {
125
+ cursor: pointer;
151
126
  }
152
127
 
153
- .account-link {
154
- border: 1px solid var(--ink);
155
- background: rgba(255, 255, 255, 0.64);
156
- color: var(--ink);
157
- text-decoration: none;
158
- padding: 10px 14px;
159
- font-size: 13px;
160
- letter-spacing: 0.08em;
161
- text-transform: uppercase;
128
+ .switch-shell {
129
+ display: inline-flex;
130
+ align-items: center;
131
+ width: 44px;
132
+ height: 24px;
133
+ padding: 3px;
134
+ border-radius: 999px;
135
+ background: rgba(47, 55, 72, 0.08);
136
+ cursor: pointer;
137
+ transition: background 140ms ease;
162
138
  }
163
139
 
164
- h1 {
165
- margin: 0;
166
- font-weight: 400;
167
- font-size: clamp(2rem, 5vw, 4rem);
168
- line-height: 0.95;
140
+ .switch-input {
141
+ position: absolute;
142
+ opacity: 0;
143
+ pointer-events: none;
169
144
  }
170
145
 
171
- .subcopy {
172
- margin: 0;
173
- max-width: 58ch;
174
- color: var(--muted);
175
- font-size: 17px;
176
- line-height: 1.6;
146
+ .switch-knob {
147
+ display: block;
148
+ width: 18px;
149
+ height: 18px;
150
+ border-radius: 999px;
151
+ background: rgba(255, 255, 255, 0.98);
152
+ box-shadow: 0 2px 8px rgba(15, 23, 42, 0.16);
153
+ transition: transform 140ms ease;
177
154
  }
178
155
 
179
- .search-row {
156
+ .switch-input:checked + .switch-knob {
157
+ transform: translateX(20px);
158
+ }
159
+
160
+ .switch-shell[data-active="true"] {
161
+ background: #dbc17a;
162
+ }
163
+
164
+ .discover-results {
180
165
  display: grid;
181
- grid-template-columns: minmax(0, 1fr) auto;
182
- gap: 12px;
183
- align-items: center;
166
+ min-width: 0;
167
+ min-height: 0;
168
+ height: 100%;
169
+ overflow: hidden;
170
+ padding: 18px 18px 18px 16px;
184
171
  }
185
172
 
186
- input {
187
- width: 100%;
188
- border: 1px solid var(--line);
189
- background: rgba(255, 255, 255, 0.72);
190
- color: var(--ink);
191
- padding: 14px 16px;
192
- font: inherit;
193
- outline: none;
173
+ .discover-results-scroll {
174
+ display: grid;
175
+ gap: 20px;
176
+ align-content: stretch;
177
+ height: 100%;
178
+ min-height: 0;
179
+ overflow-y: auto;
180
+ padding-right: 6px;
194
181
  }
195
182
 
196
- input:focus {
197
- border-color: var(--accent);
198
- box-shadow: 0 0 0 4px var(--accent-soft);
183
+ .discover-count {
184
+ position: sticky;
185
+ top: 0;
186
+ z-index: 2;
187
+ padding-bottom: 2px;
188
+ background: linear-gradient(180deg, rgba(255, 251, 245, 0.98), rgba(255, 251, 245, 0.86) 72%, rgba(255, 251, 245, 0));
199
189
  }
200
190
 
201
- .count {
202
- color: var(--muted);
203
- font-size: 13px;
204
- letter-spacing: 0.08em;
205
- text-transform: uppercase;
191
+ .discover-count {
192
+ justify-self: end;
193
+ color: #8d99ae;
194
+ font-size: 0.9rem;
206
195
  }
207
196
 
208
- .list {
197
+ .discover-list {
209
198
  list-style: none;
210
199
  margin: 0;
211
200
  padding: 0;
201
+ display: grid;
202
+ gap: 22px;
212
203
  }
213
204
 
214
- .row {
205
+ .discover-card {
215
206
  display: grid;
216
- grid-template-columns: 240px minmax(0, 1fr);
217
- gap: 20px;
218
- padding: 24px;
219
- border-bottom: 1px solid var(--line);
207
+ grid-template-columns: minmax(220px, 340px) minmax(0, 1fr);
208
+ gap: 24px;
209
+ padding: 28px;
210
+ border: 1px solid rgba(255, 255, 255, 0.82);
211
+ border-radius: 30px;
212
+ background: rgba(255, 255, 255, 0.76);
213
+ box-shadow: 0 18px 44px rgba(15, 23, 42, 0.06);
220
214
  }
221
215
 
222
- .row[hidden] {
223
- display: none;
216
+ .discover-card-media {
217
+ position: relative;
218
+ display: flex;
219
+ align-items: center;
220
+ justify-content: center;
221
+ min-height: 280px;
222
+ max-height: 540px;
223
+ overflow: hidden;
224
+ border: 1px solid rgba(209, 219, 233, 0.96);
225
+ border-radius: 30px;
226
+ background: rgba(255, 255, 255, 0.84);
224
227
  }
225
228
 
226
- .media {
229
+ .discover-card-media-button {
227
230
  width: 100%;
231
+ padding: 0;
232
+ color: inherit;
233
+ cursor: zoom-in;
234
+ transition:
235
+ border-color 140ms ease,
236
+ box-shadow 140ms ease,
237
+ transform 140ms ease;
228
238
  }
229
239
 
230
- .preview {
231
- display: block;
232
- width: 100%;
233
- aspect-ratio: 9 / 16;
234
- object-fit: cover;
235
- border: 1px solid var(--line);
236
- background: rgba(23, 19, 17, 0.06);
240
+ .discover-card-media-button:hover,
241
+ .discover-card-media-button:focus-visible {
242
+ border-color: rgba(219, 193, 122, 0.96);
243
+ box-shadow: 0 18px 38px rgba(138, 107, 27, 0.16);
244
+ transform: translateY(-1px);
237
245
  }
238
246
 
239
- .preview-empty {
240
- display: grid;
241
- place-items: center;
242
- color: var(--muted);
247
+ .discover-card-media-affordance {
248
+ position: absolute;
249
+ right: 14px;
250
+ bottom: 14px;
251
+ display: inline-flex;
252
+ align-items: center;
253
+ justify-content: center;
254
+ min-height: 34px;
255
+ padding: 0 14px;
256
+ border: 1px solid rgba(255, 255, 255, 0.72);
257
+ border-radius: 999px;
258
+ background: rgba(33, 41, 56, 0.72);
259
+ color: #fffaf3;
260
+ font-size: 0.78rem;
261
+ font-weight: 800;
262
+ letter-spacing: 0.08em;
263
+ line-height: 1;
264
+ opacity: 0;
265
+ text-transform: uppercase;
266
+ transform: translateY(4px);
267
+ transition: opacity 140ms ease, transform 140ms ease;
243
268
  }
244
269
 
245
- .details {
246
- min-width: 0;
270
+ .discover-card-media-button:hover .discover-card-media-affordance,
271
+ .discover-card-media-button:focus-visible .discover-card-media-affordance {
272
+ opacity: 1;
273
+ transform: translateY(0);
274
+ }
275
+
276
+ .discover-card-copy {
247
277
  display: grid;
248
- gap: 16px;
278
+ align-content: start;
279
+ gap: 24px;
280
+ min-width: 0;
249
281
  }
250
282
 
251
- .meta-line {
283
+ .discover-card-head {
252
284
  display: flex;
253
285
  align-items: start;
254
286
  justify-content: space-between;
255
- gap: 16px;
287
+ gap: 18px;
256
288
  }
257
289
 
258
- h2 {
259
- margin: 0;
260
- font-weight: 400;
261
- font-size: clamp(1.35rem, 2vw, 2rem);
290
+ .discover-card-title-wrap {
291
+ min-width: 0;
262
292
  }
263
293
 
264
- .copy-button {
265
- border: 1px solid var(--ink);
266
- background: var(--ink);
267
- color: #f8f5ed;
268
- padding: 10px 14px;
269
- font: inherit;
270
- cursor: pointer;
271
- white-space: nowrap;
294
+ .discover-card-title-wrap h2 {
295
+ font-size: 1.85rem;
272
296
  }
273
297
 
274
- .copy-button:hover {
275
- background: var(--accent);
276
- border-color: var(--accent);
298
+ .discover-card-meta {
299
+ margin-top: 14px;
300
+ color: #b0b9c8;
301
+ font-size: 0.95rem;
277
302
  }
278
303
 
279
- .copy-button[data-state="done"] {
280
- background: transparent;
281
- color: var(--ink);
304
+ .discover-card-actions {
305
+ display: flex;
306
+ align-items: center;
307
+ gap: 12px;
282
308
  }
283
309
 
284
- .copy-inline {
285
- border: 0;
286
- background: transparent;
287
- color: inherit;
310
+ .bookmark-button {
311
+ width: 58px;
312
+ min-width: 58px;
313
+ height: 58px;
314
+ min-height: 58px;
288
315
  padding: 0;
289
- font: inherit;
290
- text-align: left;
316
+ border-color: rgba(209, 219, 233, 0.96);
317
+ background: rgba(255, 255, 255, 0.9);
318
+ color: #55637b;
319
+ transition:
320
+ background 140ms ease,
321
+ border-color 140ms ease,
322
+ color 140ms ease,
323
+ box-shadow 140ms ease;
324
+ }
325
+
326
+ .bookmark-button svg {
327
+ width: 22px;
328
+ height: 22px;
329
+ }
330
+
331
+ .bookmark-button[data-active="true"] {
332
+ border-color: rgba(219, 193, 122, 0.9);
333
+ background: rgba(219, 193, 122, 0.2);
334
+ color: #8a6b1b;
335
+ box-shadow: 0 10px 24px rgba(138, 107, 27, 0.14);
336
+ }
337
+
338
+ .cta-button {
339
+ min-width: 132px;
340
+ height: 58px;
341
+ padding: 0 28px;
342
+ }
343
+
344
+ .discover-card-body p {
345
+ color: #5f6e86;
346
+ font-size: 1.02rem;
347
+ line-height: 1.65;
348
+ }
349
+
350
+ .discover-card-tags {
351
+ display: flex;
352
+ flex-wrap: wrap;
353
+ gap: 10px;
354
+ padding-top: 18px;
355
+ border-top: 1px solid rgba(209, 219, 233, 0.8);
356
+ }
357
+
358
+ .pill-tag {
359
+ display: inline-flex;
360
+ align-items: center;
361
+ min-height: 34px;
362
+ padding: 0 14px;
363
+ border: 1px solid rgba(209, 219, 233, 0.96);
364
+ border-radius: 999px;
365
+ background: rgba(255, 255, 255, 0.92);
366
+ color: #687791;
367
+ font-size: 0.86rem;
368
+ text-decoration: none;
369
+ }
370
+
371
+ .copy-inline {
372
+ position: relative;
373
+ gap: 8px;
291
374
  cursor: pointer;
375
+ transition:
376
+ border-color 140ms ease,
377
+ background 140ms ease,
378
+ color 140ms ease,
379
+ box-shadow 140ms ease;
292
380
  }
293
381
 
294
- .copy-inline:hover code,
295
- .copy-inline:focus-visible code {
296
- text-decoration: underline;
297
- text-underline-offset: 0.14em;
382
+ .copy-inline-label {
383
+ transition: opacity 140ms ease, transform 140ms ease;
298
384
  }
299
385
 
300
- .meta-grid {
386
+ .copy-inline-feedback {
387
+ color: #8a6b1b;
388
+ font-size: 0.79rem;
389
+ font-weight: 700;
390
+ letter-spacing: 0.02em;
391
+ opacity: 0;
392
+ transform: translateY(1px);
393
+ transition: opacity 140ms ease, transform 140ms ease;
394
+ pointer-events: none;
395
+ }
396
+
397
+ .copy-inline[data-state="done"] {
398
+ border-color: rgba(219, 193, 122, 0.96);
399
+ background: rgba(219, 193, 122, 0.18);
400
+ color: #5f6e86;
401
+ box-shadow: 0 8px 18px rgba(138, 107, 27, 0.08);
402
+ }
403
+
404
+ .copy-inline[data-state="done"] .copy-inline-feedback {
405
+ opacity: 1;
406
+ transform: translateY(0);
407
+ }
408
+
409
+ .copy-inline[data-state="done"] .copy-inline-label {
410
+ opacity: 0.82;
411
+ }
412
+
413
+ .copy-inline[data-state="error"] {
414
+ border-color: rgba(214, 107, 107, 0.35);
415
+ background: rgba(191, 38, 38, 0.08);
416
+ }
417
+
418
+ .copy-inline[data-state="error"] .copy-inline-feedback {
419
+ opacity: 1;
420
+ transform: translateY(0);
421
+ color: #a14444;
422
+ }
423
+
424
+ .preview {
425
+ width: 100%;
426
+ height: 100%;
427
+ object-fit: cover;
428
+ object-position: top center;
429
+ }
430
+
431
+ .preview-empty {
432
+ display: flex;
433
+ align-items: center;
434
+ justify-content: center;
435
+ color: #8d99ae;
436
+ }
437
+
438
+ .discover-media-modal-backdrop {
439
+ position: fixed;
440
+ inset: 0;
441
+ z-index: 60;
442
+ display: flex;
443
+ align-items: center;
444
+ justify-content: center;
445
+ padding: 24px;
446
+ background: rgba(28, 34, 45, 0.76);
447
+ backdrop-filter: blur(18px);
448
+ }
449
+
450
+ .discover-media-modal {
301
451
  display: grid;
302
- grid-template-columns: repeat(3, minmax(0, 1fr));
452
+ grid-template-rows: auto minmax(0, 1fr);
303
453
  gap: 14px;
304
- margin: 0;
454
+ width: min(1180px, 100%);
455
+ max-height: calc(100dvh - 48px);
456
+ padding: 16px;
457
+ border: 1px solid rgba(255, 255, 255, 0.28);
458
+ border-radius: 24px;
459
+ background: rgba(255, 251, 245, 0.96);
460
+ box-shadow: 0 28px 80px rgba(5, 10, 20, 0.34);
305
461
  }
306
462
 
307
- .meta-grid div {
308
- padding-top: 12px;
309
- border-top: 1px solid var(--line);
463
+ .discover-media-modal-head {
464
+ display: grid;
465
+ grid-template-columns: minmax(0, 1fr) 44px;
466
+ align-items: center;
467
+ gap: 12px;
310
468
  }
311
469
 
312
- dt {
313
- margin-bottom: 8px;
314
- color: var(--muted);
315
- font-size: 11px;
316
- letter-spacing: 0.18em;
317
- text-transform: uppercase;
470
+ .discover-media-modal-head h2 {
471
+ min-width: 0;
472
+ overflow: hidden;
473
+ color: #283244;
474
+ font-size: 1.05rem;
475
+ line-height: 1.15;
476
+ text-overflow: ellipsis;
477
+ white-space: nowrap;
318
478
  }
319
479
 
320
- dd {
321
- margin: 0;
322
- line-height: 1.5;
323
- overflow-wrap: anywhere;
480
+ .discover-media-modal-close {
481
+ width: 44px;
482
+ min-width: 44px;
483
+ height: 44px;
484
+ min-height: 44px;
485
+ padding: 0;
486
+ border-color: rgba(209, 219, 233, 0.96);
487
+ background: rgba(255, 255, 255, 0.9);
488
+ color: #53627c;
324
489
  }
325
490
 
326
- code {
327
- font-family: "SFMono-Regular", Menlo, Consolas, monospace;
328
- font-size: 0.92em;
491
+ .discover-media-modal-close svg {
492
+ width: 20px;
493
+ height: 20px;
329
494
  }
330
495
 
331
- .viral-block p {
332
- margin: 8px 0 0;
333
- color: var(--ink);
334
- line-height: 1.6;
496
+ .discover-media-modal-stage {
497
+ display: flex;
498
+ align-items: center;
499
+ justify-content: center;
500
+ min-height: 0;
501
+ overflow: hidden;
502
+ border-radius: 18px;
503
+ background: #111827;
504
+ }
505
+
506
+ .discover-media-modal-stage img,
507
+ .discover-media-modal-stage video {
508
+ display: block;
509
+ width: auto;
510
+ height: auto;
511
+ max-width: 100%;
512
+ max-height: calc(100dvh - 154px);
513
+ object-fit: contain;
335
514
  }
336
515
 
337
516
  .empty {
338
517
  display: none;
339
- padding: 28px 24px;
340
- color: var(--muted);
341
518
  }
342
519
 
343
520
  .empty[data-visible="true"] {
344
521
  display: block;
345
522
  }
346
523
 
347
- @media (max-width: 860px) {
348
- main {
349
- width: min(100vw - 20px, 1180px);
350
- padding-top: 20px;
524
+ @media (max-width: 1180px) {
525
+ .discover-card {
526
+ grid-template-columns: minmax(200px, 300px) minmax(0, 1fr);
527
+ gap: 20px;
528
+ padding: 24px;
529
+ }
530
+
531
+ .discover-shell {
532
+ grid-template-columns: 320px minmax(0, 1fr);
533
+ }
534
+
535
+ .discover-card-media {
536
+ min-height: 240px;
537
+ }
538
+
539
+ .discover-results-scroll {
540
+ max-height: none;
541
+ }
542
+ }
543
+
544
+ @media (min-width: 768px) and (max-width: 980px) {
545
+ .discover-shell {
546
+ grid-template-columns: 300px minmax(0, 1fr);
547
+ }
548
+
549
+ .discover-sidebar {
550
+ padding: 22px;
551
+ }
552
+
553
+ .discover-card {
554
+ grid-template-columns: 1fr;
555
+ }
556
+
557
+ .discover-card-media {
558
+ min-height: 0;
559
+ aspect-ratio: 16 / 11;
560
+ }
561
+
562
+ .discover-card-head {
563
+ display: grid;
564
+ grid-template-columns: minmax(0, 1fr);
565
+ }
566
+
567
+ .discover-card-actions {
568
+ justify-content: start;
569
+ }
570
+ }
571
+
572
+ @media (max-width: 767px) {
573
+ .discover-frame,
574
+ .discover-frame .frame-body,
575
+ .discover-shell,
576
+ .discover-results,
577
+ .discover-results-scroll {
578
+ min-height: auto;
579
+ height: auto;
580
+ overflow: visible;
581
+ }
582
+
583
+ .discover-frame .frame-body {
584
+ overflow: visible;
585
+ padding-top: 10px;
586
+ padding-bottom: 4px;
587
+ }
588
+
589
+ .discover-shell {
590
+ display: grid;
591
+ min-width: 0;
592
+ grid-template-columns: 1fr;
593
+ border-radius: 24px;
594
+ overflow: visible;
595
+ }
596
+
597
+ .discover-sidebar,
598
+ .discover-results {
599
+ padding: 14px;
600
+ }
601
+
602
+ .discover-sidebar {
603
+ gap: 14px;
604
+ border-right: 0;
605
+ border-bottom: 1px solid rgba(209, 219, 233, 0.8);
606
+ border-radius: 24px 24px 0 0;
607
+ }
608
+
609
+ .discover-filter-panel {
610
+ display: grid;
611
+ gap: 14px;
612
+ }
613
+
614
+ .discover-filter-panel > summary {
615
+ display: flex;
616
+ align-items: center;
617
+ justify-content: space-between;
618
+ gap: 12px;
619
+ min-height: 54px;
620
+ padding: 0 16px;
621
+ border: 1px solid rgba(209, 219, 233, 0.96);
622
+ border-radius: 18px;
623
+ background: rgba(255, 255, 255, 0.9);
624
+ color: #53627c;
625
+ cursor: pointer;
626
+ list-style: none;
627
+ font-size: 0.88rem;
628
+ font-weight: 800;
629
+ letter-spacing: 0.16em;
630
+ text-transform: uppercase;
631
+ }
632
+
633
+ .discover-filter-panel > summary::-webkit-details-marker {
634
+ display: none;
635
+ }
636
+
637
+ .discover-filter-panel > summary::after {
638
+ content: "";
639
+ width: 10px;
640
+ height: 10px;
641
+ border-right: 2px solid currentColor;
642
+ border-bottom: 2px solid currentColor;
643
+ transform: rotate(45deg) translateY(-2px);
644
+ transition: transform 140ms ease;
645
+ }
646
+
647
+ .discover-filter-panel[open] > summary::after {
648
+ transform: rotate(225deg) translateY(-1px);
649
+ }
650
+
651
+ .discover-filter-panel:not([open]) > .discover-filter-panel-body {
652
+ display: none;
653
+ }
654
+
655
+ .discover-filter-panel-body {
656
+ gap: 14px;
657
+ }
658
+
659
+ .discover-filter-block {
660
+ display: none;
351
661
  }
352
662
 
353
- .search-row,
354
- .row,
355
- .meta-grid {
663
+ .discover-filter-group {
664
+ gap: 8px;
665
+ }
666
+
667
+ .bookmarks-row {
668
+ min-height: 52px;
669
+ padding: 0 14px;
670
+ }
671
+
672
+ .discover-results-scroll {
673
+ gap: 14px;
674
+ padding-right: 0;
675
+ }
676
+
677
+ .discover-card {
356
678
  grid-template-columns: 1fr;
679
+ gap: 16px;
680
+ padding: 14px;
681
+ border-radius: 22px;
682
+ }
683
+
684
+ .discover-card-media {
685
+ min-height: 0;
686
+ max-height: none;
687
+ aspect-ratio: 16 / 11;
688
+ border-radius: 20px;
689
+ }
690
+
691
+ .discover-card-media-affordance {
692
+ opacity: 1;
693
+ transform: none;
694
+ }
695
+
696
+ .discover-card-copy {
697
+ gap: 16px;
698
+ }
699
+
700
+ .discover-card-head {
701
+ display: grid;
702
+ grid-template-columns: minmax(0, 1fr);
703
+ gap: 14px;
704
+ }
705
+
706
+ .discover-card-title-wrap h2 {
707
+ font-size: 1.55rem;
708
+ line-height: 0.96;
357
709
  }
358
710
 
359
- .row {
360
- gap: 18px;
361
- padding: 18px;
362
- }
363
-
364
- .meta-line {
365
- flex-direction: column;
366
- }
367
- }
368
- </style>
369
- </head>
370
- <body>
371
- <main>
372
- <section class="shell">
373
- <header class="topbar">
374
- <div class="topline">
375
- <span class="eyebrow">Vidfarm</span>
376
- ${accountLink}
377
- </div>
378
- <h1>Approved templates</h1>
379
- <p class="subcopy">Simple index of approved templates with preview media, viral DNA, exact template IDs, and one-click SKILL copy.</p>
380
- <div class="search-row">
381
- <input id="search" type="search" placeholder="Quicksearch: template_id, title, slug_id" autocomplete="off" />
382
- <div class="count" id="count">${input.templates.length} visible</div>
383
- </div>
384
- </header>
385
- <ul class="list" id="template-list">${rows}</ul>
386
- <div class="empty" id="empty-state">No approved templates match that search.</div>
387
- </section>
388
- </main>
389
- <script type="application/json" id="homepage-boot">${boot}</script>
390
- <script>
391
- const boot = JSON.parse(document.getElementById("homepage-boot").textContent || "{}");
392
- const searchInput = document.getElementById("search");
393
- const rows = Array.from(document.querySelectorAll(".row"));
394
- const count = document.getElementById("count");
395
- const emptyState = document.getElementById("empty-state");
396
- const lazyVideos = Array.from(document.querySelectorAll("[data-lazy-video]"));
397
-
398
- const updateFilter = () => {
399
- const query = (searchInput.value || "").trim().toLowerCase();
400
- let visibleCount = 0;
401
- for (const row of rows) {
402
- const searchText = row.getAttribute("data-search") || "";
403
- const visible = !query || searchText.includes(query);
404
- row.hidden = !visible;
405
- if (visible) {
406
- visibleCount += 1;
407
- }
408
- }
409
- count.textContent = visibleCount + " visible";
410
- emptyState.dataset.visible = visibleCount === 0 ? "true" : "false";
411
- };
412
-
413
- searchInput.addEventListener("input", updateFilter);
414
-
415
- const loadVideo = (video) => {
416
- const src = video.getAttribute("data-src");
417
- if (!src || video.getAttribute("src")) {
418
- return;
419
- }
420
- video.setAttribute("src", src);
421
- video.load();
422
- };
423
-
424
- if ("IntersectionObserver" in window) {
425
- const observer = new IntersectionObserver((entries) => {
426
- for (const entry of entries) {
427
- if (!entry.isIntersecting) {
428
- continue;
429
- }
430
- loadVideo(entry.target);
431
- observer.unobserve(entry.target);
432
- }
433
- }, {
434
- rootMargin: "240px 0px"
435
- });
436
-
437
- for (const video of lazyVideos) {
438
- observer.observe(video);
439
- }
440
- } else {
441
- for (const video of lazyVideos) {
442
- loadVideo(video);
443
- }
444
- }
445
-
446
- for (const button of document.querySelectorAll("[data-copy-text]")) {
447
- button.addEventListener("click", async () => {
448
- const text = button.getAttribute("data-copy-text") || "";
449
- const defaultLabel = button.getAttribute("data-default-label") || "";
450
- if (!text) {
451
- button.textContent = "Missing";
452
- button.dataset.state = "done";
453
- return;
454
- }
455
-
456
- try {
457
- await navigator.clipboard.writeText(text);
458
- button.textContent = "Copied";
459
- } catch {
460
- button.textContent = "Clipboard blocked";
461
- }
462
-
463
- button.dataset.state = "done";
464
- window.setTimeout(() => {
465
- button.textContent = defaultLabel;
466
- button.dataset.state = "";
467
- }, 1600);
468
- });
469
- }
470
- </script>
471
- </body>
472
- </html>`;
711
+ .discover-card-meta {
712
+ margin-top: 8px;
713
+ font-size: 0.86rem;
714
+ }
715
+
716
+ .discover-card-actions {
717
+ display: grid;
718
+ grid-template-columns: 52px minmax(0, 1fr);
719
+ gap: 10px;
720
+ width: 100%;
721
+ }
722
+
723
+ .bookmark-button {
724
+ width: 52px;
725
+ min-width: 52px;
726
+ height: 52px;
727
+ min-height: 52px;
728
+ }
729
+
730
+ .cta-button {
731
+ width: 100%;
732
+ min-width: 0;
733
+ height: 52px;
734
+ padding: 0 18px;
735
+ }
736
+
737
+ .discover-card-body p {
738
+ font-size: 0.96rem;
739
+ line-height: 1.58;
740
+ }
741
+
742
+ .discover-card-tags {
743
+ gap: 8px;
744
+ padding-top: 14px;
745
+ }
746
+
747
+ .pill-tag {
748
+ max-width: 100%;
749
+ }
750
+
751
+ .copy-inline {
752
+ min-width: 0;
753
+ }
754
+
755
+ .copy-inline-label {
756
+ min-width: 0;
757
+ overflow: hidden;
758
+ text-overflow: ellipsis;
759
+ white-space: nowrap;
760
+ }
761
+
762
+ .discover-count {
763
+ position: static;
764
+ justify-self: start;
765
+ padding-bottom: 0;
766
+ background: transparent;
767
+ }
768
+
769
+ .search-field input {
770
+ min-height: 52px;
771
+ font-size: 16px;
772
+ }
773
+
774
+ .discover-media-modal-backdrop {
775
+ align-items: stretch;
776
+ padding: 12px;
777
+ }
778
+
779
+ .discover-media-modal {
780
+ width: 100%;
781
+ max-height: calc(100dvh - 24px);
782
+ padding: 12px;
783
+ border-radius: 20px;
784
+ }
785
+
786
+ .discover-media-modal-stage {
787
+ border-radius: 14px;
788
+ }
789
+
790
+ .discover-media-modal-stage img,
791
+ .discover-media-modal-stage video {
792
+ max-height: calc(100dvh - 126px);
793
+ }
794
+ }
795
+ `
796
+ });
473
797
  }