Skip to main content

max / makenotwork

15.9 KB · 313 lines History Blame Raw
1 <div class="tab-docs"><a href="/docs/getting-started">Docs: Getting Started &rarr;</a></div>
2
3 {% if can_create_projects %}
4 <div class="creator-tab-section creator-tab-section--centered">
5 <h2 class="creator-h2">You have creator access</h2>
6 <p class="muted mb-5">You can create projects and publish content.</p>
7 <button class="btn-primary"
8 hx-get="/dashboard/tabs/projects"
9 hx-target="#tab-content"
10 hx-swap="innerHTML"
11 onclick="document.getElementById('tab-projects').click()">Go to Projects</button>
12 </div>
13
14 <div class="creator-tab-section creator-tab-section--no-top">
15 <h2 class="creator-h2 creator-h2--sm mb-3">Creator Plan</h2>
16 {% if let Some(label) = creator_tier_label %}
17 <div class="creator-plan-box mb-4">
18 <div class="creator-plan-head">
19 <span class="creator-plan-name">{{ label }}</span>
20 {% if let Some(status) = creator_sub_status %}
21 {% if status == "active" %}
22 <span class="badge active">Active</span>
23 {% else if status == "past_due" %}
24 <span class="badge pending">Past Due</span>
25 {% else %}
26 <span class="badge">{{ status }}</span>
27 {% endif %}
28 {% endif %}
29 {% if is_founder_locked %}
30 <span class="badge badge--founder-locked" title="Founder pricing is locked in for the life of this account.">Founder · locked for life</span>
31 {% else if is_founder && founder_window_open %}
32 <span class="badge badge--founder-pending" title="Founder pricing applies while the window is open. Stay subscribed until the window closes to lock it in for life.">Founder · pending lock-in</span>
33 {% endif %}
34 </div>
35 {% if let Some(period_end) = creator_period_end %}
36 <p class="muted text-sm">Current period ends {{ period_end }}</p>
37 {% endif %}
38 <p class="muted text-sm mt-2">{{ storage_total }} of {{ storage_max }} storage used ({{ storage_pct }}%). <a href="/docs/guide/tiers" class="muted">Plan limits &rarr;</a></p>
39 </div>
40 {% else %}
41 <p class="muted text-sm mb-4">
42 No active plan. During alpha, all creator features are available without a membership.
43 </p>
44 {% if founder_window_open || is_founder_locked %}
45 <div class="founder-callout mb-4">
46 {% if is_founder_locked %}
47 <p class="m-0 text-sm"><strong>Your founder pricing is locked in.</strong> The rates below show the founder rate for each tier: you can subscribe (or upgrade later) at this rate for the life of your account.</p>
48 {% else %}
49 <p class="m-0 text-sm"><strong>Founder pricing window is open.</strong> Subscribe now to lock in half-price creator memberships for life. Window closes at 1,000 creators or exit-beta, whichever first. <a href="/docs/pricing">How it works &rarr;</a></p>
50 {% endif %}
51 </div>
52 {% endif %}
53 {% if creator_tiers_configured %}
54 {% let show_founder_rate = founder_window_open || is_founder_locked %}
55 <div class="creator-tier-grid mb-4">
56 {% for card in tier_cards %}
57 <div class="creator-tier-card">
58 <div class="creator-tier-name"><a href="/docs/guide/tiers" class="creator-tier-link">{{ card.label }}</a></div>
59 {% if show_founder_rate %}
60 <div class="meta mb-2"><strong>${{ card.founder_monthly }}/mo</strong> <span class="strike-dim">${{ card.standard_monthly }}</span></div>
61 <div class="meta creator-tier-sub mb-2">or ${{ card.founder_annual }}/yr (10% off)</div>
62 {% else %}
63 <div class="meta mb-2">${{ card.standard_monthly }}/mo</div>
64 <div class="meta creator-tier-sub mb-2">or ${{ card.standard_annual }}/yr (10% off)</div>
65 {% endif %}
66 <div class="meta creator-tier-storage mb-3">{{ card.storage }}</div>
67 <div class="creator-tier-buttons">
68 <form method="post" action="/stripe/creator-tier" class="m-0">
69 {% if let Some(token) = csrf_token %}<input type="hidden" name="_csrf" value="{{ token }}">{% endif %}
70 <input type="hidden" name="tier" value="{{ card.key }}">
71 <input type="hidden" name="interval" value="monthly">
72 <button type="submit" class="btn-primary creator-tier-btn" data-loading-text="Redirecting to Stripe...">Monthly</button>
73 </form>
74 <form method="post" action="/stripe/creator-tier" class="m-0">
75 {% if let Some(token) = csrf_token %}<input type="hidden" name="_csrf" value="{{ token }}">{% endif %}
76 <input type="hidden" name="tier" value="{{ card.key }}">
77 <input type="hidden" name="interval" value="annual">
78 <button type="submit" class="btn-secondary creator-tier-btn" data-loading-text="Redirecting to Stripe...">Annual (save 10%)</button>
79 </form>
80 </div>
81 </div>
82 {% endfor %}
83 </div>
84 <p class="text-center mb-4"><a href="/docs/guide/tiers" class="text-sm">Full tier details &rarr;</a></p>
85 <p class="text-center text-sm muted mb-4">
86 Upgrades take effect immediately and are prorated. Downgrades take effect at the next billing period; if you're over the new tier's storage cap, new uploads stay blocked until you're under it, but your existing content stays published either way.
87 </p>
88 {% endif %}
89 {% endif %}
90 </div>
91
92 <div class="section-group-label creator-section-label">Usage</div>
93
94 <details class="form-section creator-form-section">
95 <summary><h2 class="creator-h2 creator-h2--sm">Storage ({{ storage_total }} / {{ storage_max }})</h2></summary>
96 <div class="storage-box mb-4">
97 <div class="storage-row">
98 <span>{{ storage_total }} of {{ storage_max }} used</span>
99 <span class="muted">{{ storage_pct }}%</span>
100 </div>
101 <div class="storage-track">
102 <div class="storage-fill {% if storage_pct >= 90 %}storage-fill--full{% endif %}" style="width: {{ storage_pct }}%"></div>
103 </div>
104 <div class="storage-breakdown">
105 <span class="muted">Audio: {{ storage_audio }}</span>
106 <span class="muted">Covers: {{ storage_covers }}</span>
107 <span class="muted">Downloads: {{ storage_downloads }}</span>
108 <span class="muted">Clips: {{ storage_insertions }}</span>
109 <span class="muted">Video: {{ storage_video }}</span>
110 <span class="muted">Media: {{ storage_media }}</span>
111 </div>
112 </div>
113 </details>
114
115 <div class="section-group-label creator-section-label">Outreach</div>
116
117 <details class="form-section creator-form-section">
118 <summary><h2 class="creator-h2 creator-h2--sm">Broadcast to Followers</h2></summary>
119 <div class="broadcast-head mb-4">
120 <p class="text-sm muted m-0 broadcast-desc">
121 Send a plain-text announcement to everyone who follows you or your projects.
122 Limited to one broadcast per 24 hours.
123 {% if follower_count > 0 %}
124 <strong>{{ follower_count }}</strong> follower{% if follower_count != 1 %}s{% endif %} will receive this email.
125 {% else %}
126 You don't have any followers yet.
127 {% endif %}
128 </p>
129 {% if follower_count > 0 %}
130 <button class="btn-secondary text-sm broadcast-export nowrap"
131 onclick="this.textContent='Exporting...'; this.disabled=true; var btn=this; fetch('/api/export/followers', {method:'POST', headers: csrfHeaders()}).then(function(r){return r.blob()}).then(function(b){var a=document.createElement('a'); a.href=URL.createObjectURL(b); a.download='followers.csv'; a.click(); btn.textContent='Export CSV'; btn.disabled=false;}).catch(function(){btn.textContent='Export CSV'; btn.disabled=false; showToast('Export failed')});">Export CSV</button>
132 {% endif %}
133 </div>
134 <form hx-post="/api/broadcast" hx-target="#broadcast-result" hx-swap="innerHTML"
135 hx-confirm="Send this broadcast to {{ follower_count }} follower{% if follower_count != 1 %}s{% endif %}?">
136 <div class="form-group">
137 <label for="broadcast-subject">Subject</label>
138 <input type="text" id="broadcast-subject" name="subject" required maxlength="200"
139 placeholder="Subject line for your announcement">
140 </div>
141 <div class="form-group">
142 <label for="broadcast-body">Message</label>
143 <textarea id="broadcast-body" name="body" rows="6" required maxlength="5000"
144 placeholder="Your announcement..."></textarea>
145 </div>
146 <div id="broadcast-result"></div>
147 <button type="submit" class="btn-primary">Send Broadcast</button>
148 </form>
149 </details>
150
151 {% if invites_enabled %}
152 <details class="form-section creator-form-section">
153 <summary><h2 class="creator-h2 creator-h2--sm">Invite Codes</h2></summary>
154 <p class="muted text-sm mb-4">
155 Invite people to Makenotwork. They skip the pitch but still need admin approval.
156 {{ active_invite_count }}/{{ invite_limit }} active.
157 </p>
158
159 {% if active_invite_count < invite_limit %}
160 <div id="invite-result" class="mb-4"></div>
161 <button class="btn-primary mb-5"
162 hx-post="/api/invites/create"
163 hx-target="#invite-result"
164 hx-swap="innerHTML">Generate Invite Code</button>
165 {% else %}
166 <p class="dimmed text-sm mb-5">
167 You have reached the limit of {{ invite_limit }} active codes. Codes free up when redeemed.
168 </p>
169 {% endif %}
170
171 {% if !invite_codes.is_empty() %}
172 <div class="scroll-x">
173 <table class="compact-table" aria-label="Invite codes">
174 <thead>
175 <tr>
176 <th>Code</th>
177 <th>Status</th>
178 <th>Created</th>
179 </tr>
180 </thead>
181 <tbody>
182 {% for code in invite_codes %}
183 <tr>
184 <td class="mono-sm">{{ code.formatted_code }}</td>
185 <td>
186 {% if code.redeemed %}
187 <span class="badge dimmed">Redeemed</span>
188 {% else %}
189 <span class="badge active">Available</span>
190 {% endif %}
191 </td>
192 <td class="text-sm">{{ code.created_at }}</td>
193 </tr>
194 {% endfor %}
195 </tbody>
196 </table>
197 </div>
198 {% endif %}
199 </details>
200 {% endif %}
201
202 {% else %}
203
204 <div class="creator-tab-section">
205 <h2 class="creator-h2">Become a Creator</h2>
206 <p class="creator-intro mb-5">
207 Apply for creator access to start publishing and selling your work.
208 Tell us what you make and which tier fits. Most applications are approved within a few days.
209 </p>
210 </div>
211
212 <hr class="creator-divider">
213
214 {% if let Some(entry) = waitlist_entry %}
215 <div class="creator-tab-section">
216 <h2 class="creator-h2 mb-4">Application Submitted</h2>
217 {% if let Some(pitch_text) = entry.pitch %}
218 <div class="creator-pitch-box mb-4">
219 <div class="meta mb-2">Your pitch</div>
220 <p>{{ pitch_text }}</p>
221 </div>
222 {% else %}
223 <div class="creator-pitch-box mb-4">
224 <p class="muted">You were invited: no pitch required.</p>
225 </div>
226 {% endif %}
227 <div class="muted text-sm">
228 Applied {{ entry.created_at }}
229 {% if entry.status == "pending" %}
230 &middot; Status: <strong>Pending review</strong>
231 {% else if entry.status == "approved" %}
232 &middot; Status: <strong>Approved</strong>
233 {% else %}
234 &middot; Status: {{ entry.status }}
235 {% endif %}
236 </div>
237 <p class="text-sm mt-4">
238 We review applications individually, usually within a few days. You'll get an email when you're approved.
239 </p>
240 </div>
241 {% else %}
242 {% if email_verified %}
243 <div class="creator-tab-section">
244 <h2 class="creator-h2 mb-4">Apply for Creator Access</h2>
245 <p class="mb-5">
246 Tell us what you make and which tier you need. If you have existing work online,
247 link to it: a portfolio, channel, or profile elsewhere helps us review faster.
248 </p>
249 <form hx-post="/api/waitlist/apply"
250 hx-target="closest div"
251 hx-swap="innerHTML"
252 id="waitlist-form">
253 <div class="form-group">
254 <label for="pitch">What do you make?</label>
255 <textarea id="pitch" name="pitch" rows="4"
256 minlength="20" maxlength="500" required
257 placeholder="Briefly describe your work. A link to your portfolio, channel, or existing storefront is helpful."></textarea>
258 <div class="hint">20-500 characters.</div>
259 </div>
260 <div class="form-group">
261 <label for="preferred-tier">Which tier fits?</label>
262 <select id="preferred-tier" name="preferred_tier">
263 <option value="">Not sure yet</option>
264 <option value="basic">Basic (${{ tier_cards[0].standard_monthly }}/mo): text, blogs, newsletters</option>
265 <option value="small_files">Small Files (${{ tier_cards[1].standard_monthly }}/mo): audio, software, plugins</option>
266 <option value="big_files">Big Files (${{ tier_cards[2].standard_monthly }}/mo): video, games, large software</option>
267 <option value="everything">Everything (${{ tier_cards[3].standard_monthly }}/mo): all features, current and future</option>
268 </select>
269 </div>
270 <div class="form-group">
271 <label>
272 <input type="checkbox" id="free-trial" name="free_trial" value="yes"
273 onchange="document.getElementById('trial-details').classList.toggle('hidden', !this.checked);">
274 I'd like to request a free trial
275 </label>
276 </div>
277 <div id="trial-details" class="hidden">
278 <div class="form-group">
279 <label for="trial-length">How long do you need?</label>
280 <select id="trial-length" name="trial_length">
281 <option value="2 weeks">2 weeks</option>
282 <option value="1 month" selected>1 month</option>
283 <option value="2 months">2 months</option>
284 <option value="3 months">3 months</option>
285 </select>
286 </div>
287 <div class="form-group">
288 <label for="trial-reason">What do you want to test?</label>
289 <textarea id="trial-reason" name="trial_reason" rows="3" maxlength="500"
290 placeholder="What feature or workflow are you unsure about? What do you need to try before committing?"></textarea>
291 <div class="hint">Longer trials should have a specific reason: a feature you need to evaluate, a workflow you want to test with real content, etc.</div>
292 </div>
293 </div>
294 <div id="apply-result"></div>
295 <button type="submit" class="btn-primary">Submit Application</button>
296 </form>
297 </div>
298 {% else %}
299 <div class="creator-tab-section creator-tab-section--centered">
300 <h2 class="creator-h2 mb-4">Verify Your Email First</h2>
301 <p class="muted mb-5">
302 You need a verified email address to apply for creator access.
303 </p>
304 <button class="btn-primary"
305 hx-post="/api/resend-verification"
306 hx-target="#verify-result"
307 hx-swap="innerHTML">Resend Verification Email</button>
308 <div id="verify-result" class="mt-4"></div>
309 </div>
310 {% endif %}
311 {% endif %}
312 {% endif %}
313