diff src/links.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/links.html.luan	Fri Jul 11 20:57:49 2025 -0600
@@ -0,0 +1,324 @@
+local Luan = require "luan:Luan.luan"
+local error = Luan.error
+local ipairs = Luan.ipairs or error()
+local Html = require "luan:Html.luan"
+local html_encode = Html.encode or error()
+local Table = require "luan:Table.luan"
+local concat = Table.concat 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 show_editable_link = Shared.show_editable_link or error()
+local User = require "site:/lib/User.luan"
+local Link = require "site:/lib/Link.luan"
+local get_owner_links = Link.get_owner_links or error()
+local Pic = require "site:/lib/Pic.luan"
+local Utils = require "site:/lib/Utils.luan"
+local to_list = Utils.to_list or error()
+local Logging = require "luan:logging/Logging.luan"
+local logger = Logging.logger "links.html"
+
+
+local function hashtags(pic)
+	local hashtags = to_list(pic.hashtags)
+	for i, hashtag in ipairs(hashtags) do
+		hashtags[i] = "#"..hashtag
+	end
+	return concat(hashtags," ")
+end
+
+local function div_links(links,pic_id)
+%>
+		<div links>
+			<form add onsubmit="ajaxForm('add_link.js',this)" action="javascript:">
+<%	if pic_id ~= nil then %>
+				<input type=hidden name=pic value="<%=pic_id%>">
+<%	end %>
+				<input type=text required name=title placeholder="Title">
+				<input type=url required name=url placeholder="URL">
+				<button type=submit big>Add link</button>
+			</form>
+			<div start></div>
+<%	for _, link in ipairs(links) do
+			show_editable_link(link)
+	end %>
+		</div>
+<%
+end
+
+return function()
+	local user = User.current_required()
+	if user==nil then return end
+	local owner = user
+	local pic = Http.request.parameters.pic
+	if pic ~= nil then
+		pic = Pic.get_by_id(pic)
+		if pic == nil then
+			logger.warn("pic not found\n"..Http.request.raw_head)
+			Http.response.send_error(404)
+			return
+		end
+		pic.user_id == user.id or error()
+		owner = pic
+	end
+	local links = get_owner_links(owner.id)
+	local pic_id = pic and pic.id
+	Io.stdout = Http.response.text_writer()
+%>
+<!doctype html>
+<html lang="en">
+	<head>
+<%		head() %>
+		<title>Link My Style</title>
+		<style>
+			form[add] {
+				margin-bottom: 40px;
+			}
+			input {
+				margin-bottom: 5px;
+			}
+			input[type="url"],
+			input[type="text"] {
+				display: block;
+			}
+			div[link] {
+				margin-bottom: 20px;
+			}
+			button[small] {
+				font-size: 12px;
+			}
+			div[delete2] p {
+				margin-bottom: 5px;
+			}
+
+			div[link] > div:first-of-type {
+				border-radius: 12px / 50%;
+				margin-bottom: 5px;
+				overflow: hidden;
+				position: relative;
+				border: 1px solid #ebebeb;
+			}
+			div[link] a {
+				border-radius: initial;
+				margin-bottom: initial;
+			}
+			div[link] a:hover {
+				background-color: #243F47;
+			}
+			div[link] img {
+				position: absolute;
+				top: 0;
+				height: 100%;
+				background-color: white;
+				opacity: 0.3;
+				padding: 4px;
+				touch-action: none;
+			}
+
+<%	if pic == nil then %>
+			div[links] {
+				margin-top: 20px;
+			}
+<%	else %>
+			div[msg] {
+				margin-top: 20px;
+				margin-left: 5%;
+				color: darkgreen;
+<%		if Http.request.parameters.saved == nil then %>
+				display: none;
+<%		end %>
+			}
+			div[body] {
+				margin-top: 40px;
+				margin-bottom: 20px;
+			}
+			div[pic] img {
+				width: 100%;
+				display: block;
+				margin-bottom: 5px;
+			}
+			div[pic] form {
+				margin-top: 20px;
+			}
+			div[field] {
+				margin-top: 1px;
+				margin-bottom: 10px;
+			}
+			div[hashtags] {
+				margin-top: 20px;
+			}
+			@media (min-width: 888px) {
+				div[body] {
+					display: flex;
+				}
+				div[pic] {
+					width: 45%;
+					margin-left: 5%;
+				}
+				div[outer_links] {
+					width: 55%;
+					margin-left: 5%;
+					margin-right: 5%;
+				}
+			}
+			@media (max-width: 887px) {
+				div[pic] {
+					display: block;
+					width: 90%;
+					margin-left: auto;
+					margin-right: auto;
+					margin-bottom: 40px;
+				}
+			}
+<%	end %>
+		</style>
+		<script>
+			'use strict';
+
+			function clearAddForm() {
+				let form = document.querySelector('form[add]');
+				form.querySelector('[name="title"]').value = '';
+				form.querySelector('[name="url"]').value = '';
+			}
+
+			function deleteLink1(button,linkId) {
+				let div = button.parentNode;
+				if( div.querySelector('div[delete2]') )
+					return;
+				let html = `
+				<div delete2>
+					<p>Are you sure that you want to delete this?</p>
+					<button delete2 small onclick="deleteLink2('${linkId}')">Yes</button>
+					<button small onclick="undelete1(this)">No</button>
+				</div>
+`				;
+				div.insertAdjacentHTML( 'beforeEnd', html );
+				div.scrollIntoViewIfNeeded(false);
+			}
+			function undelete1(button) {
+				button.parentNode.outerHTML = '';
+			}
+			function deleteLink2(linkId) {
+				ajax( '/delete_link.js?link='+linkId );
+			}
+			function deletePic1(button) {
+				let div = button.parentNode;
+				if( div.querySelector('div[delete2]') )
+					return;
+				let html = `
+				<div delete2>
+					<p>Are you sure that you want to delete this?</p>
+					<button delete2 small onclick="deletePic2('<%=pic_id%>')">Yes</button>
+					<button small onclick="undelete1(this)">No</button>
+				</div>
+`				;
+				div.insertAdjacentHTML( 'beforeEnd', html );
+				div.scrollIntoViewIfNeeded(false);
+			}
+			function deletePic2() {
+				ajax( '/delete_pic.js?pic=<%=pic_id%>' );
+			}
+
+			function editLink(linkId) {
+				ajax( '/edit_link.js?link='+linkId );
+			}
+
+			function cancel(linkId) {
+				ajax( '/cancel_edit_link.js?link='+linkId );
+			}
+
+			dad.onDropped = function(event) {
+				let dragging = event.original;
+				if( iDragging === indexOf(dragging.parentNode.querySelectorAll(dropSelector),dragging) )
+					return;
+				let linkId = dragging.getAttribute('link');
+				let prev = dragging.previousElementSibling;
+				let prevId = prev && prev.getAttribute('link');
+				ajax( '/move_link.js?link='+linkId+'&prev='+prevId );
+			};
+
+			dad.whatToDrag = function(draggable) {
+				return draggable.parentNode.parentNode;
+			};
+
+			function dragInit() {
+				dropSelector = 'div[link]';
+				let items = document.querySelectorAll('div[link] img');
+				for( let i=0; i<items.length; i++ ) {
+					let item = items[i];
+					dad.setDraggable(item);
+					dad.setDropzone(item.parentNode.parentNode);
+				}
+			}
+
+<%	if pic ~= nil then %>
+			function changePic(uuid,filename) {
+				ajax( '/change_pic.js', 'pic=<%=pic.id%>&uuid=' + uuid + '&filename=' + encodeURIComponent(filename) );
+			}
+			function startChangePic() {
+				uploadcare.cropprOptions = {};
+				uploadcare.upload(changePic);
+			}
+<%	end %>
+		</script>
+	</head>
+	<body>
+	<div full>
+<%
+	body_header()
+	if pic == nil then
+%>
+		<p top>Enter your title and a URL to create a link. Once saved, you can drag-and-drop the icon on the left to change the order. The order on this page will also appear on your page.</p>
+<%
+		div_links(links,pic_id)
+	else
+%>
+		<div back>
+			<a href="/pics.html#p-<%=pic.id%>"><img src="/images/keyboard_backspace.svg"></a>
+		</div>
+		<div msg>
+			Your image has been saved.
+		</div>
+		<div body>
+			<div pic>
+				<img <%=pic.title_attr()%> src="<%=pic.get_url()%>">
+				<div>
+					<button type=button small onclick="startChangePic()">Change</button>
+					<button type=button small onclick="deletePic1(this)">Delete</button>
+				</div>
+				<div hashtags><%=pic.hashtags_html("pics.html")%></div>
+				<form onsubmit="ajaxForm('/save_pic_title.js',this)" action="javascript:">
+					<input type=hidden name=pic value="<%=pic_id%>">
+					<label>Photo title</label>
+					<div field>
+						<input type=text required name=title placeholder="Title" value="<%= html_encode(pic.title or "") %>">
+					</div>
+					<label>Hashtags</label>
+					<div field>
+						<textarea name=hashtags placeholder="#hashtag1 #hashtag2"><%= hashtags(pic) %></textarea>
+						<div error=hashtags></div>
+					</div>
+					<div field>
+						<label clickable><input type=checkbox name=visible <%=pic.is_hidden and "" or "checked"%>> Visible</label>
+					</div>
+					<button type=submit small>Save</button>
+					<div error=success></div>
+				</form>
+			</div>
+			<div outer_links>
+<%				div_links(links,pic_id) %>
+			</div>
+		</div>
+<%
+	end
+%>
+<%		footer() %>
+	</div>
+	<script> dragInit(); </script>
+	</body>
+</html>
+<%
+end