Skip to main content

max / makenotwork

7.3 KB · 154 lines History Blame Raw
1 <div class="pricing-strategies">
2 <div class="pricing-strategies-title">Pricing strategies</div>
3 <div class="pricing-strategies-grid">
4 <div><strong>Fixed price</strong>: set in the Details tab. Good for finished products.</div>
5 <div><strong>Pay What You Want</strong>: fans choose their price. Set a minimum below.</div>
6 <div><strong>Free + promo codes</strong>: set price to $0, then generate codes for specific access.</div>
7 <div><strong>License keys</strong>: per-seat licensing for software. Works with any pricing model.</div>
8 </div>
9 </div>
10
11 <!-- Pay What You Want -->
12 <div class="content-section">
13 <div class="section-header">
14 <h2 class="subsection-title">Pay What You Want</h2>
15 </div>
16
17 <form hx-put="/api/items/{{ item.id }}"
18 hx-target="#pwyw-save-status"
19 hx-swap="innerHTML"
20 hx-indicator="#pwyw-spinner">
21 <div class="form-group">
22 <label class="checkbox-label">
23 <input type="hidden" name="pwyw_enabled" value="off">
24 <input type="checkbox" name="pwyw_enabled" value="on"
25 {% if item.pwyw_enabled %}checked{% endif %}
26 onchange="document.getElementById('pwyw-settings').classList.toggle('hidden', !this.checked)">
27 Enable pay-what-you-want pricing
28 </label>
29 <p class="form-hint">The item price becomes the suggested amount. Buyers can choose any amount at or above the minimum.</p>
30 </div>
31
32 <div id="pwyw-settings"{% if !item.pwyw_enabled %} class="hidden"{% endif %}>
33 <div class="form-group">
34 <label for="pwyw-min-dollars">Minimum price ($)</label>
35 <input type="number" id="pwyw-min-dollars" step="0.01" min="0" placeholder="0.00">
36 <input type="hidden" id="pwyw-min-cents" name="pwyw_min_cents"
37 value="{% if let Some(min) = item.pwyw_min_cents %}{{ min }}{% endif %}">
38 <p class="form-hint">The lowest amount a buyer can pay. $0 = any amount.</p>
39 </div>
40 </div>
41 <script>
42 (function() {
43 var dollars = document.getElementById('pwyw-min-dollars');
44 var cents = document.getElementById('pwyw-min-cents');
45 if (cents.value) dollars.value = (parseInt(cents.value, 10) / 100).toFixed(2);
46 dollars.addEventListener('input', function() {
47 cents.value = Math.round(parseFloat(this.value || 0) * 100);
48 });
49 })();
50 </script>
51
52 <button class="btn-primary" type="submit">
53 Save PWYW Settings
54 <span id="pwyw-spinner" class="htmx-indicator"> ...</span>
55 </button>
56 <span id="pwyw-save-status"></span>
57 </form>
58 </div>
59
60 <!-- License Terms -->
61 <div class="content-section">
62 <div class="section-header">
63 <h2 class="subsection-title">License Terms</h2>
64 </div>
65
66 <form hx-put="/api/items/{{ item.id }}/license-settings"
67 hx-target="#license-save-status"
68 hx-swap="innerHTML"
69 hx-indicator="#license-spinner">
70 <div class="form-group">
71 <label for="dash-license-preset">License</label>
72 <select id="dash-license-preset" name="license_preset"
73 onchange="document.getElementById('dash-custom-license').classList.toggle('hidden', this.value !== 'custom')">
74 <option value="">None (no license)</option>
75 {% for opt in license_preset_options %}
76 <option value="{{ opt.0 }}"{% if item.license_preset.as_deref() == Some(opt.0) %} selected{% endif %}>{{ opt.1 }}</option>
77 {% endfor %}
78 </select>
79 <p class="form-hint">Displayed on the item page and included with downloads as LICENSE.txt.</p>
80 </div>
81
82 <div id="dash-custom-license"{% if item.license_preset.as_deref() != Some("custom") %} class="hidden"{% endif %}>
83 <div class="form-group">
84 <label for="dash-custom-text">Custom License Text</label>
85 <textarea id="dash-custom-text" name="custom_license_text" rows="6"
86 placeholder="Enter your custom license terms...">{{ item.custom_license_text.as_deref().unwrap_or("") }}</textarea>
87 </div>
88 </div>
89
90 <div class="form-group">
91 <label class="checkbox-label">
92 <input type="checkbox" name="enable_license_keys" value="on"
93 {% if item.enable_license_keys %}checked{% endif %}
94 onchange="document.getElementById('license-keys-section').classList.toggle('hidden', !this.checked)">
95 Enable license keys for this item
96 </label>
97 <p class="form-hint">Buyers receive a unique license key with their purchase. Each key can be activated on a limited number of devices (you choose). Useful for software with per-seat licensing. Works with any pricing model including Pay What You Want.</p>
98 </div>
99
100 <div class="form-group">
101 <label for="default-max-activations">Default max activations per key</label>
102 <input type="number" id="default-max-activations" name="default_max_activations"
103 value="{% if let Some(max) = item.default_max_activations %}{{ max }}{% endif %}"
104 min="1" placeholder="Leave blank for unlimited">
105 <p class="form-hint">How many machines can activate each key. Blank = unlimited.</p>
106 </div>
107
108 <button class="btn-primary" type="submit">
109 Save License Settings
110 <span id="license-spinner" class="htmx-indicator"> ...</span>
111 </button>
112 <span id="license-save-status"></span>
113 </form>
114
115 <div id="license-keys-section" class="license-keys-section{% if !item.enable_license_keys %} hidden{% endif %}">
116 <div class="section-header">
117 <h3>Generated Keys</h3>
118 <form hx-post="/api/items/{{ item.id }}/keys"
119 hx-target="#license-keys-list"
120 hx-swap="outerHTML">
121 <button class="btn-secondary" type="submit">Generate Key</button>
122 </form>
123 </div>
124
125 {% include "partials/item_license_keys.html" %}
126 </div>
127 </div>
128
129 <!-- Promo Codes -->
130 <div class="content-section">
131 <div class="section-header">
132 <h2 class="subsection-title">Promo Codes</h2>
133 </div>
134 <p class="form-hint promo-codes-hint">Generate codes that grant free access to this item. Share them with reviewers, collaborators, or for promotions.</p>
135
136 <form hx-post="/api/promo-codes"
137 hx-target="#promo-codes-list"
138 hx-swap="outerHTML"
139 class="promo-codes-form">
140 <input type="hidden" name="item_id" value="{{ item.id }}">
141 <input type="hidden" name="code_purpose" value="free_access">
142 <div class="promo-codes-row">
143 <input type="number" name="max_uses" min="1" placeholder="Max uses (blank = unlimited)"
144 class="promo-max-uses">
145 <input type="date" name="expires_at" placeholder="Expires (optional)"
146 title="Expiry date (optional)"
147 class="promo-expires">
148 <button class="btn-secondary" type="submit">Generate Code</button>
149 </div>
150 </form>
151
152 {% include "partials/promo_codes_list.html" %}
153 </div>
154