Skip to main content

max / makenotwork

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