Skip to main content

max / makenotwork

9.3 KB · 204 lines History Blame Raw
1 <div class="tab-docs"><a href="/docs/profile">Docs: Profile &rarr;</a></div>
2
3 <div class="form-section">
4 <h2 class="subsection-title">Links</h2>
5 <p class="muted mb-section">Add links to your public profile.</p>
6
7 <div id="links-list">
8 {% for link in custom_links %}
9 {% let id = link.id.as_str() %}
10 {% let title = link.title.as_str() %}
11 {% let url = link.url.as_str() %}
12 {% include "partials/link_row.html" %}
13 {% endfor %}
14 </div>
15
16 <script src="/static/tab-user-profile.js?v=0623"></script>
17
18 <form hx-post="/api/links"
19 hx-target="#links-list"
20 hx-swap="beforeend"
21 data-after="reset">
22 <div class="field-row">
23 <div class="form-group is-grow">
24 <label for="link-title">Title</label>
25 <input type="text" id="link-title" name="title" placeholder="My Website" required>
26 </div>
27 <div class="form-group is-grow-2">
28 <label for="link-url">URL</label>
29 <input type="url" id="link-url" name="url" placeholder="https://..." required>
30 </div>
31 <button class="btn-secondary" type="submit">Add Link</button>
32 </div>
33 </form>
34 </div>
35
36 <div class="form-section">
37 <h2 class="subsection-title">Profile</h2>
38 <p class="muted mb-section">Your public page: <a href="/u/{{ user.username }}">makenot.work/u/{{ user.username }}</a></p>
39
40 <form hx-put="/api/users/me"
41 hx-target="#profile-save-status"
42 hx-swap="innerHTML"
43 hx-indicator="#profile-spinner">
44 <div class="form-group">
45 <label for="display-name">Display Name</label>
46 <input type="text" id="display-name" name="display_name" value="{{ user.display_name_or_username() }}">
47 <div class="hint">Defaults to your username if left empty</div>
48 </div>
49
50 <div class="form-group">
51 <label for="bio">Bio</label>
52 <textarea id="bio" name="bio">{{ user.bio.as_deref().unwrap_or("") }}</textarea>
53 </div>
54
55 <button class="btn-primary" type="submit">
56 Save Changes
57 <span id="profile-spinner" class="htmx-indicator"> ...</span>
58 </button>
59 <span id="profile-save-status"></span>
60 </form>
61 </div>
62
63 <div class="form-section">
64 <h2 class="subsection-title">Theme</h2>
65 <p class="muted mb-section">Color palette for your public profile page.</p>
66
67 <form hx-put="/api/users/me/theme"
68 hx-target="#profile-theme-save-status"
69 hx-swap="innerHTML"
70 hx-indicator="#profile-theme-spinner">
71 <div class="form-group">
72 <label for="profile-theme">Profile theme</label>
73 <select id="profile-theme" name="theme_id">
74 {% for t in theme_options %}
75 <option value="{{ t.id }}"{% if t.selected %} selected{% endif %}>{{ t.name }}</option>
76 {% endfor %}
77 </select>
78 <div class="hint">Applies to makenot.work/u/{{ user.username }}. Projects can set their own theme.</div>
79 </div>
80
81 <button class="btn-primary" type="submit">
82 Save Theme
83 <span id="profile-theme-spinner" class="htmx-indicator"> ...</span>
84 </button>
85 <span id="profile-theme-save-status"></span>
86 </form>
87 </div>
88
89 <div class="form-section">
90 <h2 class="subsection-title">Custom page</h2>
91 <p class="muted mb-section">
92 Go beyond the theme: write your own HTML and CSS for your public profile.
93 No JavaScript, on-platform links only.
94 </p>
95 <a class="btn-secondary" href="/dashboard/custom-page">Edit custom page</a>
96 </div>
97
98 {% if can_create_projects %}
99 <details class="form-section">
100 <summary><h2 class="subsection-title">Custom Domain</h2></summary>
101 <p class="muted mb-section">Point your own domain at your makenot.work profile.</p>
102
103 {% match custom_domain %}
104 {% when Some with (cd) %}
105 <div class="profile-domain-header">
106 <strong>{{ cd.domain }}</strong>
107 {% if cd.verified %}
108 <span class="profile-domain-status is-verified">Verified</span>
109 {% else %}
110 <span class="profile-domain-status is-pending">Pending verification</span>
111 {% endif %}
112 </div>
113
114 {% if !cd.verified %}
115 <div class="callout callout--warning">
116 <p class="m-0 mb-section"><strong>DNS setup required:</strong> add two records at your domain registrar, then click Check DNS.</p>
117
118 <p class="m-0 mb-peer"><strong>1. Point your domain</strong> (routes visitors to your page)</p>
119 <div class="dns-row">
120 <span class="dns-row-label">CNAME:</span>
121 <span id="dns-route-host" class="dns-row-value">{{ crate::quasi::literal::html(cd.domain)|safe }}</span>
122 <button type="button" class="btn-secondary dns-row-copy"
123 data-action="copyElementText" data-arg="dns-route-host">Copy</button>
124 </div>
125 <div class="dns-row">
126 <span class="dns-row-label">Value:</span>
127 <span id="dns-route-value" class="dns-row-value">{{ crate::quasi::literal::html("connect.makenot.work")|safe }}</span>
128 <button type="button" class="btn-secondary dns-row-copy"
129 data-action="copyElementText" data-arg="dns-route-value">Copy</button>
130 </div>
131 <p class="callout-hint mb-section">On Cloudflare, set this record to <strong>DNS only</strong> (grey cloud), not Proxied. For an apex/root domain, use CNAME flattening or ALIAS.</p>
132
133 <p class="m-0 mb-peer"><strong>2. Verify ownership</strong></p>
134 <div class="dns-row">
135 <span class="dns-row-label">TXT:</span>
136 <span id="dns-record" class="dns-row-value">{{ crate::quasi::literal::of(["_mnw-verify.", cd.domain.as_str()])|safe }}</span>
137 <button type="button" class="btn-secondary dns-row-copy"
138 data-action="copyElementText" data-arg="dns-record">Copy</button>
139 </div>
140 <div class="dns-row">
141 <span class="dns-row-label">Value:</span>
142 <span id="dns-value" class="dns-row-value">{{ crate::quasi::literal::html(cd.verification_token)|safe }}</span>
143 <button type="button" class="btn-secondary dns-row-copy"
144 data-action="copyElementText" data-arg="dns-value">Copy</button>
145 </div>
146 <p class="callout-hint">DNS changes can take up to 24 hours to propagate. <a href="/docs/custom-domains">Setup guide</a></p>
147 </div>
148 <div class="profile-domain-actions">
149 <button class="btn-primary"
150 hx-post="/api/domains/verify"
151 hx-vals='{"domain_id": "{{ cd.id }}"}'
152 hx-target="#domain-verify-result"
153 hx-swap="innerHTML"
154 data-after="refresh-profile-if-verified">Check DNS</button>
155 <button class="btn-danger"
156 hx-delete="/api/domains/{{ cd.id }}"
157 hx-confirm="Remove this domain?"
158 hx-target="closest .form-section"
159 hx-swap="outerHTML"
160 data-after="refresh-profile">Remove</button>
161 </div>
162 <div id="domain-verify-result" class="profile-domain-result"></div>
163 {% else %}
164 <p class="profile-domain-lead">
165 Visitors to <strong>{{ cd.domain }}</strong> will see your profile, projects, and items.
166 </p>
167 <button class="btn-danger"
168 hx-delete="/api/domains/{{ cd.id }}"
169 hx-confirm="Remove this domain? Your domain will stop serving your content."
170 hx-target="closest .form-section"
171 hx-swap="outerHTML"
172 data-after="refresh-profile">Remove Domain</button>
173 {% endif %}
174 {% when None %}
175 <form hx-post="/api/domains"
176 hx-target="#domain-add-result"
177 hx-swap="innerHTML"
178 data-after="refresh-profile">
179 <div class="field-row">
180 <div class="form-group is-grow">
181 <label for="custom-domain">Domain</label>
182 <input type="text" id="custom-domain" name="domain" placeholder="mysite.com" required>
183 </div>
184 <button class="btn-primary" type="submit">Add Domain</button>
185 </div>
186 </form>
187 <div id="domain-add-result" class="profile-domain-add-result"></div>
188 {% endmatch %}
189 </details>
190 {% endif %}
191
192 <details class="form-section">
193 <summary><h2 class="subsection-title">Personal Feed</h2></summary>
194 <p class="muted profile-feed-lead">An RSS feed of new content from creators and projects you follow. Add this URL to your RSS reader.</p>
195 <div class="profile-feed-row" id="feed-url-row">
196 <input type="text" id="feed-url" value="{{ feed_url }}" readonly class="profile-feed-input">
197 <button class="btn-secondary nowrap" type="button"
198 data-action="copyFeedUrl">Copy URL</button>
199 <button class="btn-secondary nowrap" type="button"
200 hx-post="/dashboard/feed/regenerate" hx-target="#feed-url-row" hx-swap="outerHTML">Regenerate</button>
201 </div>
202 <p class="muted profile-feed-lead">Regenerating issues a new URL and immediately stops the old one from working. Use it if your feed link leaks.</p>
203 </details>
204