Files
.sune/ev/landing.sune

1 line
6.7 KiB
Plaintext

[{"id":"fsr2nfx","name":"Landing Page","pinned":false,"avatar":"","url":"gh://multipleof4/.sune/ev/landing.sune","updatedAt":1758959352325,"settings":{"model":"google/gemini-2.5-pro","temperature":"","top_p":"","top_k":"","frequency_penalty":"","repetition_penalty":"","min_p":"","top_a":"","verbosity":"","reasoning_effort":"default","system_prompt":"","html":"<!--\n Sune: URL Shortener\n Version: 1.0.6\n-->\n<div x-data x-init=\"\n const $ = q => $el.querySelector(q);\n\n const loadScript=(src,c)=>new Promise((res,rej)=>{if(window[c])return res();const s=document.createElement('script');s.src=src;s.async=s.defer=!0;s.onload=res;s.onerror=()=>rej(`Failed to load ${src}`);document.head.appendChild(s)});\n\n const f = $('#shorten-form'), i = $('#url-input'), sb = $('#submit-button');\n const m = $('#message-area'), rb = $('#result-container'), ro = $('#result-output');\n const cb = $('#copy-button'), ob = $('#open-link-button');\n\n const norm = s => { try { return new URL((s=s.trim()).includes('://') ? s : 'https://' + s).href } catch { return '' } };\n\n const RC_KEY = '6LeXhdYrAAAAALW6DdgxNeHU0kwBncdicLnVYvXT';\n const rcEl = $('#recaptcha-container');\n loadScript('https://www.google.com/recaptcha/api.js', 'grecaptcha')\n .then(() => {\n grecaptcha.ready(() => {\n try { grecaptcha.render(rcEl, { sitekey: RC_KEY }) }\n catch (e) { m.textContent = 'Could not render CAPTCHA.' }\n });\n })\n .catch(() => m.textContent = 'Could not load CAPTCHA. Check connection or ad-blocker.');\n\n f.onsubmit = async e => {\n e.preventDefault();\n m.textContent = '';\n const u = norm(i.value);\n if (!u) return m.textContent = 'Please enter a valid URL.';\n\n if (typeof grecaptcha === 'undefined') return m.textContent = 'CAPTCHA not ready. Please try again.';\n const token = grecaptcha.getResponse();\n if (!token) return m.textContent = 'Please complete the CAPTCHA.';\n\n sb.disabled = true;\n sb.innerHTML = '…';\n\n try {\n const r = await fetch('https://4ev.link/api/create', {\n method: 'POST',\n headers: {'Content-Type': 'application/json'},\n body: JSON.stringify({url: u, token})\n });\n if (!r.ok) throw new Error(await r.text() || `Request failed: ${r.status}`);\n const d = await r.json();\n rb.hidden = false;\n ro.value = d.shortUrl;\n ob.href = d.shortUrl;\n } catch (err) {\n rb.hidden = true;\n m.textContent = err.message || 'An unknown error occurred.';\n } finally {\n grecaptcha.reset();\n sb.disabled = false;\n sb.innerHTML = 'Shorten';\n }\n };\n\n const setButtonIcon = (btn, iconName, colorClass = '') => {\n btn.innerHTML = `<i data-lucide='${iconName}' class='w-5 h-5 ${colorClass}'></i>`;\n lucide.createIcons();\n };\n\n cb.onclick = async () => {\n ro.select();\n try {\n await navigator.clipboard.writeText(ro.value);\n setButtonIcon(cb, 'check', 'text-green-500');\n setTimeout(() => setButtonIcon(cb, 'copy'), 1200);\n } catch {}\n };\n\n ro.onclick = () => ro.select();\n i.oninput = () => {\n rb.hidden = true;\n m.textContent = '';\n };\n\" class=\"relative bg-gray-50 dark:bg-neutral-950 text-gray-800 dark:text-gray-300 antialiased w-full max-w-2xl mx-auto rounded-2xl border border-gray-200 dark:border-neutral-800 overflow-hidden\">\n <a href=\"https://4ev.link\" target=\"_blank\" rel=\"noopener\" title=\"4ev.link Homepage\" class=\"absolute top-4 left-4 flex items-center gap-1.5 text-gray-800 dark:text-white hover:opacity-75 transition-opacity\">\n <svg class=\"w-6 h-6\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.72\"/><path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.72-1.72\"/>\n </svg>\n <span class=\"font-bold text-lg tracking-tight\">4ev.link</span>\n </a>\n <span class=\"absolute top-2 right-3 text-xs text-gray-400 dark:text-neutral-600\">v1.0.6</span>\n \n <section class=\"p-4 pt-20 sm:p-6 sm:pt-10 text-center\">\n <h1 class=\"text-2xl sm:text-3xl font-bold tracking-tight text-black dark:text-white\">\n Links that last <span class=\"text-gray-400 dark:text-neutral-500\">forever</span>.\n </h1>\n <p class=\"mt-2 max-w-2xl mx-auto text-sm text-gray-600 dark:text-neutral-400\">\n A simple, fast, and reliable URL shortener.\n </p>\n\n <form id=\"shorten-form\" class=\"mt-6 max-w-xl mx-auto flex flex-col gap-4\">\n <div class=\"flex flex-col sm:flex-row gap-3\">\n <div class=\"relative flex-1\">\n <i data-lucide=\"link\" class=\"absolute top-1/2 left-4 -translate-y-1/2 w-5 h-5 text-gray-400 dark:text-neutral-500 pointer-events-none\"></i>\n <input id=\"url-input\" type=\"text\" placeholder=\"your-long-link.com\" autocapitalize=\"off\" spellcheck=\"false\" class=\"w-full pl-11 pr-4 py-3 bg-white dark:bg-neutral-900 border border-gray-200 dark:border-neutral-800 rounded-lg focus:ring-2 focus:ring-black dark:focus:ring-white focus:outline-none transition-shadow\">\n </div>\n <button id=\"submit-button\" type=\"submit\" class=\"px-6 py-3 font-semibold bg-black dark:bg-white text-white dark:text-black rounded-lg hover:opacity-90 transition-opacity disabled:opacity-50 disabled:cursor-wait\">\n Shorten\n </button>\n </div>\n <div id=\"recaptcha-container\" class=\"self-center transform scale-[0.9] -translate-y-2 sm:scale-100 sm:translate-y-0 origin-center\"></div>\n </form>\n\n <div id=\"result-container\" hidden class=\"mt-4 max-w-xl mx-auto flex gap-2\">\n <input id=\"result-output\" type=\"text\" readonly class=\"flex-1 p-3 bg-gray-100 dark:bg-neutral-900 border border-gray-200 dark:border-neutral-800 rounded-lg text-sm text-center truncate\">\n <button id=\"copy-button\" type=\"button\" title=\"Copy to clipboard\" class=\"p-3 bg-gray-200 dark:bg-neutral-800 rounded-lg hover:opacity-80 transition-opacity\">\n <i data-lucide=\"copy\" class=\"w-5 h-5\"></i>\n </button>\n <a id=\"open-link-button\" target=\"_blank\" rel=\"noopener\" title=\"Open link in new tab\" class=\"p-3 bg-gray-200 dark:bg-neutral-800 rounded-lg hover:opacity-80 transition-opacity\">\n <i data-lucide=\"arrow-up-right\" class=\"w-5 h-5\"></i>\n </a>\n </div>\n\n <p id=\"message-area\" class=\"mt-3 text-red-500 text-sm h-5\"></p>\n </section>\n</div>\n","extension_html":"<sune src='https://raw.githubusercontent.com/sune-org/store/refs/heads/main/sync.sune' private></sune>","hide_composer":true,"include_thoughts":false,"json_output":false,"ignore_master_prompt":false,"json_schema":""},"storage":{}}]