Mercurial Hosting > linkmystyle
comparison src/account.html.luan @ 0:8f4df159f06b
start public repo
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Fri, 11 Jul 2025 20:57:49 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:8f4df159f06b |
---|---|
1 local Luan = require "luan:Luan.luan" | |
2 local error = Luan.error | |
3 local Html = require "luan:Html.luan" | |
4 local html_encode = Html.encode or error() | |
5 local Io = require "luan:Io.luan" | |
6 local Http = require "luan:http/Http.luan" | |
7 local Shared = require "site:/lib/Shared.luan" | |
8 local head = Shared.head or error() | |
9 local body_header = Shared.body_header or error() | |
10 local footer = Shared.footer or error() | |
11 local show_user_icons = Shared.show_user_icons or error() | |
12 local password_input = Shared.password_input or error() | |
13 local User = require "site:/lib/User.luan" | |
14 local Logging = require "luan:logging/Logging.luan" | |
15 local logger = Logging.logger "account.html" | |
16 | |
17 | |
18 return function() | |
19 local user = User.current_required() | |
20 if user==nil then return end | |
21 local title = user.title | |
22 local bio = user.bio | |
23 local username = user.name | |
24 local password = user.password | |
25 local email = user.email | |
26 local mp_id = user.mp_id | |
27 Io.stdout = Http.response.text_writer() | |
28 %> | |
29 <!doctype html> | |
30 <html lang="en"> | |
31 <head> | |
32 <% head() %> | |
33 <title>Link My Style</title> | |
34 <style> | |
35 h1 { | |
36 text-align: center; | |
37 } | |
38 div[body] { | |
39 max-width: 600px; | |
40 margin-left: auto; | |
41 margin-right: auto; | |
42 } | |
43 @media (max-width: 700px) { | |
44 div[body] { | |
45 max-width: 90%; | |
46 } | |
47 } | |
48 div[body] > * { | |
49 margin-bottom: 64px; | |
50 } | |
51 h2 { | |
52 margin-top: 20px; | |
53 margin-bottom: 20px !important; | |
54 } | |
55 label { | |
56 display: block; | |
57 } | |
58 div[field] { | |
59 margin-bottom: 10px; | |
60 } | |
61 button[delete1] { | |
62 background-color: red; | |
63 } | |
64 button[delete1]:hover, | |
65 button[delete2]:hover { | |
66 background-color: #7F1B1B; | |
67 } | |
68 div[delete2] { | |
69 display: none; | |
70 } | |
71 | |
72 div[pic] { | |
73 display: flex; | |
74 margin-bottom: 20px; | |
75 } | |
76 div[pic] img { | |
77 width: 100px; | |
78 height: 100px; | |
79 object-fit: cover; | |
80 border-radius: 50%; | |
81 background-color: grey; | |
82 flex-shrink: 0; | |
83 } | |
84 div[pic] div { | |
85 width: 100%; | |
86 display: flex; | |
87 flex-direction: column; | |
88 align-items: center; | |
89 justify-content: space-around; | |
90 } | |
91 div[pic] button { | |
92 width: 90%; | |
93 } | |
94 | |
95 div[icons] div[list] { | |
96 display: flex; | |
97 gap: 5px; | |
98 flex-wrap: wrap; | |
99 margin-bottom: 8px; | |
100 } | |
101 span[icon] { | |
102 border: 1px solid; | |
103 display: flex; | |
104 padding-right: 4px; | |
105 } | |
106 span[icon] img { | |
107 display: block; | |
108 height: 40px; | |
109 } | |
110 span[icon] > img { | |
111 opacity: 0.3; | |
112 touch-action: none; | |
113 } | |
114 </style> | |
115 <script> | |
116 'use strict'; | |
117 | |
118 function delete1() { | |
119 let delete2 = document.querySelector('div[delete2]'); | |
120 delete2.style.display = 'block'; | |
121 delete2.scrollIntoViewIfNeeded(false); | |
122 } | |
123 function undelete1() { | |
124 document.querySelector('div[delete2]').style.display = 'none'; | |
125 } | |
126 function delete2() { | |
127 ajax( '/delete_user.js' ); | |
128 } | |
129 | |
130 function removePic() { | |
131 let img = document.querySelector('div[pic] img'); | |
132 img.src = '/images/nothing.svg'; | |
133 let pic_uuid = document.querySelector('input[name="pic_uuid"]'); | |
134 pic_uuid.value = 'remove'; | |
135 } | |
136 function uploaded(uuid,filename) { | |
137 document.querySelector('input[name="pic_uuid"]').value = uuid; | |
138 document.querySelector('input[name="pic_filename"]').value = filename; | |
139 let img = document.querySelector('div[pic] img'); | |
140 img.src = uploadcareUrl(uuid); | |
141 } | |
142 function startUpload() { | |
143 uploadcare.cropprOptions = {aspectRatio: 1}; | |
144 uploadcare.upload(uploaded); | |
145 } | |
146 | |
147 dad.onDropped = function(event) { | |
148 let dragging = event.original; | |
149 if( iDragging === indexOf(dragging.parentNode.querySelectorAll(dropSelector),dragging) ) | |
150 return; | |
151 let iconId = dragging.getAttribute('icon'); | |
152 let prev = dragging.previousElementSibling; | |
153 let prevId = prev && prev.getAttribute('icon'); | |
154 ajax( '/move_icon.js?icon='+iconId+'&prev='+prevId ); | |
155 }; | |
156 dad.whatToDrag = function(draggable) { | |
157 return draggable.parentNode; | |
158 }; | |
159 function dragInit() { | |
160 dropSelector = 'span[icon]'; | |
161 let items = document.querySelectorAll('span[icon] > img'); | |
162 for( let i=0; i<items.length; i++ ) { | |
163 let item = items[i]; | |
164 dad.setDraggable(item); | |
165 dad.setDropzone(item.parentNode); | |
166 } | |
167 } | |
168 </script> | |
169 </head> | |
170 <body> | |
171 <div full> | |
172 <% body_header() %> | |
173 <h1>My Account</h1> | |
174 <div body> | |
175 <form onsubmit="ajaxForm('/save_account.js',this)" action="javascript:"> | |
176 <h2>My information</h2> | |
177 <div pic> | |
178 <img src="<%= user.get_pic_url() or "/images/nothing.svg" %>"> | |
179 <div> | |
180 <input type=hidden name="pic_uuid"> | |
181 <input type=hidden name="pic_filename"> | |
182 <button type=button big onclick="startUpload()">Pick an image</button> | |
183 <button type=button big onclick="removePic()">Remove</button> | |
184 </div> | |
185 </div> | |
186 <label>Profile Title</label> | |
187 <div field> | |
188 <input type=text name=title value="<%= html_encode(title or username) %>"> | |
189 </div> | |
190 <label>Profile Bio</label> | |
191 <div field> | |
192 <textarea name=bio><%= html_encode(bio or "") %></textarea> | |
193 </div> | |
194 <label>Username</label> | |
195 <div field> | |
196 <input type=text required name=username placeholder="Username" value="<%= username %>"> | |
197 <div error=username></div> | |
198 </div> | |
199 <label>Password</label> | |
200 <div field> | |
201 <% password_input(password) %> | |
202 </div> | |
203 <button type=submit big>Save</button> | |
204 <div error=success></div> | |
205 </form> | |
206 | |
207 <% | |
208 %> | |
209 <h2 icons>Social icons</h2> | |
210 <div icons> | |
211 <% show_user_icons(user) %> | |
212 </div> | |
213 | |
214 <form onsubmit="ajaxForm('/save_email.js',this)" action="javascript:"> | |
215 <h2>My email</h2> | |
216 <label>Email</label> | |
217 <div field> | |
218 <input type=email required name=email placeholder="Email" value="<%= email %>"> | |
219 <div error=email></div> | |
220 </div> | |
221 <button type=submit big>Change</button> | |
222 </form> | |
223 | |
224 <form onsubmit="ajaxForm('/save_mp.js',this)" action="javascript:"> | |
225 <h2>Custom analytics</h2> | |
226 <label>Mixpanel Project Token</label> | |
227 <div field> | |
228 <input type=text name=mp_id value="<%= html_encode(mp_id or "") %>"> | |
229 </div> | |
230 <button type=submit big>Save</button> | |
231 <div error=success></div> | |
232 </form> | |
233 | |
234 <div> | |
235 <h2>Delete account</h2> | |
236 <button type=button delete1 big onclick="delete1()">Delete account</button> | |
237 <div delete2> | |
238 <p>Are you sure that you want to delete this account?</p> | |
239 <button type=button delete2 small onclick="delete2()">Yes</button> | |
240 <button type=button small onclick="undelete1()">No</button> | |
241 </div> | |
242 </div> | |
243 </div> | |
244 <% footer() %> | |
245 </div> | |
246 </body> | |
247 <script> dragInit(); </script> | |
248 </html> | |
249 <% | |
250 end |