0
|
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
|