Files
.sune/ev/landing.sune

1 line
5.7 KiB
Plaintext

[{"id":"fsr2nfx","name":"Landing Page","pinned":false,"avatar":"","url":"gh://multipleof4/.sune/ev/landing.sune","updatedAt":1758952548748,"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.4\n-->\n<div x-data x-init=\"\n const $ = q => $el.querySelector(q);\n\n const loadScript = (src, check) => new Promise((res, rej) => {\n if (window[check]) return res();\n const s = document.createElement('script');\n s.src = src;\n s.async = s.defer = true;\n s.onload = res;\n s.onerror = () => rej(`Failed to load ${src}`);\n document.head.appendChild(s);\n });\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 loadScript('https://www.google.com/recaptcha/api.js', 'grecaptcha')\n .catch(() => m.textContent = 'Could not load CAPTCHA.');\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 refresh.';\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 with status ${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 cb.onclick = async () => {\n ro.select();\n try {\n await navigator.clipboard.writeText(ro.value);\n cb.innerHTML = `<i data-lucide='check' class='w-5 h-5 text-green-500'></i>`;\n lucide.createIcons();\n setTimeout(() => {\n cb.innerHTML = `<i data-lucide='copy' class='w-5 h-5'></i>`;\n lucide.createIcons();\n }, 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 rounded-2xl border border-gray-200 dark:border-neutral-800 overflow-hidden\">\n <span class=\"absolute top-2 right-3 text-xs text-gray-400 dark:text-neutral-600\">v1.0.4</span>\n <section class=\"p-4 sm:p-6 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 <label 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\"></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\">\n </label>\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 class=\"g-recaptcha self-center\" data-sitekey=\"6LeXhdYrAAAAALW6DdgxNeHU0kwBncdicLnVYvXT\"></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":{}}]