Skip to main content

max / makenotwork

11.6 KB · 227 lines History Blame Raw
1 {%- import "partials/_ui.html" as ui -%}
2 <div class="tab-docs"><a href="/docs/items">Docs: Items &rarr;</a></div>
3
4 <div class="content-header">
5 <h2 class="subsection-title">Items</h2>
6 <a href="/dashboard/project/{{ project_slug }}/new-item" class="btn-primary">New Item</a>
7 </div>
8
9 {% if items.is_empty() %}
10 <div class="empty-state empty-state--lg">
11 <p class="mb-4">No items in this project yet. Add your first item to start publishing.</p>
12 <a href="/dashboard/project/{{ project_slug }}/new-item" class="btn-primary">Add First Item</a>
13 <p class="form-hint mt-5">After creating an item, set its pricing and publish it to make it available to fans.</p>
14 </div>
15 {% else %}
16 <div class="content-filters">
17 <input type="text" id="content-search" placeholder="Search items..." data-input="filterContentTable"
18 class="content-filter-search">
19 <select id="content-filter-status" data-change="filterContentTable" class="content-filter-select">
20 <option value="">All statuses</option>
21 <option value="Active">Active</option>
22 <option value="Draft">Draft</option>
23 </select>
24 <select id="content-filter-type" data-change="filterContentTable" class="content-filter-select">
25 <option value="">All types</option>
26 {% for item in items %}<option value="{{ item.item_type }}" class="content-type-opt">{{ item.item_type }}</option>{% endfor %}
27 </select>
28 </div>
29 <div id="bulk-action-bar" class="bulk-action-bar" data-active="false">
30 <span id="bulk-count" class="bulk-count">0 selected</span>
31 <button class="btn-secondary small" data-action="bulkAction" data-arg="publish" disabled>Publish</button>
32 <button class="btn-secondary small" data-action="bulkAction" data-arg="unpublish" disabled>Unpublish</button>
33 <button class="btn-secondary small" data-action="showBulkPrice" disabled id="bulk-price-btn">Set Price</button>
34 <button class="btn-secondary small" data-action="showBulkTag" disabled id="bulk-tag-btn">Add Tag</button>
35 <button class="btn-secondary small danger-text" data-action="bulkAction" data-arg="delete" disabled>Delete</button>
36 <button class="btn-secondary small bulk-deselect" data-action="deselectAll" disabled>Deselect</button>
37 </div>
38 <div id="bulk-price-form" class="bulk-form hidden">
39 <div class="bulk-form-row">
40 <div>
41 <label class="bulk-form-label">New price ($)</label>
42 <input type="number" id="bulk-price-input" min="0" step="0.01" placeholder="0.00" class="bulk-form-input input--xs w-120">
43 </div>
44 <button class="btn-primary small" data-action="submitBulkPrice">Apply</button>
45 <button class="btn-secondary small" data-action="hide" data-target="bulk-price-form">Cancel</button>
46 </div>
47 <p class="form-hint mt-2">Enter 0 to make items free.</p>
48 </div>
49 <div id="bulk-tag-form" class="bulk-form hidden">
50 <div class="bulk-form-row">
51 <div>
52 <label class="bulk-form-label">Tag slug</label>
53 <input type="text" id="bulk-tag-input" placeholder="e.g. audio.genre.ambient" class="bulk-form-input input--xs w-260">
54 </div>
55 <button class="btn-primary small" data-action="submitBulkTag">Apply</button>
56 <button class="btn-secondary small" data-action="hide" data-target="bulk-tag-form">Cancel</button>
57 </div>
58 <p class="form-hint mt-2">Use dot-notation: type.category.value</p>
59 </div>
60 <table class="data-table">
61 <thead>
62 <tr>
63 <th class="col-3"><input type="checkbox" id="select-all" data-change="toggleSelectAllFromEl"></th>
64 <th class="col-5">#</th>
65 <th class="col-32 sortable-th" data-action="sortContent" data-arg="2" data-arg2="text" title="Sort by title">Item <span class="sort-arrow" data-col="2"></span></th>
66 <th class="col-12 sortable-th" data-action="sortContent" data-arg="3" data-arg2="text" title="Sort by type">Type <span class="sort-arrow" data-col="3"></span></th>
67 <th class="col-10 sortable-th" data-action="sortContent" data-arg="4" data-arg2="money" title="Sort by price">Price <span class="sort-arrow" data-col="4"></span></th>
68 <th class="col-10 sortable-th" data-action="sortContent" data-arg="5" data-arg2="num" title="Sort by sales">Sales <span class="sort-arrow" data-col="5"></span></th>
69 <th class="col-10 sortable-th" data-action="sortContent" data-arg="6" data-arg2="money" title="Sort by revenue">Revenue <span class="sort-arrow" data-col="6"></span></th>
70 <th class="col-8 sortable-th" data-action="sortContent" data-arg="7" data-arg2="text" title="Sort by status">Status <span class="sort-arrow" data-col="7"></span></th>
71 <th class="col-10">Actions</th>
72 </tr>
73 </thead>
74 <tbody>
75 {% for item in items %}
76 <tr>
77 <td><input type="checkbox" class="bulk-check" value="{{ item.id }}" data-change="updateBulkUI"></td>
78 <td class="nowrap">
79 {{ item.position }}
80 {% if !loop.first %}
81 <button class="btn-secondary order-arrow-btn"
82 hx-put="/api/items/{{ item.id }}/move" hx-vals='{"direction":"up"}'
83 hx-swap="none"
84 data-hx-get="/dashboard/project/{{ project_slug }}/tabs/content" data-hx-target="#tab-content">&#9650;</button>
85 {% endif %}
86 {% if !loop.last %}
87 <button class="btn-secondary order-arrow-btn"
88 hx-put="/api/items/{{ item.id }}/move" hx-vals='{"direction":"down"}'
89 hx-swap="none"
90 data-hx-get="/dashboard/project/{{ project_slug }}/tabs/content" data-hx-target="#tab-content">&#9660;</button>
91 {% endif %}
92 </td>
93 <td>
94 <span id="item-title-{{ item.id }}">
95 {% if !item.children.is_empty() %}
96 <button class="bundle-toggle" data-action="toggleBundleChildren" data-arg="{{ item.id }}" title="Toggle bundle contents">&#9654;</button>
97 {% endif %}
98 <a href="/dashboard/item/{{ item.id }}" class="fw-bold">{{ item.title }}</a>
99 {% if item.is_unlisted %}<span class="badge badge--inline-tiny">Unlisted</span>{% endif %}
100 </span>
101 </td>
102 <td>{{ item.item_type }}{% if !item.children.is_empty() %} <span class="dimmed text-xs">({{ item.children.len() }})</span>{% endif %}</td>
103 <td>{{ item.price }}</td>
104 <td>{{ item.sales }}</td>
105 <td>{{ item.revenue }}</td>
106 <td><span class="badge {{ item.status|lowercase }}">{{ item.status }}</span></td>
107 <td>
108 <div class="item-actions">
109 {% if item.status == "Draft" %}
110 <a href="/dashboard/project/{{ project_slug }}/new-item/{{ item.id }}/step/details" class="btn-primary small">Continue</a>
111 <button class="btn-secondary small" data-action="quickPublish" data-arg="{{ item.id }}">Publish</button>
112 {% else %}
113 <a href="/i/{{ item.id }}" class="btn-secondary small">View</a>
114 {% endif %}
115 <a href="/dashboard/item/{{ item.id }}" class="btn-secondary small">Edit</a>
116 <button class="btn-secondary small"
117 data-action="inlineRename" data-arg="{{ item.id }}">Rename</button>
118 </div>
119 </td>
120 </tr>
121 {% for child in item.children %}
122 <tr class="bundle-child bundle-child-{{ item.id }} hidden">
123 <td><input type="checkbox" class="bulk-check" value="{{ child.id }}" data-change="updateBulkUI"></td>
124 <td></td>
125 <td class="bundle-child-cell">
126 <span id="item-title-{{ child.id }}" class="bundle-child-title">
127 <span class="bundle-child-arrow">&#8627;</span>
128 <a href="/dashboard/item/{{ child.id }}">{{ child.title }}</a>
129 {% if child.is_unlisted %}<span class="badge badge--inline-tiny">Unlisted</span>{% endif %}
130 </span>
131 </td>
132 <td class="muted">{{ child.item_type }}</td>
133 <td class="muted">{{ child.price }}</td>
134 <td class="muted">{{ child.sales }}</td>
135 <td class="muted">{{ child.revenue }}</td>
136 <td><span class="badge {{ child.status|lowercase }}">{{ child.status }}</span></td>
137 <td>
138 <div class="item-actions">
139 <a href="/dashboard/item/{{ child.id }}" class="btn-secondary small">Edit</a>
140 </div>
141 </td>
142 </tr>
143 {% endfor %}
144 {% endfor %}
145 </tbody>
146 </table>
147 {% endif %}
148
149 {% if !deleted_items.is_empty() %}
150 <details class="deleted-items-details">
151 <summary class="deleted-items-summary">Recently Deleted ({{ deleted_items.len() }})</summary>
152 <p class="form-hint mt-2">Deleted items are permanently removed after 7 days.</p>
153 <table class="data-table mt-3">
154 <thead>
155 <tr>
156 <th>Title</th>
157 <th>Deleted</th>
158 <th></th>
159 </tr>
160 </thead>
161 <tbody>
162 {% for item in deleted_items %}
163 <tr id="deleted-{{ item.id }}">
164 <td class="dimmed">{{ item.title }}</td>
165 <td class="dimmed">{{ item.deleted_at }}</td>
166 <td>
167 <button class="btn-secondary small"
168 hx-post="/api/items/{{ item.id }}/restore"
169 hx-swap="none"
170 data-hx-get="/dashboard/project/{{ project_slug }}/tabs/content" data-hx-target="#tab-content">Restore</button>
171 </td>
172 </tr>
173 {% endfor %}
174 </tbody>
175 </table>
176 </details>
177 {% endif %}
178
179 <div id="tab-project-content-cfg" hidden data-project-slug="{{ project_slug }}"></div>
180 <script src="/static/tab-project-content.js?v=0623"></script>
181
182 <hr class="section-divider">
183
184 <div class="content-header">
185 <h2 class="subsection-title">Blog Posts</h2>
186 <a href="/dashboard/project/{{ project_slug }}/blog/new">
187 <button class="btn-primary">New Post</button>
188 </a>
189 </div>
190
191 {% if posts.is_empty() %}
192 {% call ui::empty_state_compact("No blog posts yet. Share updates, release notes, or stories with your audience.") %}{% endcall %}
193 {% else %}
194 <table class="data-table">
195 <thead>
196 <tr>
197 <th class="col-45">Title</th>
198 <th class="col-15">Status</th>
199 <th class="col-20">Published</th>
200 <th class="col-20">Actions</th>
201 </tr>
202 </thead>
203 <tbody>
204 {% for post in posts %}
205 <tr id="post-row-{{ post.id }}">
206 <td>
207 <a href="/p/{{ project_slug }}/blog/{{ post.slug }}" class="fw-bold">{{ post.title }}</a>
208 </td>
209 <td><span class="badge {{ post.status|lowercase }}">{{ post.status }}</span></td>
210 <td>{{ post.published_at }}</td>
211 <td>
212 <div class="item-actions">
213 <a href="/p/{{ project_slug }}/blog/{{ post.slug }}" class="btn-secondary small">View</a>
214 <a href="/dashboard/project/{{ project_slug }}/blog/new?post={{ post.id }}" class="btn-secondary small">Edit</a>
215 <button class="btn-secondary small danger-text"
216 hx-delete="/api/blog/{{ post.id }}"
217 hx-target="#post-row-{{ post.id }}"
218 hx-swap="outerHTML"
219 hx-confirm="Delete this blog post?">Delete</button>
220 </div>
221 </td>
222 </tr>
223 {% endfor %}
224 </tbody>
225 </table>
226 {% endif %}
227