Skip to main content

max / makenotwork

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