init commit
This commit is contained in:
parent
dfe324cf8f
commit
7e37f1bbe0
31 changed files with 2103 additions and 718 deletions
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { fade, fly } from "svelte/transition";
|
||||
|
||||
let { errorMessage = null as string | null, duration = 5000 } = $props();
|
||||
let { errorMessage = $bindable(), duration = 5000 } = $props();
|
||||
|
||||
$effect(() => {
|
||||
if (!errorMessage) {
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
timeoutId = setTimeout(() => {
|
||||
visible = false;
|
||||
timeoutId = null;
|
||||
errorMessage = "";
|
||||
}, duration);
|
||||
});
|
||||
|
||||
|
|
@ -27,7 +28,7 @@
|
|||
in:fly={{ y: -70, duration: 500 }}
|
||||
out:fade={{ duration: 300 }}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 shrink-0 stroke-current" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
||||
<svg class="h-6 w-6 shrink-0 stroke-current" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
||||
<span>{errorMessage}</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
55
src/lib/Footer.svelte
Normal file
55
src/lib/Footer.svelte
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<script>
|
||||
import { auth } from "./auth.svelte";
|
||||
const year = new Date().getFullYear();
|
||||
</script>
|
||||
|
||||
<footer class="flex items-center justify-center bg-base-200 text-base-content p-10 mt-15 z-9">
|
||||
<div class="footer footer-horizontal max-w-800">
|
||||
<div class="hidden sm:block"></div>
|
||||
<div class="hidden sm:block"></div>
|
||||
<aside>
|
||||
<svg
|
||||
width="50"
|
||||
height="50"
|
||||
viewBox="0 0 24 24"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
class="fill-current">
|
||||
<path
|
||||
d="M22.672 15.226l-2.432.811.841 2.515c.33 1.019-.209 2.127-1.23 2.456-1.15.325-2.148-.321-2.463-1.226l-.84-2.518-5.013 1.677.84 2.517c.391 1.203-.434 2.542-1.831 2.542-.88 0-1.601-.564-1.86-1.314l-.842-2.516-2.431.809c-1.135.328-2.145-.317-2.463-1.229-.329-1.018.211-2.127 1.231-2.456l2.432-.809-1.621-4.823-2.432.808c-1.355.384-2.558-.59-2.558-1.839 0-.817.509-1.582 1.327-1.846l2.433-.809-.842-2.515c-.33-1.02.211-2.129 1.232-2.458 1.02-.329 2.13.209 2.461 1.229l.842 2.515 5.011-1.677-.839-2.517c-.403-1.238.484-2.553 1.843-2.553.819 0 1.585.509 1.85 1.326l.841 2.517 2.431-.81c1.02-.33 2.131.211 2.461 1.229.332 1.018-.21 2.126-1.23 2.456l-2.433.809 1.622 4.823 2.433-.809c1.242-.401 2.557.484 2.557 1.838 0 .819-.51 1.583-1.328 1.847m-8.992-6.428l-5.01 1.675 1.619 4.828 5.011-1.674-1.62-4.829z"></path>
|
||||
</svg>
|
||||
<p>
|
||||
© 2025-{year} HexName
|
||||
<br/>
|
||||
Focus on what truly matters.
|
||||
</p>
|
||||
</aside>
|
||||
<nav>
|
||||
<p class="footer-title">Services</p>
|
||||
<div>
|
||||
<a class="link link-hover" href="/register">Register</a> /
|
||||
<a class="link link-hover" href="/login">Log in</a>
|
||||
</div>
|
||||
{#if auth.isAuthenticated}
|
||||
<a class="link link-hover" href="/dashboard/register-domain">Register a domain</a>
|
||||
{:else}
|
||||
<a class="link link-hover" href="/#search-for-your-domain">Search for a domain</a>
|
||||
{/if}
|
||||
<a class="link link-hover" href="/#contact-us">Contact us!</a>
|
||||
</nav>
|
||||
<nav>
|
||||
<p class="footer-title">Pages</p>
|
||||
<a class="link link-hover" href="/">Home</a>
|
||||
<a class="link link-hover" href="/about">About</a>
|
||||
<a class="link link-hover" href="/faq">Frequently asked questions</a>
|
||||
</nav>
|
||||
<nav>
|
||||
<p class="footer-title">Legal</p>
|
||||
<a class="link link-hover" href="/terms-of-service">Terms of service</a>
|
||||
<a class="link link-hover" href="/privacy-policy">Privacy policy</a>
|
||||
<a class="link link-hover" href="cookie-policy">Cookie policy</a>
|
||||
</nav>
|
||||
<div class="hidden sm:block"></div>
|
||||
<div class="hidden sm:block"></div>
|
||||
</div>
|
||||
</footer>
|
||||
|
|
@ -26,26 +26,25 @@
|
|||
auth.isMfaEnabled = !auth.isMfaEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
let { sideMenuOpen = $bindable(), isMobile } = $props()
|
||||
</script>
|
||||
|
||||
<div class="navbar bg-base-100 shadow-sm top-0 z-10 py-0">
|
||||
<div class="backdrop-blur bg-white/6 fixed navbar shadow-sm top-0 z-40 py-0" id="main-navbar">
|
||||
<div class="navbar-start">
|
||||
<div class="dropdown">
|
||||
<div tabindex="0" role="button" class="btn btn-ghost lg:hidden">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h8m-8 6h16" /> </svg>
|
||||
</div>
|
||||
<ul
|
||||
tabindex="-1"
|
||||
class="menu menu-sm dropdown-content bg-base-100 rounded-box z-1 mt-3 w-52 p-2 shadow">
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/about">About us</a></li>
|
||||
<li><a href="/faq">FAQ</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<a class="btn btn-ghost text-xl" href="/">HexName</a>
|
||||
{#if auth.isAuthenticated || isMobile}
|
||||
<button aria-label="toggle side menu" onclick={() => {sideMenuOpen = !sideMenuOpen}}>
|
||||
<ul class="menu p-0"><li>
|
||||
<div class="p-2.5">
|
||||
<svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h8m-8 6h16"/></svg>
|
||||
</div>
|
||||
</li></ul>
|
||||
</button>
|
||||
{/if}
|
||||
<ul class="menu pl-0"><li><a href="/" class="text-xl font-semibold">HexName</a></li></ul>
|
||||
</div>
|
||||
<div class="navbar-center hidden lg:flex">
|
||||
<ul class="menu menu-horizontal px-1">
|
||||
<div class="navbar m-0 w-100">
|
||||
<ul class="menu menu-horizontal not-md:hidden m-auto justify-center items-center">
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/about">About us</a></li>
|
||||
<li><a href="/faq">FAQ</a></li>
|
||||
|
|
@ -53,35 +52,39 @@
|
|||
</div>
|
||||
<div class="navbar-end">
|
||||
{#if auth.isAuthenticated}
|
||||
<div class="dropdown dropdown-end">
|
||||
<div tabindex="0" role="button" class="btn btn-ghost btn-circle avatar">
|
||||
<svg class="size-9" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="#dfe5ed"><path stroke-linecap="round" stroke-linejoin="round" d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" /></svg>
|
||||
<div class="dropdown dropdown-end z-40">
|
||||
<div tabindex="0" role="button" class="btn btn-ghost btn-circle avatar" aria-label="profile icon">
|
||||
<svg class="size-9" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="#dfe5ed"><path stroke-linecap="round" stroke-linejoin="round" d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" /></svg>
|
||||
</div>
|
||||
<ul
|
||||
tabindex="-1"
|
||||
class="menu menu-sm dropdown-content bg-base-200 rounded-box z-40 mt-3 w-52 p-2 shadow">
|
||||
<li><text class="font-bold">{auth.userEmail}</text></li>
|
||||
<!-- <li><input type="checkbox" value="light" class="toggle theme-controller"/></li> -->
|
||||
<!-- <li>
|
||||
<div class="justify-between">
|
||||
2-factor via email
|
||||
<label class="toggle text-base-content outline-transparent">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={auth.isMfaEnabled}
|
||||
onchange={toggleMfa}
|
||||
/>
|
||||
<svg class="outline-transparent" aria-label="disabled" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18" /><path d="m6 6 12 12"/></svg>
|
||||
<svg class="outline-transparent" aria-label="enabled" viewBox="0 0 24 24"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="4" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"></path></g></svg>
|
||||
</label>
|
||||
</div>
|
||||
</li> -->
|
||||
<li><a href="/delete-account">Delete account</a></li>
|
||||
<li><a href="/logout">Log out</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<ul
|
||||
tabindex="-1"
|
||||
class="menu menu-sm dropdown-content bg-base-200 rounded-box z-10 mt-3 w-52 p-2 shadow">
|
||||
<li><text class="font-bold">{auth.userEmail}</text></li>
|
||||
<li>
|
||||
<div class="justify-between">
|
||||
2-factor via email
|
||||
<label class="toggle text-base-content outline-transparent">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={auth.isMfaEnabled}
|
||||
on:change={toggleMfa}
|
||||
/>
|
||||
<svg class="outline-transparent" aria-label="disabled" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18" /><path d="m6 6 12 12"/></svg>
|
||||
<svg class="outline-transparent" aria-label="enabled" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="4" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"></path></g></svg>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
<li><a href="/delete-account">Delete account</a></li>
|
||||
<li><a href="/logout">Log out</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{:else}
|
||||
<a href="/register"><button class="btn btn-sm btn-primary rounded-lg mr-2">Create an account</button></a>
|
||||
<a href="/login"><button class="btn btn-sm btn-secondary rounded-lg mr-2">Log in</button></a>
|
||||
<div class="gap-4 flex">
|
||||
<a href="/register"><button style="box-shadow: 0 0 10px rgba(0,0,0,0.6)" class="btn btn-primary break-keep whitespace-nowrap rounded-lg">Create an account</button></a>
|
||||
<a href="/login"><button style="box-shadow: 0 0 10px rgba(0,0,0,0.6)" class="btn btn-outline btn-secondary whitespace-nowrap border-2 rounded-lg">Log in</button></a>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="divider bg-primary-content/20 fixed mt-[63px] z-41 h-0.25 w-screen"></div>
|
||||
|
|
|
|||
112
src/lib/Phone.svelte
Normal file
112
src/lib/Phone.svelte
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
<script>
|
||||
let { isRotated } = $props();
|
||||
</script>
|
||||
|
||||
<div class={isRotated ? "rotate-x-40 rotate-z-35" : ""}>
|
||||
<div class=".max-w-90 .min-w-90">
|
||||
<div class="flex flex-col items-center">
|
||||
<div class="mockup-phone border-primary">
|
||||
<div class="mockup-phone-camera"></div>
|
||||
<div class="mockup-phone-display text-white .grid .place-content-center bg-base-200">
|
||||
<div class="flex flex-col h-full w-full">
|
||||
<div class="p-4 text-xs my-8">
|
||||
<pre>$ dig example.hexname.com -t TXT +short</pre>
|
||||
<pre class="text-success">"v=spf1 mx ra=spf-reports -all"</pre>
|
||||
<pre>$</pre>
|
||||
<pre>$</pre>
|
||||
<pre>$ dig example.hexname.com +short</pre>
|
||||
<pre class="text-success">198.51.100.98</pre>
|
||||
<pre>$ curl icanhazip.com</pre>
|
||||
<pre class="text-success">198.51.100.135</pre>
|
||||
<pre>$ ./update-ddns.sh</pre>
|
||||
<pre>$ dig example.hexname.com +short</pre>
|
||||
<pre class="text-success">198.51.100.135</pre>
|
||||
<pre>$ <text class="animate-terminal-blink">█</text></pre>
|
||||
</div>
|
||||
|
||||
<div class="mt-auto bg-base-300 w-full p-1 text-xs">
|
||||
<div class="my-1 grid grid-cols-7 w-full justify-items-center items-center gap-1">
|
||||
<kbd>ESC</kbd>
|
||||
<kbd>/</kbd>
|
||||
<kbd>-</kbd>
|
||||
<kbd>HOME</kbd>
|
||||
<kbd class="scale-130">↑</kbd>
|
||||
<kbd>END</kbd>
|
||||
<kbd>PGUP</kbd>
|
||||
<kbd>
|
||||
<svg class="size-3.5" fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M22 4.25a.75.75 0 00-1.5 0v15a.75.75 0 001.5 0v-15zm-9.72 14.28a.75.75 0 11-1.06-1.06l4.97-4.97H1.75a.75.75 0 010-1.5h14.44l-4.97-4.97a.75.75 0 011.06-1.06l6.25 6.25a.75.75 0 010 1.06l-6.25 6.25z"/></svg>
|
||||
</kbd>
|
||||
<kbd>CTRL</kbd>
|
||||
<kbd>ALT</kbd>
|
||||
<kbd class="scale-130">←</kbd>
|
||||
<kbd class="scale-130">↓</kbd>
|
||||
<kbd class="scale-130">→</kbd>
|
||||
<kbd>PGDN</kbd>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-base-100 mb-5 py-2 w-full">
|
||||
<div class="flex w-full justify-center gap-1">
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="q">q</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="w">w</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="e">e</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="r">r</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="t">t</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="y">y</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="u">u</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="i">i</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="o">o</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="p">p</kbd>
|
||||
</div>
|
||||
<div class="my-1 flex w-full justify-center gap-1">
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="a">a</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="s">s</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="d">d</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="f">f</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="g">g</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="h">h</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="j">j</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="k">k</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="l">l</kbd>
|
||||
</div>
|
||||
<div class="my-1 flex w-full justify-center gap-1">
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10">
|
||||
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none"><path d="M8 17V12H5.6302C4.71068 12 4.27858 10.8635 4.96584 10.2526L10.6713 5.18109C11.429 4.50752 12.571 4.50752 13.3287 5.18109L19.0342 10.2526C19.7214 10.8635 19.2893 12 18.3698 12H16V17C16 18.1046 15.1046 19 14 19H10C8.89543 19 8 18.1046 8 17Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="z">z</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="x">x</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="c">c</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="v">v</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="b">b</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="n">n</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="m">m</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip="/">/</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10">
|
||||
<svg class="w-4.5 h-4.5" viewBox="0 0 24 24" fill="none"><path d="M7.91987 5C7.33602 5 6.78132 5.25513 6.40136 5.69842L2.11564 10.6984C1.47366 11.4474 1.47366 12.5526 2.11564 13.3016L6.40136 18.3016C6.78132 18.7449 7.33602 19 7.91987 19L19 19C20.1046 19 21 18.1046 21 17L21 7C21 5.89543 20.1046 5 19 5L7.91987 5Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/><path d="M15 10.0001L11 14.0001" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/><path d="M11 10.0001L15 14.0001" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/></svg>
|
||||
</kbd>
|
||||
</div>
|
||||
<div class="my-1 flex w-full justify-center gap-1">
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10">123</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip=",">,</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 w-39.5 text-xs text-primary-content/60">< Space ></kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10 hover:tooltip hover:tooltip-primary" data-tip=".">.</kbd>
|
||||
<kbd class="kbd h-7 cursor-pointer hover:-translate-y-[2px] hover:bg-white/10">
|
||||
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M20.239 3.749a.75.75 0 0 0-.75.75V15H5.549l2.47-2.47a.75.75 0 0 0-1.06-1.06l-3.75 3.75a.75.75 0 0 0 0 1.06l3.75 3.75a.75.75 0 1 0 1.06-1.06L5.55 16.5h14.69a.75.75 0 0 0 .75-.75V4.5a.75.75 0 0 0-.75-.751Z" clip-rule="evenodd"/></svg>
|
||||
</kbd>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col items-center">
|
||||
{#if isRotated}
|
||||
<div style="box-shadow: 0 0 200px rgba(18, 68, 227, 0.8)" class="absolute mockup-phone shadow-2xl shadow-primary/50 border-black/40 border-[3.5px] bg-white/55 -z-1 -translate-y-178 translate-x-5 scale-93 max-w-90 min-w-90"></div>
|
||||
<div style="border-bottom: 1.5px solid" class="absolute rounded-lg -translate-y-128 translate-x-44 rotate-90 z-9 w-25 h-[10px] bg-black/65"></div>
|
||||
<div style="border-bottom: 1.5px solid" class="absolute rounded-lg -translate-y-100 translate-x-44 rotate-90 z-9 w-15 h-[10px] bg-black/65"></div>
|
||||
<div style="border-left: 1.5px solid; border-bottom: 1.5px solid;" class="absolute rounded-lg ml-3 mt-[3px] w-10 h-3 border-2 border-white/15 bg-black/80"></div>
|
||||
{:else}
|
||||
<div style="box-shadow: 0 0 200px rgba(18, 68, 227, 0.8)" class="absolute mockup-phone -z-1 -translate-y-177 scale-93 w-80"></div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -8,8 +8,103 @@
|
|||
let { records = $bindable(), record, i, fqdn, error }: { records: DnsRecord[], record: DnsRecord, i: number, fqdn: string, error: string } = $props();
|
||||
|
||||
let isEdit = $state(false);
|
||||
let recordDraft = $state($state.snapshot(record));
|
||||
$effect(() => {
|
||||
records.length;
|
||||
isEdit = false;
|
||||
})
|
||||
let errorMessage = $state('');
|
||||
// svelte-ignore state_referenced_locally
|
||||
let recordDraft = $state($state.snapshot(record));
|
||||
// svelte-ignore state_referenced_locally
|
||||
let hasToken = $state(record.has_token);
|
||||
|
||||
let tokenScript = $derived.by(() => {
|
||||
if (record.record_type === "A") {
|
||||
return "#!/bin/bash\n" +
|
||||
"IP=$(curl -s http://ipv4.icanhazip.com)\n" +
|
||||
`curl -X PUT https://hexname.com/api/v1/ddns/ipv4/${token}/$IP`
|
||||
} else if (record.record_type === "AAAA") {
|
||||
return "#!/bin/bash\n" +
|
||||
"IP=$(curl -s http://ipv6.icanhazip.com)\n" +
|
||||
`curl -X PUT https://hexname.com/api/v1/ddns/ipv6/${token}/$IP`
|
||||
} else {
|
||||
return "A weird error happened. Please contact support with this screenshot.";
|
||||
}
|
||||
});
|
||||
|
||||
let copied = $state(false);
|
||||
let resetTimer: NodeJS.Timeout | undefined;
|
||||
|
||||
function copyToken() {
|
||||
if (copied) return;
|
||||
|
||||
navigator.clipboard.writeText(tokenScript);
|
||||
copied = true;
|
||||
let btn = document.getElementById("copy-btn")
|
||||
btn?.classList.add("swap-active");
|
||||
|
||||
clearTimeout(resetTimer);
|
||||
resetTimer = setTimeout(() => {
|
||||
copied = false;
|
||||
btn?.classList.remove("swap-active");
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
let modal: HTMLDialogElement | null = $state(null);
|
||||
let token = $state('');
|
||||
async function generateToken() {
|
||||
try {
|
||||
let res = await fetch(`${PUBLIC_BACKEND_API_HOST}/api/v1/record/ddns-token`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({"id": record.id })});
|
||||
|
||||
if (!res.ok) {
|
||||
errorMessage = (await res.json()).msg || "Something went wrong";
|
||||
console.log(errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
let data = await res.json();
|
||||
if (!res.ok) {
|
||||
errorMessage = data?.msg || "Something went wrong";
|
||||
console.log(errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
token = data.token;
|
||||
modal?.showModal();
|
||||
} catch (err: any) {
|
||||
errorMessage = err?.msg || "Network error";
|
||||
console.log(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
async function revokeToken() {
|
||||
try {
|
||||
let res = await fetch(`${PUBLIC_BACKEND_API_HOST}/api/v1/record/ddns-token`, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({"id": record.id })});
|
||||
|
||||
if (!res.ok) {
|
||||
errorMessage = (await res.json()).msg || "Something went wrong";
|
||||
console.log(errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!res.ok) {
|
||||
errorMessage = "Something went wrong";
|
||||
console.log(errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
hasToken = false;
|
||||
} catch (err: any) {
|
||||
errorMessage = err?.msg || "Network error";
|
||||
console.log(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
function triggerMenu() {
|
||||
if (isEdit) {
|
||||
|
|
@ -69,7 +164,6 @@
|
|||
}
|
||||
|
||||
records = handleUiRecordUpdates(records, data);
|
||||
alert("Record successfully updated!")
|
||||
} catch (err: any) {
|
||||
errorMessage = err?.msg || "Network error";
|
||||
console.log(errorMessage);
|
||||
|
|
@ -101,10 +195,11 @@
|
|||
|
||||
<tr
|
||||
class={isEdit
|
||||
? "bg-base-300"
|
||||
? "bg-primary/30"
|
||||
// ? "bg-base-300"
|
||||
:
|
||||
`${
|
||||
i % 2 === 0 ? '[&>td]:bg-base-100' : '[&>td]:bg-base-200'
|
||||
i % 2 === 0 ? '[&>td]:bg-base-100' : '[&>td]:bg-base-200/60'
|
||||
}`
|
||||
}
|
||||
>
|
||||
|
|
@ -124,12 +219,12 @@
|
|||
</td>
|
||||
<td class="w-0 p-0 px-4">
|
||||
{#if isEdit}
|
||||
<button class="btn btn-xs tooltip rounded-md p-0 w-7 h-7" data-tip="Discard changes" onclick={triggerMenu}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" /></svg>
|
||||
<button class="btn btn-xs tooltip rounded-md p-0 w-7 h-7" data-tip="Discard changes" aria-label="close icon" onclick={triggerMenu}>
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" /></svg>
|
||||
</button>
|
||||
{:else}
|
||||
<button class="btn btn-xs tooltip rounded-md p-0 w-7 h-7" data-tip="Edit" onclick={triggerMenu}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6"><path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" /></svg>
|
||||
<button class="btn btn-xs tooltip rounded-md p-0 w-7 h-7" data-tip="Edit" aria-label="pencil icon" onclick={triggerMenu}>
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6"><path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" /></svg>
|
||||
</button>
|
||||
{/if}
|
||||
</td>
|
||||
|
|
@ -154,7 +249,7 @@
|
|||
<label class="fieldset-legend mr-1" for="record-priority">Priority</label>
|
||||
<div class="tooltip tooltip-info mt-1" data-tip="This field is useful if you have multiple mailservers. The server with the lower priority is tried first. If it fails to receive mail, the one with the next lowest priority is tried. Set the same priority values for for load-balancing.">
|
||||
<div role="alert" class="alert m-0 p-0 gap-2 flex flex-column justify-center ml-auto ">
|
||||
<svg class="stroke-primary-content h-4 w-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
||||
<svg class="stroke-primary-content h-4 w-4" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -171,7 +266,7 @@
|
|||
<label class="fieldset-legend mr-1" for="record-priority">Priority</label>
|
||||
<div class="tooltip tooltip-info mt-1" data-tip="This field is useful if you have multiple servers. The server with the lower priority is prioritized for traffic.">
|
||||
<div role="alert" class="alert m-0 p-0 gap-2 flex flex-column justify-center ml-auto ">
|
||||
<svg class="stroke-primary-content h-4 w-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
||||
<svg class="stroke-primary-content h-4 w-4" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -185,7 +280,7 @@
|
|||
<label class="fieldset-legend mr-1" for="record-weight">Weight</label>
|
||||
<div class="tooltip tooltip-info mt-1" data-tip="This field serves a similar purpose as the Priority, except it is looked at second. So priority takes precedence.">
|
||||
<div role="alert" class="alert m-0 p-0 gap-2 flex flex-column justify-center ml-auto ">
|
||||
<svg class="stroke-primary-content h-4 w-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
||||
<svg class="stroke-primary-content h-4 w-4" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -210,6 +305,7 @@
|
|||
<div class="align-right validator-hint mt-1">{error}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row">
|
||||
<label class="m-2 form-control flex flex-1 flex-col">
|
||||
<div class="flex flex-row">
|
||||
|
|
@ -226,7 +322,7 @@
|
|||
<label class="fieldset-legend mr-1" for="record-ttl">TTL</label>
|
||||
<div class="tooltip tooltip-info mt-1" data-tip="TTL or 'Time To Live' controls how long the record is allowed to be cached on different devices. Set a lower number if you expect your record to change value very often.">
|
||||
<div role="alert" class="alert m-0 p-0 gap-2 flex flex-column justify-center ml-auto ">
|
||||
<svg class="stroke-primary-content h-4 w-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
||||
<svg class="stroke-primary-content h-4 w-4" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -245,6 +341,55 @@
|
|||
bind:checked={recordDraft.is_active}
|
||||
/>
|
||||
</label>
|
||||
{#if record.record_type === 'A' || record.record_type === "AAAA"}
|
||||
{#if hasToken}
|
||||
<button class="btn text-error" type="button" onclick={() => modal?.showModal()}>Revoke DDNS token</button>
|
||||
<dialog bind:this={modal} class="modal">
|
||||
<div class="modal-box">
|
||||
<h3 class="text-lg font-bold">Are you sure you want to revoke this DDNS token?</h3>
|
||||
<p class="py-4">You won't be able to use the token to update this record anymore.<br>You can generate a new token anytime.</p>
|
||||
<div class="modal-action gap-6">
|
||||
<button class="btn w-30 btn-primary mr-auto" type="button" onclick={() => modal?.close()}>Go back</button>
|
||||
<button class="btn w-30 btn-error ml-auto" type="button" onclick={() => { revokeToken(); modal?.close();}}>Revoke</button>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
{:else}
|
||||
<button class="btn text-success" type="button" onclick={generateToken}>Generate DDNS token</button>
|
||||
<dialog bind:this={modal} class="modal">
|
||||
<div class="modal-box w-fill lg:w-250 max-w-none">
|
||||
<h3 class="text-lg font-bold">DDNS token generated!</h3>
|
||||
<p class="py-4">This token will only be shown once now. Make sure to save it.</p>
|
||||
<code>{token}</code>
|
||||
<p class="py-4">Or use this Bash script to update your IP:</p>
|
||||
<div class="mockup-code my-2 relative bg-base-200">
|
||||
<label id="copy-btn" class="btn btn-circle swap swap-rotate absolute top-2 right-2">
|
||||
<input type="checkbox" bind:checked={copied} onclick={(e) => {e.preventDefault(); copyToken();}}/>
|
||||
<svg class="size-6 swap-off" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0 0 13.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 0 1-.75.75H9a.75.75 0 0 1-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 0 1-2.25 2.25H6.75A2.25 2.25 0 0 1 4.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 0 1 1.927-.184"/></svg>
|
||||
<svg class="size-6 swap-on" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"/></svg>
|
||||
</label>
|
||||
<div class="overflow-x-auto p-2">
|
||||
{#if record.record_type === 'A'}
|
||||
<pre><code>#!/bin/bash</code></pre>
|
||||
<pre><code>IP=$(curl -s http://ipv4.icanhazip.com)</code></pre>
|
||||
<pre><code>curl -X PUT https://hexname.com/api/v1/ddns/ipv4/{token}/$IP</code></pre>
|
||||
{:else if record.record_type === 'AAAA'}
|
||||
<pre><code>#!/bin/bash</code></pre>
|
||||
<pre><code>IP=$(curl -s http://ipv6.icanhazip.com)</code></pre>
|
||||
<pre><code>curl -X PUT https://hexname.com/api/v1/ddns/ipv6/{token}/$IP</code></pre>
|
||||
{:else}
|
||||
A weird error happened. Please contact support with this screenshot.
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-action">
|
||||
<button class="btn btn-primary w-30" type="button" onclick={() => { modal?.close(); hasToken = true; token = '';} }>Got it!</button>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<button class="btn btn-error m-2 p-0 w-full sm:w-30" type="button" onclick={handleDeleteRecord}>Delete record</button>
|
||||
<button class="btn btn-primary m-2 p-0 w-full sm:w-30" type="submit">Save</button>
|
||||
</div>
|
||||
|
|
@ -252,7 +397,7 @@
|
|||
<RecordExplanation recordType={recordDraft.record_type} name={recordDraft.name} value={recordDraft.value} displayName={getDisplayName(recordDraft.record_type, recordDraft.name)} displayValue={getDisplayValue(recordDraft.record_type, recordDraft.value, fqdn)} {fqdn}/>
|
||||
{#if errorMessage}
|
||||
<div class="mt-3 h-12 flex items-center">
|
||||
<ErrorPopup {errorMessage} duration={10000} />
|
||||
<ErrorPopup bind:errorMessage={errorMessage} duration={10000} />
|
||||
</div>
|
||||
{/if}
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -1,35 +1,60 @@
|
|||
<script lang="ts">
|
||||
import { domains } from "./domains.svelte";
|
||||
|
||||
let errorMessage: string | null = $state(null);
|
||||
import { auth } from '$lib/auth.svelte';
|
||||
let { sideMenuOpen = $bindable(), isDashboard } = $props()
|
||||
</script>
|
||||
|
||||
<aside class="bg-base-200">
|
||||
<ul class="menu overflow-y-auto h-full w-0 sm:w-60 hidden lg:block max-h-full scroll">
|
||||
<li>
|
||||
<a href="/dashboard/register-domain">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</svg>
|
||||
Register a new domain
|
||||
</a>
|
||||
{#if sideMenuOpen}
|
||||
<button aria-label="close side menu" class={`fixed inset-0 top-16
|
||||
${isDashboard ? "not-lg:bg-black/40 not-lg:backdrop-blur-sm z-30 lg:-z-10"
|
||||
: "bg-black/40 backdrop-blur-sm z-30"}`}
|
||||
onclick={() => {sideMenuOpen = false}}
|
||||
></button>
|
||||
{/if}
|
||||
<aside
|
||||
class={`
|
||||
fixed top-16 w-60 bg-white/6 transition-transform
|
||||
${sideMenuOpen ? 'translate-x-0' : '-translate-x-60.25'}
|
||||
lg:translate-x-0.
|
||||
duration-250 ease-in-out
|
||||
z-31
|
||||
`}
|
||||
>
|
||||
<ul class="menu bg-white/6 h-[calc(100vh-65px)] z-9 w-60 block min-h-0 overflow-y-auto">
|
||||
{#if isDashboard}
|
||||
<li class="bg-base-300 opacity-0 lg:opacity-100 h-screen fixed -z-1 w-60 top-0 left-0 m-0"></li>
|
||||
{/if}
|
||||
<li class="md:hidden block">
|
||||
<a href="/">Home</a>
|
||||
<a href="/about">About us</a>
|
||||
<a href="/faq">FAQ</a>
|
||||
</li>
|
||||
{#if !domains.loadingSubdomains}
|
||||
{#if auth.isAuthenticated}
|
||||
<div class="sm:hidden divider m-0"></div>
|
||||
<li>
|
||||
<a href="/dashboard/register-domain">
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15"/>
|
||||
</svg>
|
||||
Register a new domain
|
||||
</a>
|
||||
</li>
|
||||
{/if}
|
||||
{#if !domains.loadingSubdomains}
|
||||
<div class="divider m-0"></div>
|
||||
<li>
|
||||
<details open>
|
||||
<summary>Manage your DNS records</summary>
|
||||
<ul>
|
||||
{#each domains.subdomains as sub}
|
||||
<li><a href="/dashboard/{sub.id}">
|
||||
{sub.name}.{sub.domain}
|
||||
</a></li>
|
||||
{/each}
|
||||
</ul>
|
||||
</details>
|
||||
<a href="/dashboard">Manage your DNS records</a>
|
||||
<ul>
|
||||
{#each domains.subdomains as sub}
|
||||
<li><a href="/dashboard/{sub.id}">
|
||||
{sub.name}.{sub.domain}
|
||||
</a></li>
|
||||
{/each}
|
||||
</ul>
|
||||
</li>
|
||||
{:else if domains.loadingFailed}
|
||||
<li class="bg-error rounded"><a class="text-error-content" href="/logout">Loading your domains failed. Please refresh the page or try logging out and back in</a></li>
|
||||
{/if}
|
||||
</ul>
|
||||
</aside>
|
||||
<div class="divider divider-vertical bg-primary-content/35 fixed w-0.25 h-[calc(100vh-65px)] top-0 z-10 m-0 ml-60"> </div>
|
||||
</aside>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ export interface DnsRecord {
|
|||
priority?: number;
|
||||
weight?: number;
|
||||
port?: number;
|
||||
has_token?: boolean;
|
||||
}
|
||||
|
||||
export interface RecordsResponse {
|
||||
|
|
|
|||
23
src/lib/slideIn.ts
Normal file
23
src/lib/slideIn.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
export function slideIn(node: HTMLElement) {
|
||||
const observer = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
if (entry.isIntersecting) {
|
||||
node.classList.add("opacity-100");
|
||||
node.classList.remove("opacity-0", "lg:translate-x-60", "lg:-translate-x-60", "translate-x-30", "-translate-x-30", "lg:-translate-x-60", "not-lg:translate-y-40");
|
||||
observer.unobserve(node);
|
||||
}
|
||||
},
|
||||
{
|
||||
threshold: 0,
|
||||
rootMargin: "0px 0px -20% 0px"
|
||||
}
|
||||
);
|
||||
|
||||
observer.observe(node);
|
||||
|
||||
return {
|
||||
destroy() {
|
||||
observer.disconnect();
|
||||
}
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue