Skip to main content

max / makenotwork

11.1 KB · 231 lines History Blame Raw
1 {% extends "base.html" %}
2 {%- import "partials/carousel.html" as carousel -%}
3
4 {% block title %}{{ project.title }} - {{ creator_username }}{% endblock %}
5 {% block body_attrs %} class="padded-page project-page"{% endblock %}
6
7 {% block head %}
8 {# Tier 0 creator theme: primitive-layer override; semantic layer derives from it. #}
9 <style id="creator-theme">{{ theme_css|safe }}</style>
10 <meta property="og:title" content="{{ project.title }} by {{ creator_username }}">
11 <meta property="og:description" content="{{ project.description }}">
12 <meta property="og:type" content="website">
13 <meta property="og:url" content="{{ host_url }}/p/{{ project.slug }}">
14 <link rel="canonical" href="{{ host_url }}/p/{{ project.slug }}">
15 <meta property="og:site_name" content="Makenot.work">
16 {% if project.cover_image_url.is_some() %}<meta name="twitter:card" content="summary_large_image">{% else %}<meta name="twitter:card" content="summary">{% endif %}
17 <meta name="twitter:title" content="{{ project.title }} by {{ creator_username }}">
18 <meta name="twitter:description" content="{{ project.description }}">
19 {% if let Some(img) = project.cover_image_url %}
20 <meta property="og:image" content="{{ img }}">
21 <meta name="twitter:image" content="{{ img }}">
22 {% else %}
23 <meta property="og:image" content="{{ host_url }}/static/images/og-card.png">
24 <meta name="twitter:image" content="{{ host_url }}/static/images/og-card.png">
25 {% endif %}
26 <script type="application/ld+json">
27 {
28 "@context": "https://schema.org",
29 "@type": "CollectionPage",
30 "name": "{{ project.title_json()|safe }}",
31 "description": "{{ project.description_json()|safe }}",
32 "url": "{{ host_url }}/p/{{ project.slug }}",
33 "author": {
34 "@type": "Person",
35 "name": "{{ creator_username }}",
36 "url": "{{ host_url }}/u/{{ creator_username }}"
37 },
38 "numberOfItems": {{ project.item_count }},
39 "isPartOf": {
40 "@type": "WebSite",
41 "name": "Makenot.work",
42 "url": "{{ host_url }}"
43 }
44 }
45 </script>
46 <link rel="alternate" type="application/rss+xml" title="{{ project.title }} - RSS Feed" href="/p/{{ project.slug }}/rss">
47 {% endblock %}
48
49 {% block content %}
50 {% include "partials/site_header.html" %}
51
52 <div class="container">
53 <header class="store-header">
54 {% if let Some(img_url) = project.cover_image_url %}
55 <img src="{{ img_url }}" alt="{{ project.title }}" class="store-cover">
56 {% endif %}
57 <h1 class="store-title">{{ project.title }}<span class="dot">.</span></h1>
58 <div class="store-meta">
59 by <a href="/u/{{ creator_username }}">{{ creator_username }}</a> &middot;
60 <span>{{ project.item_count }} items</span>
61 </div>
62 <p class="store-description">{{ project.description }}</p>
63 <div class="store-actions">
64 {% if is_owner %}
65 <a href="/dashboard/project/{{ project.slug }}" class="btn-secondary">Edit Project</a>
66 {% endif %}
67 {% if session_user.is_some() %}
68 {% if is_following %}
69 <button class="btn-secondary follow-btn is-selected"
70 hx-delete="/api/follow/project/{{ project_id }}"
71 hx-swap="outerHTML">Following ({{ follower_count }})</button>
72 {% else %}
73 <button class="btn-secondary follow-btn"
74 hx-post="/api/follow/project/{{ project_id }}"
75 hx-swap="outerHTML">Follow ({{ follower_count }})</button>
76 {% endif %}
77 {% else if follower_count > 0 %}
78 <span class="follower-count-muted">{{ follower_count }} followers</span>
79 {% endif %}
80 <a href="/p/{{ project.slug }}/rss" class="btn-secondary">RSS Feed</a>
81 {% if has_blog_posts %}
82 <a href="/p/{{ project.slug }}/blog" class="btn-secondary">Blog</a>
83 {% endif %}
84 {% for repo in &git_repos %}
85 <a href="{{ repo.1 }}" class="btn-secondary">Git ({{ repo.0 }})</a>
86 {% endfor %}
87 {% if let Some(url) = community_url %}
88 <a href="{{ url }}" class="btn-secondary">Community</a>
89 {% endif %}
90 {% include "partials/tip_button.html" %}
91 </div>
92 </header>
93
94 {% if !gallery.is_empty() %}
95 <section class="project-gallery">
96 {% call carousel::carousel("project-gallery", gallery) %}{% endcall %}
97 </section>
98 {% endif %}
99
100 {% if !sections.is_empty() %}
101 <section class="project-sections">
102 <div class="section-tabs">
103 {% for section in sections %}
104 <button class="section-tab{% if loop.first %} is-selected{% endif %}"
105 data-tab="section-{{ section.slug }}"
106 data-action="onSwitchSectionTab" data-arg="section-{{ section.slug }}">{{ section.title }}</button>
107 {% endfor %}
108 </div>
109 {% for section in sections %}
110 <div class="section-panel{% if loop.first %} active{% endif %}" id="section-{{ section.slug }}">
111 {{ section.body_html|safe }}
112 </div>
113 {% endfor %}
114 </section>
115 <script src="/static/page-project.js?v=0623" defer></script>
116 {% endif %}
117
118 <section class="items-section">
119 <div class="items-header">
120 <h2 class="section-header">Available Items</h2>
121 <div class="view-controls">
122 <button type="button" class="view-btn" data-view="list" title="List view">|||</button>
123 <button type="button" class="view-btn is-selected" data-view="grid" title="Grid view">:::</button>
124 </div>
125 </div>
126 <div class="items-container items-grid-view" id="items-container">
127 <div class="items-grid">
128 {% for item in items %}
129 <div class="item-card">
130 <a href="{% if item.can_access %}/i/{{ item.id }}{% else %}/purchase/{{ item.id }}{% endif %}" class="item-thumbnail">{{ item.thumbnail }}</a>
131 <div class="item-content">
132 <h3 class="item-title"><a href="{% if item.can_access %}/i/{{ item.id }}{% else %}/purchase/{{ item.id }}{% endif %}">{{ item.title }}</a></h3>
133 <div class="item-meta">{{ item.item_type }}{% if item.bundle_item_count > 0 %} ({{ item.bundle_item_count }} items){% endif %} &middot; {{ item.release_date }}</div>
134 <div class="item-tags">
135 {% for tag in item.tags %}
136 <a href="/discover?tag={{ tag.slug }}" class="tag">{{ tag.name }}</a>
137 {% endfor %}
138 </div>
139 <p class="item-description">{{ item.description }}</p>
140 <div class="item-footer">
141 <div class="item-price">{{ item.price }}</div>
142 <div class="item-stats">{{ item.sales_count }} sales</div>
143 </div>
144 {% if item.can_access %}
145 <a href="/l/{{ item.id }}" class="btn-secondary">View in library</a>
146 {% else if item.is_free %}
147 <button class="btn-primary"
148 hx-post="/api/library/add/{{ item.id }}"
149 hx-swap="outerHTML">Add to Library</button>
150 {% else if item.pwyw_enabled %}
151 <a href="/purchase/{{ item.id }}" class="btn-primary">Pay What You Want</a>
152 {% else %}
153 <a href="/purchase/{{ item.id }}" class="btn-primary">Buy Once</a>
154 {% endif %}
155 </div>
156 </div>
157 {% endfor %}
158 </div>
159
160 <!-- List View -->
161 <div class="items-list">
162 {% for item in items %}
163 <a href="{% if item.can_access %}/i/{{ item.id }}{% else %}/purchase/{{ item.id }}{% endif %}" class="list-item">
164 <div class="list-item-info">
165 <span class="list-item-title">{{ item.title }}</span>
166 <span class="list-item-meta">{{ item.item_type }}</span>
167 </div>
168 <div class="list-item-price">{{ item.price }}</div>
169 </a>
170 {% endfor %}
171 </div>
172 </div>
173 </section>
174
175 {% if !subscription_tiers.is_empty() %}
176 <section class="tiers-section">
177 <h2 class="section-header">Membership</h2>
178 <div class="tiers-grid">
179 {% for tier in subscription_tiers %}
180 <div class="tier-card">
181 <div class="tier-name">{{ tier.name }}</div>
182 <div class="tier-price">{{ tier.price }}</div>
183 {% if !tier.description.is_empty() %}
184 <p class="tier-description">{{ tier.description }}</p>
185 {% endif %}
186 {% if has_subscription %}
187 <div class="tier-active-badge">Subscribed</div>
188 {% else if session_user.is_some() %}
189 <form method="post" action="/stripe/subscribe/{{ tier.id }}">
190 {% if let Some(token) = csrf_token %}<input type="hidden" name="_csrf" value="{{ token }}">{% endif %}
191 <details class="promo-details">
192 <summary>Have a promo code?</summary>
193 <input type="text" name="promo_code" placeholder="e.g. TRIAL14" class="promo-input">
194 </details>
195 <button class="btn-primary" type="submit" data-loading-text="Redirecting to Stripe...">Subscribe</button>
196 </form>
197 {% else %}
198 <a href="/login" class="btn-primary">Log in to Subscribe</a>
199 {% endif %}
200 </div>
201 {% endfor %}
202 </div>
203 </section>
204 {% endif %}
205
206 <footer class="store-footer">
207 <p>Powered by <a href="/">Makenot<span class="dot">.</span>work</a> &middot; Fair distribution for creatives of all kinds</p>
208 <p class="store-footer-links">
209 <a href="/p/{{ project.slug }}" data-copy-link>Copy link</a> &middot;
210 <a href="/policy">Policy</a> &middot;
211 {% if session_user.is_some() %}
212 <a href="#" data-prevent data-action="show" data-target="report-modal">Report</a>
213 {% else %}
214 <a href="/login">Report</a>
215 {% endif %}
216 </p>
217 </footer>
218 </div>
219
220 {% if session_user.is_some() %}
221 {% let report_target_type = "project" %}
222 {% let report_target_id = project_id %}
223 {% let report_has_labels = true %}
224 {% include "partials/report_modal.html" %}
225 {% endif %}
226 {% endblock %}
227
228 {% block scripts %}
229 <script src="/static/page-project-2.js?v=0623" defer></script>
230 {% endblock %}
231