0
|
1 local Luan = require "luan:Luan.luan"
|
|
2 local error = Luan.error
|
|
3 local pairs = Luan.pairs or error()
|
|
4 local parse = Luan.parse or error()
|
|
5 local Html = require "luan:Html.luan"
|
|
6 local html_encode = Html.encode or error()
|
|
7 local Io = require "luan:Io.luan"
|
|
8 local Http = require "luan:http/Http.luan"
|
|
9 local Shared = require "site:/lib/Shared.luan"
|
|
10 local head = Shared.head or error()
|
|
11 local body_header = Shared.body_header or error()
|
|
12 local footer = Shared.footer or error()
|
|
13 local fields = Shared.theme_fields or error()
|
|
14 local User = require "site:/lib/User.luan"
|
|
15 local get_background_img_url = User.get_background_img_url or error()
|
|
16 local Logging = require "luan:logging/Logging.luan"
|
|
17 local logger = Logging.logger "theme.html"
|
|
18
|
|
19
|
|
20 local google_explanation = [[All Google fonts use this URL format. You can change the font name and edit the font URL to use other Google fonts not listed here.]]
|
|
21
|
|
22 local fonts = {
|
|
23 ["Sans-Serif"] = {}
|
|
24 ["Times New Roman"] = {}
|
|
25 ["Optima"] = {}
|
|
26 ["Apple Chancery"] = {}
|
|
27 ["Courier"] = {}
|
|
28 ["Copperplate"] = {}
|
|
29 ["Bitter"] = {
|
|
30 title = "Google: Bitter"
|
|
31 url = "https://fonts.googleapis.com/css?family=Bitter"
|
|
32 explanation = google_explanation
|
|
33 }
|
|
34 ["Genos"] = {
|
|
35 title = "Google: Genos"
|
|
36 url = "https://fonts.googleapis.com/css?family=Genos"
|
|
37 explanation = google_explanation
|
|
38 }
|
|
39 ["Emblema One"] = {
|
|
40 title = "Google: Emblema One"
|
|
41 url = "https://fonts.googleapis.com/css?family=Emblema+One"
|
|
42 explanation = google_explanation
|
|
43 }
|
|
44 }
|
|
45 for name, font in pairs(fonts) do
|
|
46 font.name = name
|
|
47 font.title = font.title or name
|
|
48 font.url = font.url or ""
|
|
49 font.explanation = font.explanation or ""
|
|
50 end
|
|
51
|
|
52 local function color_input(user_data,color)
|
|
53 local value = user_data[color]
|
|
54 value = value and html_encode(value)
|
|
55 local default = fields[color]
|
|
56 local v = value or default
|
|
57 %>
|
|
58 <div>
|
|
59 <input type=color <%= v=="" and "" or [[value="]]..v..[["]] %> oninput="colorChange(this)">
|
|
60 <span color <%= v=="" and "" or [[style="background-color:]]..v..[["]] %> onclick="colorClick(this)"></span>
|
|
61 <input type=text name="<%=color%>" value="<%= value or "" %>" placeholder="<%=default%>" onchange="colorInputChange(this)">
|
|
62 </div>
|
|
63 <%
|
|
64 end
|
|
65
|
|
66 local function radio_input(user_data,name,value)
|
|
67 local current = user_data[name] or fields[name]
|
|
68 local checked = value==current and "checked" or ""
|
|
69 %><input type=radio name="<%=name%>" value="<%=value%>" <%=checked%> ><%
|
|
70 end
|
|
71
|
|
72 return function()
|
|
73 local user = User.current_required()
|
|
74 if user==nil then return end
|
|
75 local user_data = user.theme_data
|
|
76 user_data = user_data and parse(user_data) or {}
|
|
77 local message
|
|
78 Io.stdout = Http.response.text_writer()
|
|
79 %>
|
|
80 <!doctype html>
|
|
81 <html lang="en">
|
|
82 <head>
|
|
83 <% head() %>
|
|
84 <title>Link My Style</title>
|
|
85 <style>
|
|
86 <%
|
|
87 for _, font in pairs(fonts) do
|
|
88 if font.url ~= "" then
|
|
89 %>
|
|
90 @import "<%=font.url%>";
|
|
91 <%
|
|
92 end
|
|
93 %>
|
|
94 <%
|
|
95 end
|
|
96 %>
|
|
97
|
|
98 h1 {
|
|
99 text-align: center;
|
|
100 }
|
|
101 div[body] {
|
|
102 max-width: 600px;
|
|
103 margin-left: auto;
|
|
104 margin-right: auto;
|
|
105 }
|
|
106 @media (max-width: 700px) {
|
|
107 div[body] {
|
|
108 max-width: 90%;
|
|
109 }
|
|
110 }
|
|
111 label {
|
|
112 display: block;
|
|
113 }
|
|
114 form > div {
|
|
115 display: flex;
|
|
116 margin-top: 1px;
|
|
117 margin-bottom: 10px;
|
|
118 position: relative;
|
|
119 }
|
|
120 input[type="color"] {
|
|
121 /* hide this useless modern piece of junk */
|
|
122 position: absolute;
|
|
123 z-index: 1;
|
|
124 width: 42.5px;
|
|
125 height: 42.5px;
|
|
126 cursor: pointer;
|
|
127 opacity: 0;
|
|
128 }
|
|
129 span[color] {
|
|
130 width: 42.5px;
|
|
131 cursor: pointer;
|
|
132 border: 1px solid #E0E0E0;
|
|
133 }
|
|
134 form span[pulldown] {
|
|
135 border: 1px solid #E0E0E0;
|
|
136 display: flex;
|
|
137 align-items: center;
|
|
138 }
|
|
139 form span[pulldown] > span {
|
|
140 padding: 4px;
|
|
141 }
|
|
142 span[shape] a {
|
|
143 margin: 12px;
|
|
144 padding: 12px 100px;
|
|
145 border: 1px solid black;
|
|
146 }
|
|
147 span[shape] a:hover {
|
|
148 text-decoration: none;
|
|
149 }
|
|
150 input[type="text"] {
|
|
151 display: initial;
|
|
152 margin: 0;
|
|
153 border-radius: 0;
|
|
154 }
|
|
155 label[clickable] {
|
|
156 border: 1px solid grey;
|
|
157 padding: 4px;
|
|
158 padding-right: 8px;
|
|
159 }
|
|
160 label[white] {
|
|
161 color: white;
|
|
162 background-color: black;
|
|
163 }
|
|
164 div[background_img] {
|
|
165 gap: 8px;
|
|
166 }
|
|
167 button[background_img] {
|
|
168 width: 42.5px;
|
|
169 height: 42.5px;
|
|
170 padding: 0;
|
|
171 border: 1px solid #E0E0E0;
|
|
172 }
|
|
173 button[background_img] img {
|
|
174 display: block;
|
|
175 width: 100%;
|
|
176 height: 100%;
|
|
177 object-fit: cover;
|
|
178 }
|
|
179 div[background_img] button[small] {
|
|
180 flex-grow: 1;
|
|
181 background-color: #E0E0E0;
|
|
182 color: black;
|
|
183 }
|
|
184 div[background_img] button[small]:hover {
|
|
185 background-color: #C0C0C0;
|
|
186 }
|
|
187 div[font] {
|
|
188 gap: 8px;
|
|
189 }
|
|
190 div[font] input[name="font"] {
|
|
191 width: 33%;
|
|
192 }
|
|
193 div[font] input[name="font_url"] {
|
|
194 width: 66%;
|
|
195 }
|
|
196 div[font_explanation] {
|
|
197 color: #808080;
|
|
198 }
|
|
199 </style>
|
|
200 <script>
|
|
201 'use strict';
|
|
202
|
|
203 function colorClick(colorSpan) {
|
|
204 console.log('colorClick');
|
|
205 let colorInput = colorSpan.parentNode.querySelector('input[type="color"]');
|
|
206 colorInput.click();
|
|
207 }
|
|
208 function colorChange(colorInput) {
|
|
209 let parent = colorInput.parentNode;
|
|
210 let color = colorInput.value;
|
|
211 parent.querySelector('input[type="text"]').value = color;
|
|
212 parent.querySelector('span[color]').style['background-color'] = color;
|
|
213 }
|
|
214 function colorInputChange(input) {
|
|
215 let parent = input.parentNode;
|
|
216 let color = input.value || input.placeholder;
|
|
217 parent.querySelector('input[type="color"]').value = color;
|
|
218 parent.querySelector('span[color]').style['background-color'] = color;
|
|
219 }
|
|
220 function setField(name,value) {
|
|
221 document.querySelector('input[type="text"][name="'+name+'"]').value = value;
|
|
222 }
|
|
223 function setFont(font,url,explanation) {
|
|
224 setField('font',font);
|
|
225 setField('font_url',url);
|
|
226 document.querySelector('div[font_explanation]').textContent = explanation;
|
|
227 }
|
|
228
|
|
229 function uploaded(uuid,filename) {
|
|
230 document.querySelector('input[name="background_img_uuid"]').value = uuid;
|
|
231 document.querySelector('input[name="background_img_filename"]').value = filename;
|
|
232 document.querySelector('div[background_img] img').src = uploadcareUrl(uuid);
|
|
233 }
|
|
234 function clearImg() {
|
|
235 document.querySelector('input[name="background_img_uuid"]').value = '';
|
|
236 document.querySelector('input[name="background_img_filename"]').value = '';
|
|
237 document.querySelector('div[background_img] img').src = '/images/nothing.svg';
|
|
238 }
|
|
239 </script>
|
|
240 </head>
|
|
241 <body>
|
|
242 <div full>
|
|
243 <% body_header() %>
|
|
244 <h1>My Theme</h1>
|
|
245 <p top>Click the left side of every section to make quick changes or put exactly what you'd like in the input field. To remove a color or shadow, delete the text from the input field.</p>
|
|
246 <div body>
|
|
247 <form onsubmit="ajaxForm('/theme.js',this)" action="javascript:">
|
|
248 <label>Background Image</label>
|
|
249 <div background_img>
|
|
250 <button type=button background_img onclick="uploadcare.upload(uploaded)">
|
|
251 <img src="<%= get_background_img_url(user_data) or "/images/nothing.svg" %>" >
|
|
252 </button>
|
|
253 <input type=hidden name="background_img_uuid" value="<%= user_data.background_img_uuid or "" %>">
|
|
254 <input type=hidden name="background_img_filename" value="<%= user_data.background_img_filename or "" %>">
|
|
255 <button type=button small onclick="uploadcare.upload(uploaded)">Add</button>
|
|
256 <button type=button small onclick="clearImg()">Clear</button>
|
|
257 </div>
|
|
258 <label>Background Color</label>
|
|
259 <% color_input(user_data,"background_color") %>
|
|
260 <label>Button Color</label>
|
|
261 <% color_input(user_data,"link_background_color") %>
|
|
262 <label>Button Hover Color</label>
|
|
263 <% color_input(user_data,"link_hover_background_color") %>
|
|
264 <label>Button Text Color</label>
|
|
265 <% color_input(user_data,"link_text_color") %>
|
|
266 <label>Title Color</label>
|
|
267 <% color_input(user_data,"title_color") %>
|
|
268 <label>Bio Color</label>
|
|
269 <% color_input(user_data,"bio_color") %>
|
|
270 <label>Social Icon Color</label>
|
|
271 <div>
|
|
272 <label clickable black><% radio_input(user_data,"icon_color","") %>Black</label>
|
|
273
|
|
274 <label clickable white><% radio_input(user_data,"icon_color","white") %>White</label>
|
|
275 </div>
|
|
276 <label>Button Shape</label>
|
|
277 <%
|
|
278 local field = "link_border_radius"
|
|
279 local value = user_data[field]
|
|
280 value = value and html_encode(value)
|
|
281 local default = fields[field]
|
|
282 local value_or_default = value or default
|
|
283 %>
|
|
284 <div>
|
|
285 <span shape pulldown>
|
|
286 <span onclick="clickMenu(this)">Select...</span>
|
|
287 <div pulldown_menu>
|
|
288 <a style="border-radius:22px / 50%" href="javascript:setField('<%=field%>','22px / 50%')">Link</a>
|
|
289 <a style="border-radius:12px / 50%" href="javascript:setField('<%=field%>','12px / 50%')">Link</a>
|
|
290 <a style="border-radius:10px" href="javascript:setField('<%=field%>','10px')">Link</a>
|
|
291 <a style="border-radius:0" href="javascript:setField('<%=field%>','0')">Link</a>
|
|
292 <a style="border-radius:10px 100px" href="javascript:setField('<%=field%>','10px 100px')">Link</a>
|
|
293 </div>
|
|
294 </span>
|
|
295 <input type=text name="<%=field%>" value="<%= value or "" %>" placeholder="<%=default%>">
|
|
296 </div>
|
|
297 <label>Button Border Color</label>
|
|
298 <% color_input(user_data,"link_border_color") %>
|
|
299 <label>Button Shadow</label>
|
|
300 <%
|
|
301 local field = "link_shadow"
|
|
302 local value = user_data[field]
|
|
303 value = value and html_encode(value)
|
|
304 local default = fields[field]
|
|
305 local value_or_default = value or default
|
|
306 %>
|
|
307 <div>
|
|
308 <span shape pulldown>
|
|
309 <span onclick="clickMenu(this)">Select...</span>
|
|
310 <div pulldown_menu>
|
|
311 <a style="box-shadow:5px 5px 2px 1px" href="javascript:setField('<%=field%>','5px 5px 2px 1px')">Link</a>
|
|
312 <a style="box-shadow:1px 1px 10px 1px" href="javascript:setField('<%=field%>','1px 1px 10px 1px')">Link</a>
|
|
313 </div>
|
|
314 </span>
|
|
315 <input type=text name="<%=field%>" value="<%= value or "" %>" placeholder="<%=default%>">
|
|
316 </div>
|
|
317 <label>Button Shadow Color</label>
|
|
318 <% color_input(user_data,"link_shadow_color") %>
|
|
319 <label>Font</label>
|
|
320 <%
|
|
321 local value = user_data.font
|
|
322 value = value and html_encode(value)
|
|
323 local value_url = user_data.font_url
|
|
324 value_url = value_url and html_encode(value_url)
|
|
325 local default = fields.font
|
|
326 local explanation = fonts[value] and fonts[value].explanation or ""
|
|
327 %>
|
|
328 <div font>
|
|
329 <span pulldown>
|
|
330 <span onclick="clickMenu(this)">Select...</span>
|
|
331 <div pulldown_menu>
|
|
332 <% for _, font in pairs(fonts) do %>
|
|
333 <a style="font-family:<%=font.name%>" href="javascript:setFont('<%=font.name%>','<%=font.url%>','<%=font.explanation%>')"><%=font.title%></a>
|
|
334 <% end %>
|
|
335 </div>
|
|
336 </span>
|
|
337 <input type=text name="font" value="<%= value or "" %>" placeholder="<%=default%>">
|
|
338 <input type=text name="font_url" value="<%= value_url or "" %>" placeholder="URL">
|
|
339 </div>
|
|
340 <div font_explanation><%=explanation%></div>
|
|
341 <button type=submit big>Save</button>
|
|
342 <%
|
|
343 local msg = message and message.info
|
|
344 %>
|
|
345 <div success><%= msg or "" %></div>
|
|
346 </form>
|
|
347 </div>
|
|
348 <% footer() %>
|
|
349 </div>
|
|
350 </body>
|
|
351 </html>
|
|
352 <%
|
|
353 end
|