Align hostname choice layout

This commit is contained in:
StasonJatham committed 2026-05-20 20:14:59 +02:00
1 parent 2966a69331
commit 12fb14984c
3 files changed
+41 -35

No files matched your search

Binary file not shown.

Before

Width:  |  Height:  |  Size: 576 KiB

After

Width:  |  Height:  |  Size: 660 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 KiB

After

Width:  |  Height:  |  Size: 420 KiB

+41 -35
View File
@@ -664,23 +664,42 @@ def _render_public_home(
{created_html} {created_html}
<section class="section" id="create"> <section class="section" id="create">
<div class="container narrow"> <div class="container narrow">
<div class="row g-4 align-items-center"> <div class="text-center mb-4">
<div class="col-lg-6"> <p class="eyebrow">Choose your hostname</p>
<p class="eyebrow">Create in one step</p>
<h2>No account. No login.</h2> <h2>No account. No login.</h2>
<p class="section-copy">The generated URL is the secret. FRITZ!Box replaces <code>&lt;ipaddr&gt;</code> and calls it when your public IP changes.</p> <p class="section-copy mx-auto">Use a generated KarlDNS hostname immediately, or verify your own domain with a DNS TXT record.</p>
</div>
<div class="row g-4 align-items-stretch">
<div class="col-lg-6">
<div class="card card-body h-100 gap-3">
<p class="eyebrow">Use our domain</p>
<h3>Generate a KarlDNS hostname</h3>
<p class="section-copy mb-0">KarlDNS generates the hostname, secret update URL, and optional router compatibility credentials automatically.</p>
<form method="post" action="/magic" class="d-grid gap-3" aria-label="Create a generated DynDNS hostname">
<button type="submit" class="btn btn-primary rounded-pill">Generate hostname</button>
</form>
</div>
</div>
<div class="col-lg-6">
<div class="card card-body h-100 gap-3">
<p class="eyebrow">Use your own domain</p>
<h3>Verify DNS ownership</h3>
<p class="section-copy mb-0">Add one TXT record so KarlDNS can confirm you control the domain before it publishes A/AAAA records there.</p>
<form method="post" action="/request-domain" class="d-grid gap-3" aria-label="Request a custom domain TXT challenge">
<label>Domain
<input class="form-control" name="domain" placeholder="example.com" autocomplete="off" autocapitalize="none" spellcheck="false" required>
</label>
<button type="submit" class="btn btn-primary rounded-pill">Create TXT challenge</button>
</form>
</div>
</div>
</div>
<div class="terminal-card mt-4" aria-hidden="true"> <div class="terminal-card mt-4" aria-hidden="true">
<div class="terminal-dots"><span></span><span></span><span></span></div> <div class="terminal-dots"><span></span><span></span><span></span></div>
<code>$ curl -sS 'https://karldns.de/u/&lt;secret&gt;?myip=203.0.113.10'</code> <code>$ curl -sS 'https://karldns.de/u/&lt;secret&gt;?myip=203.0.113.10'</code>
<code>good 203.0.113.10</code> <code>good 203.0.113.10</code>
</div> </div>
</div> </div>
<form method="post" action="/magic" class="col-lg-5 card card-body gap-3" aria-label="Create a generated DynDNS hostname">
<p class="section-copy mb-0">KarlDNS generates the hostname, secret update URL, and optional router compatibility credentials automatically.</p>
<button type="submit" class="btn btn-primary rounded-pill">Generate hostname</button>
</form>
</div>
</div>
</section> </section>
<section class="section" id="manual-updates"> <section class="section" id="manual-updates">
<div class="container narrow text-center"> <div class="container narrow text-center">
@@ -729,9 +748,10 @@ def _top_nav(label: str | None = None, links: str = "") -> str:
def _custom_domain_flow(service: DdnsService, challenge: dict[str, str | None] | None, message: str | None) -> str: def _custom_domain_flow(service: DdnsService, challenge: dict[str, str | None] | None, message: str | None) -> str:
if not challenge:
return ""
challenge_html = "" challenge_html = ""
create_form = "" create_form = ""
if challenge:
domain = html.escape(str(challenge["domain"])) domain = html.escape(str(challenge["domain"]))
token = str(challenge["token"]) token = str(challenge["token"])
claim_secret = html.escape(str(challenge.get("claim_secret") or "")) claim_secret = html.escape(str(challenge.get("claim_secret") or ""))
@@ -740,9 +760,9 @@ def _custom_domain_flow(service: DdnsService, challenge: dict[str, str | None] |
status = html.escape(message or "Add this TXT record at your DNS provider, then check when it has propagated.") status = html.escape(message or "Add this TXT record at your DNS provider, then check when it has propagated.")
txt_bundle = f"TXT name: {verification_name}\nTXT value: {token}" txt_bundle = f"TXT name: {verification_name}\nTXT value: {token}"
challenge_html = f""" challenge_html = f"""
<div class="col-md-4"> <div class="col-lg-5">
<div class="card card-body h-100 gap-3"> <div class="card card-body h-100 gap-3">
<span class="badge text-bg-primary rounded-circle align-self-start">2</span> <span class="badge text-bg-primary rounded-circle align-self-start">1</span>
<h3>Add the TXT record</h3> <h3>Add the TXT record</h3>
<p class="small text-secondary mb-0 mt-2">{status}</p> <p class="small text-secondary mb-0 mt-2">{status}</p>
<div class="alert alert-info mb-0 py-2 small">TXT name and value are public DNS records. The private claim link is secret.</div> <div class="alert alert-info mb-0 py-2 small">TXT name and value are public DNS records. The private claim link is secret.</div>
@@ -760,9 +780,9 @@ def _custom_domain_flow(service: DdnsService, challenge: dict[str, str | None] |
""" """
if challenge.get("verified_at"): if challenge.get("verified_at"):
create_form = f""" create_form = f"""
<div class="col-md-4"> <div class="col-lg-5">
<div class="card card-body h-100 gap-3"> <div class="card card-body h-100 gap-3">
<span class="badge text-bg-primary rounded-circle align-self-start">3</span> <span class="badge text-bg-primary rounded-circle align-self-start">2</span>
<h3>Create router hostname</h3> <h3>Create router hostname</h3>
<form method="post" action="/accounts" class="d-grid gap-3" aria-label="Create custom-domain router credentials"> <form method="post" action="/accounts" class="d-grid gap-3" aria-label="Create custom-domain router credentials">
<input type="hidden" name="mode" value="custom"> <input type="hidden" name="mode" value="custom">
@@ -778,9 +798,9 @@ def _custom_domain_flow(service: DdnsService, challenge: dict[str, str | None] |
""" """
else: else:
create_form = """ create_form = """
<div class="col-md-4"> <div class="col-lg-5">
<div class="card card-body h-100 gap-3 opacity-75"> <div class="card card-body h-100 gap-3 opacity-75">
<span class="badge text-bg-primary rounded-circle align-self-start">3</span> <span class="badge text-bg-primary rounded-circle align-self-start">2</span>
<h3>Create router hostname</h3> <h3>Create router hostname</h3>
<p class="small text-secondary mb-0 mt-2">This unlocks after the TXT record is visible in public DNS.</p> <p class="small text-secondary mb-0 mt-2">This unlocks after the TXT record is visible in public DNS.</p>
</div> </div>
@@ -789,27 +809,13 @@ def _custom_domain_flow(service: DdnsService, challenge: dict[str, str | None] |
return f""" return f"""
<section class="section" id="custom-domain"> <section class="section" id="custom-domain">
<div class="container"> <div class="container narrow">
<div class="d-flex align-items-md-center justify-content-between gap-4 flex-column flex-md-row"> <div class="text-center">
<div>
<p class="eyebrow">Direct custom-domain publishing</p> <p class="eyebrow">Direct custom-domain publishing</p>
<h2>Verify DNS ownership</h2> <h2>Verify DNS ownership</h2>
<p class="section-copy">Use this only when KarlDNS should publish A/AAAA records directly inside your domain. If you just want your own subdomain, generate a hostname above and create a CNAME to it.</p> <p class="section-copy mx-auto">Use this only when KarlDNS should publish A/AAAA records directly inside your domain. If you just want your own subdomain, generate a hostname above and create a CNAME to it.</p>
</div>
</div>
<div class="row g-3 mt-4">
<div class="col-md-4">
<div class="card card-body h-100 gap-3">
<span class="badge text-bg-primary rounded-circle align-self-start">1</span>
<h3>Enter domain</h3>
<form method="post" action="/request-domain" class="d-grid gap-3" aria-label="Request a custom domain TXT challenge">
<label>Domain
<input class="form-control" name="domain" placeholder="example.com" autocomplete="off" autocapitalize="none" spellcheck="false" required>
</label>
<button type="submit" class="btn btn-primary rounded-pill">Create TXT challenge</button>
</form>
</div>
</div> </div>
<div class="row g-3 mt-4 justify-content-center">
{challenge_html} {challenge_html}
{create_form} {create_form}
</div> </div>