Mercurial Hosting > linkmystyle
diff src/lib/Shared.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/lib/Shared.luan Fri Jul 11 20:57:49 2025 -0600 @@ -0,0 +1,358 @@ +local Luan = require "luan:Luan.luan" +local error = Luan.error +local ipairs = Luan.ipairs or error() +local pairs = Luan.pairs or error() +local range = Luan.range or error() +local Table = require "luan:Table.luan" +local is_list = Table.is_list or error() +local is_empty = Table.is_empty or error() +local concat = Table.concat or error() +local Io = require "luan:Io.luan" +local uri = Io.uri or error() +local Html = require "luan:Html.luan" +local html_encode = Html.encode or error() +local url_encode = Html.url_encode or error() +local Parsers = require "luan:Parsers.luan" +local json_parse = Parsers.json_parse or error() +local json_string = Parsers.json_string or error() +local Thread = require "luan:Thread.luan" +local thread_run = Thread.run or error() +local sleep = Thread.sleep or error() +local Time = require "luan:Time.luan" +local Http = require "luan:http/Http.luan" +local Mail = require "luan:mail/Mail.luan" +local Config = require "site:/private/Config.luan" +local uploadcare_public_key = Config.uploadcare.public_key or error() +local Ab_test = require "site:/lib/Ab_test.luan" +local ab_test_head = Ab_test.head or error() +local User = require "site:/lib/User.luan" +local current_user = User.current or error() +local Icon = require "site:/lib/Icon.luan" +local get_user_icons = Icon.get_user_icons or error() +local Utils = require "site:/lib/Utils.luan" +local is_production = not not Utils.is_production +local base_url = Utils.base_url or error() +local to_list = Utils.to_list or error() +local Logging = require "luan:logging/Logging.luan" +local logger = Logging.logger "Shared" + + +local Shared = {} + +Shared.has_facebook = false; + +local started = Time.now() + +Shared.is_production = is_production +local is_local = Http.domain == nil +local has_reporting = true + +Shared.compressed = Utils.compressed + +local mp_id = is_production and "404d4c479de9c3070252e692375e82ca" or "bd2099a22e4118350a46b5b360d8c4da" +Shared.mp_id = mp_id +local mp_url = "https://api.mixpanel.com/track" + +local function call_mixpanel_raw(url,data) + local options = { + method = "POST" + parameters = { + data = json_string(data) + verbose = "1" + } + } + -- logger.info(options.parameters.data) + local result = uri(url,options).read_text() + result = json_parse(result) + result.error and logger.error("mixpanel: "..result.error) +end +Shared.call_mixpanel_raw = call_mixpanel_raw + +function Shared.call_mixpanel(data) + if is_list(data) then + for _, event in ipairs(data) do + event.properties.token = mp_id + end + else + data.properties.token = mp_id + end + call_mixpanel_raw(mp_url,data) +end + + +local function remove_from_path(name) + local path = Http.request.path + if path == "/index.html" then + path = "/" + end + local params = Http.request.parameters + params[name] = nil + if not is_empty(params) then + local t = {} + for name, value in pairs(params) do + t[#t+1] = url_encode(name).."="..url_encode(value) + end + path = path.."?"..concat(t,"&") + end + return path +end + +local function min_head(user) +%> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel="icon" href="/images/favicon.png" type="image/png"> + <style> + @import "https://fonts.googleapis.com/css?family=Bitter"; + @import "/site.css?s=<%=started%>"; + </style> + <script src="/site.js?s=<%=started%>"></script> +<% + local theme_date = user and user.theme_date + if theme_date ~= nil then +%> + <style> @import "/theme.css?user=<%=user.id%>&date=<%=theme_date%>&s=<%=started%>"; </style> +<% + end +end + +function Shared.head() + local user = current_user() + min_head(user) + local source = Http.request.parameters.source + if source ~= nil then + local path = remove_from_path('source') +%> + <script> + history.replaceState(null,null,'<%=path%>'); + </script> +<% + end + if user == nil and Http.request.cookies.source == nil then + source = source or "" +%> + <script> + mixpanel.ours.identify(); + mixpanel.ours.people.set({'source':'<%=source%>'}); + </script> +<% + Http.response.set_persistent_cookie( "source", source ) + end +%> + <style> + @import "/uploadcare/croppr.css"; + @import "/uploadcare/uploadcare.css?s=<%=started%>"; + @import "/dad.css"; + @import "/admin.css?s=<%=started%>"; + </style> + <script src="/uploadcare/croppr.js"></script> + <script src="/uploadcare/uploadcare.js?s=<%=started%>"></script> + <script> window.uploadcarePubKey = '<%=uploadcare_public_key%>'; </script> + <script src="/dad.js?v1"></script> +<% if user ~= nil then %> + <script> + window.UserEmail = '<%= user.email or error() %>'; + window.UserName = '<%= user.name or error() %>'; + </script> +<% end %> + <script src="/admin.js?s=<%=started%>"></script> +<% + ab_test_head() +end + +function Shared.pub_head(user) +%> + <script> + window.Owner = '<%= user.name %>'; +<% if user.mp_id ~= nil then %> + window.OwnerMpId = <%= json_string(user.mp_id) %>; +<% end %> + </script> +<% + min_head(user) + if has_reporting then +%> + <script async src="/reporting.js?s=<%=started%>"></script> +<% + end +end + +function Shared.page_header() +%> + <a header href="/"> + <img logo=big src="/images/logo.png"> + <img logo=small src="/images/small_logo.png"> + </a> +<% +end + +function Shared.body_header() + local user = current_user() +%> + <div header> + <a left href="/"> + <img logo=big src="/images/logo.png"> + <img logo=small src="/images/small_logo.png"> + </a> +<% if user == nil then %> + <span right login> + <a button login href="/login.html">Log in</a> + <a button register href="/register.html">Sign up</a> + </span> +<% else %> + <span right pulldown> + <img src="<%= user.get_pic_url() or "/images/user.png" %>" onclick="clickMenu(this)"> + <div pulldown_menu> + <a href="javascript:copyLink()"> + <span>linkmy.style/<%=user.name%></span> + <span copy>Copy</span> + </a> + <a href="/<%=user.name%>">My page</a> + <a href="/account.html">My account</a> + <a href="/links.html">Links</a> + <a href="/pics.html">Photos</a> + <a href="/theme.html">My theme</a> + <a href="/qr_code.html">QR code</a> + <a href="/analytics.html">Analytics</a> + <a href="javascript:logout()">Log out</a> + </div> + </span> + <input clipboard value="<%=base_url()%>/<%=user.name%>"> +<% end %> + </div> +<% +end + +function Shared.footer() +%> + <div footer> + <span> + <a href="/help.html">Help</a> + <br>support@linkmy.style + </span> + <span> + <a href="https://apps.apple.com/us/app/linkmystyle/id6475133762"><img ios src="/images/ios.svg"></a> + <a href="https://www.instagram.com/linkmy.style/"><img src="/images/icons/instagram.svg"></a> + </span> + </div> +<% +end + +function Shared.show_editable_link(link) +%> + <div link="<%=link.id%>"> + <div> + <a link pub_content href="<%=html_encode(link.url)%>" draggable=false><%=html_encode(link.title)%></a> + <img src="/images/drag_indicator.svg"> + </div> + <button type=button small onclick="editLink('<%=link.id%>')">Edit</button> + <button type=button small onclick="deleteLink1(this,'<%=link.id%>')">Delete</button> + </div> +<% +end + +function Shared.show_saved(close_url) +%> + <div saved> + <p>Your changes have been saved.</p> + <p><a href="/theme.html">Edit Theme</a></p> + <a close href="<%=close_url%>"><img src="/images/close.svg"></a> + </div> +<% +end + +function Shared.show_user_icons(user) + local icons = get_user_icons(user.id) +%> + <div list> +<% + for _, icon in ipairs(icons) do +%> + <span icon="<%=icon.id%>"> + <img src="/images/drag_indicator.svg"> + <a <%=icon.title_attr()%> href="<%=html_encode(icon.url)%>" draggable=false> + <img src="/images/icons/<%=icon.name%>.svg" draggable=false> + </a> + </span> +<% + end +%> + </div> + <button big onclick="ajax('/edit_icons.js')"><%= #icons==0 and "Add" or "Edit" %></button> +<% +end + +function Shared.js_error(field,message) +%> + showError( context.form, '<%=field%>', <%=json_string(message)%> ); +<% +end + +local send_mail = Mail.sender(Config.mail_server).send + +function Shared.send_mail_async(mail) + thread_run( function() + for i in range(1,5) do + try + send_mail(mail) + return + catch e + logger.error("send_mail_async fail "..i..":\n"..e) + sleep(10000) + end + end + error "send_mail_async failed" + end ) +end + +Shared.theme_fields = { + background_color = "#c0d1d6" + link_background_color = "#325762" + link_hover_background_color = "#243f47" + link_text_color = "#ffffff" + title_color = "#000000" + bio_color = "#000000" + icon_color = "" + link_border_radius = "12px / 50%" + link_border_color = "" + link_shadow = "" + link_shadow_color = "" + font = "Bitter" + font_url = "" + background_img_uuid = "" + background_img_filename = "" +} + +function Shared.password_input(value) + value = value or "" +%> + <div password> + <input type=password required name=password value="<%=html_encode(value)%>" placeholder="Password"> + <img show src="/images/visibility.svg" onclick="showPassword(parentNode)"> + <img hide src="/images/visibility_off.svg" onclick="hidePassword(parentNode)"> + </div> +<% +end + +function Shared.get_hashtags_list(pics) + local hashtags_set = {} + for _, pic in ipairs(pics) do + local hashtags = pic.hashtags + if hashtags ~= nil then + hashtags = to_list(hashtags) + for _, hashtag in ipairs(hashtags) do + hashtags_set[hashtag] = true + end + local classes = concat( hashtags, " " ) + pic.class = [[class="]]..classes..[["]] + end + end + local list = {} + for hashtag, v in pairs(hashtags_set) do + if v == true then + list[#list+1] = hashtag + end + end + return list, hashtags_set +end + +return Shared