diff src/theme.html.luan @ 0:8f4df159f06b

start public repo
author Franklin Schmidt <fschmidt@gmail.com>
date Fri, 11 Jul 2025 20:57:49 -0600
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/theme.html.luan	Fri Jul 11 20:57:49 2025 -0600
@@ -0,0 +1,353 @@
+local Luan = require "luan:Luan.luan"
+local error = Luan.error
+local pairs = Luan.pairs or error()
+local parse = Luan.parse or error()
+local Html = require "luan:Html.luan"
+local html_encode = Html.encode or error()
+local Io = require "luan:Io.luan"
+local Http = require "luan:http/Http.luan"
+local Shared = require "site:/lib/Shared.luan"
+local head = Shared.head or error()
+local body_header = Shared.body_header or error()
+local footer = Shared.footer or error()
+local fields = Shared.theme_fields or error()
+local User = require "site:/lib/User.luan"
+local get_background_img_url = User.get_background_img_url or error()
+local Logging = require "luan:logging/Logging.luan"
+local logger = Logging.logger "theme.html"
+
+
+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.]]
+
+local fonts = {
+	["Sans-Serif"] = {}
+	["Times New Roman"] = {}
+	["Optima"] = {}
+	["Apple Chancery"] = {}
+	["Courier"] = {}
+	["Copperplate"] = {}
+	["Bitter"] = {
+		title = "Google: Bitter"
+		url = "https://fonts.googleapis.com/css?family=Bitter"
+		explanation = google_explanation
+	}
+	["Genos"] = {
+		title = "Google: Genos"
+		url = "https://fonts.googleapis.com/css?family=Genos"
+		explanation = google_explanation
+	}
+	["Emblema One"] = {
+		title = "Google: Emblema One"
+		url = "https://fonts.googleapis.com/css?family=Emblema+One"
+		explanation = google_explanation
+	}
+}
+for name, font in pairs(fonts) do
+	font.name = name
+	font.title = font.title or name
+	font.url = font.url or ""
+	font.explanation = font.explanation or ""
+end
+
+local function color_input(user_data,color)
+	local value = user_data[color]
+	value = value and html_encode(value)
+	local default = fields[color]
+	local v = value or default
+%>
+				<div>
+					<input type=color <%= v=="" and "" or [[value="]]..v..[["]] %> oninput="colorChange(this)">
+					<span color <%= v=="" and "" or [[style="background-color:]]..v..[["]] %> onclick="colorClick(this)"></span>
+					<input type=text name="<%=color%>" value="<%= value or "" %>" placeholder="<%=default%>" onchange="colorInputChange(this)">
+				</div>
+<%
+end
+
+local function radio_input(user_data,name,value)
+	local current = user_data[name] or fields[name]
+	local checked = value==current and "checked" or ""
+	%><input type=radio name="<%=name%>" value="<%=value%>" <%=checked%> ><%
+end
+
+return function()
+	local user = User.current_required()
+	if user==nil then return end
+	local user_data = user.theme_data
+	user_data = user_data and parse(user_data) or {}
+	local message
+	Io.stdout = Http.response.text_writer()
+%>
+<!doctype html>
+<html lang="en">
+	<head>
+<%		head() %>
+		<title>Link My Style</title>
+		<style>
+<%
+	for _, font in pairs(fonts) do
+		if font.url ~= "" then
+%>
+			@import "<%=font.url%>";
+<%
+		end
+%>
+<%
+	end
+%>
+
+			h1 {
+				text-align: center;
+			}
+			div[body] {
+				max-width: 600px;
+				margin-left: auto;
+				margin-right: auto;
+			}
+			@media (max-width: 700px) {
+				div[body] {
+					max-width: 90%;
+				}
+			}
+			label {
+				display: block;
+			}
+			form > div {
+				display: flex;
+				margin-top: 1px;
+				margin-bottom: 10px;
+				position: relative;
+			}
+			input[type="color"] {
+				/* hide this useless modern piece of junk */
+				position: absolute;
+				z-index: 1;
+				width: 42.5px;
+				height: 42.5px;
+				cursor: pointer;
+				opacity: 0;
+			}
+			span[color] {
+				width: 42.5px;
+				cursor: pointer;
+				border: 1px solid #E0E0E0;
+			}
+			form span[pulldown] {
+				border: 1px solid #E0E0E0;
+				display: flex;
+				align-items: center;
+			}
+			form span[pulldown] > span {
+				padding: 4px;
+			}
+			span[shape] a {
+				margin: 12px;
+				padding: 12px 100px;
+				border: 1px solid black;
+			}
+			span[shape] a:hover {
+				text-decoration: none;
+			}
+			input[type="text"] {
+				display: initial;
+				margin: 0;
+				border-radius: 0;
+			}
+			label[clickable] {
+				border: 1px solid grey;
+				padding: 4px;
+				padding-right: 8px;
+			}
+			label[white] {
+				color: white;
+				background-color: black;
+			}
+			div[background_img] {
+				gap: 8px;
+			}
+			button[background_img] {
+				width: 42.5px;
+				height: 42.5px;
+				padding: 0;
+				border: 1px solid #E0E0E0;
+			}
+			button[background_img] img {
+				display: block;
+				width: 100%;
+				height: 100%;
+				object-fit: cover;
+			}
+			div[background_img] button[small] {
+				flex-grow: 1;
+				background-color: #E0E0E0;
+				color: black;
+			}
+			div[background_img] button[small]:hover {
+				background-color: #C0C0C0;
+			}
+			div[font] {
+				gap: 8px;
+			}
+			div[font] input[name="font"] {
+				width: 33%;
+			}
+			div[font] input[name="font_url"] {
+				width: 66%;
+			}
+			div[font_explanation] {
+				color: #808080;
+			}
+		</style>
+		<script>
+			'use strict';
+
+			function colorClick(colorSpan) {
+				console.log('colorClick');
+				let colorInput = colorSpan.parentNode.querySelector('input[type="color"]');
+				colorInput.click();
+			}
+			function colorChange(colorInput) {
+				let parent = colorInput.parentNode;
+				let color = colorInput.value;
+				parent.querySelector('input[type="text"]').value = color;
+				parent.querySelector('span[color]').style['background-color'] = color;
+			}
+			function colorInputChange(input) {
+				let parent = input.parentNode;
+				let color = input.value || input.placeholder;
+				parent.querySelector('input[type="color"]').value = color;
+				parent.querySelector('span[color]').style['background-color'] = color;
+			}
+			function setField(name,value) {
+				document.querySelector('input[type="text"][name="'+name+'"]').value = value;
+			}
+			function setFont(font,url,explanation) {
+				setField('font',font);
+				setField('font_url',url);
+				document.querySelector('div[font_explanation]').textContent = explanation;
+			}
+
+			function uploaded(uuid,filename) {
+				document.querySelector('input[name="background_img_uuid"]').value = uuid;
+				document.querySelector('input[name="background_img_filename"]').value = filename;
+				document.querySelector('div[background_img] img').src = uploadcareUrl(uuid);
+			}
+			function clearImg() {
+				document.querySelector('input[name="background_img_uuid"]').value = '';
+				document.querySelector('input[name="background_img_filename"]').value = '';
+				document.querySelector('div[background_img] img').src = '/images/nothing.svg';
+			}
+		</script>
+	</head>
+	<body>
+	<div full>
+<%		body_header() %>
+		<h1>My Theme</h1>
+		<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>
+		<div body>
+			<form onsubmit="ajaxForm('/theme.js',this)" action="javascript:">
+				<label>Background Image</label>
+				<div background_img>
+					<button type=button background_img onclick="uploadcare.upload(uploaded)">
+						<img src="<%= get_background_img_url(user_data) or "/images/nothing.svg" %>" >
+					</button>
+					<input type=hidden name="background_img_uuid" value="<%= user_data.background_img_uuid or "" %>">
+					<input type=hidden name="background_img_filename" value="<%= user_data.background_img_filename or "" %>">
+					<button type=button small onclick="uploadcare.upload(uploaded)">Add</button>
+					<button type=button small onclick="clearImg()">Clear</button>
+				</div>
+				<label>Background Color</label>
+<%				color_input(user_data,"background_color") %>
+				<label>Button Color</label>
+<%				color_input(user_data,"link_background_color") %>
+				<label>Button Hover Color</label>
+<%				color_input(user_data,"link_hover_background_color") %>
+				<label>Button Text Color</label>
+<%				color_input(user_data,"link_text_color") %>
+				<label>Title Color</label>
+<%				color_input(user_data,"title_color") %>
+				<label>Bio Color</label>
+<%				color_input(user_data,"bio_color") %>
+				<label>Social Icon Color</label>
+				<div>
+					<label clickable black><% radio_input(user_data,"icon_color","") %>Black</label>
+					&nbsp; &nbsp;
+					<label clickable white><% radio_input(user_data,"icon_color","white") %>White</label>
+				</div>
+				<label>Button Shape</label>
+<%
+	local field = "link_border_radius"
+	local value = user_data[field]
+	value = value and html_encode(value)
+	local default = fields[field]
+	local value_or_default = value or default
+%>
+				<div>
+					<span shape pulldown>
+						<span onclick="clickMenu(this)">Select...</span>
+						<div pulldown_menu>
+							<a style="border-radius:22px / 50%" href="javascript:setField('<%=field%>','22px / 50%')">Link</a>
+							<a style="border-radius:12px / 50%" href="javascript:setField('<%=field%>','12px / 50%')">Link</a>
+							<a style="border-radius:10px" href="javascript:setField('<%=field%>','10px')">Link</a>
+							<a style="border-radius:0" href="javascript:setField('<%=field%>','0')">Link</a>
+							<a style="border-radius:10px 100px" href="javascript:setField('<%=field%>','10px 100px')">Link</a>
+						</div>
+					</span>
+					<input type=text name="<%=field%>" value="<%= value or "" %>" placeholder="<%=default%>">
+				</div>
+				<label>Button Border Color</label>
+<%				color_input(user_data,"link_border_color") %>
+				<label>Button Shadow</label>
+<%
+	local field = "link_shadow"
+	local value = user_data[field]
+	value = value and html_encode(value)
+	local default = fields[field]
+	local value_or_default = value or default
+%>
+				<div>
+					<span shape pulldown>
+						<span onclick="clickMenu(this)">Select...</span>
+						<div pulldown_menu>
+							<a style="box-shadow:5px 5px 2px 1px" href="javascript:setField('<%=field%>','5px 5px 2px 1px')">Link</a>
+							<a style="box-shadow:1px 1px 10px 1px" href="javascript:setField('<%=field%>','1px 1px 10px 1px')">Link</a>
+						</div>
+					</span>
+					<input type=text name="<%=field%>" value="<%= value or "" %>" placeholder="<%=default%>">
+				</div>
+				<label>Button Shadow Color</label>
+<%				color_input(user_data,"link_shadow_color") %>
+				<label>Font</label>
+<%
+	local value = user_data.font
+	value = value and html_encode(value)
+	local value_url = user_data.font_url
+	value_url = value_url and html_encode(value_url)
+	local default = fields.font
+	local explanation = fonts[value] and fonts[value].explanation or ""
+%>
+				<div font>
+					<span pulldown>
+						<span onclick="clickMenu(this)">Select...</span>
+						<div pulldown_menu>
+<%	for _, font in pairs(fonts) do %>
+							<a style="font-family:<%=font.name%>" href="javascript:setFont('<%=font.name%>','<%=font.url%>','<%=font.explanation%>')"><%=font.title%></a>
+<%	end %>
+						</div>
+					</span>
+					<input type=text name="font" value="<%= value or "" %>" placeholder="<%=default%>">
+					<input type=text name="font_url" value="<%= value_url or "" %>" placeholder="URL">
+				</div>
+				<div font_explanation><%=explanation%></div>
+				<button type=submit big>Save</button>
+<%
+	local msg = message and message.info
+%>
+				<div success><%= msg or "" %></div>
+			</form>
+		</div>
+<%		footer() %>
+	</div>
+	</body>
+</html>
+<%
+end