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