feat(web): WelcomePage landing component
Add the public landing page: a static Charm-box tapir mascot (reusing the shared tapirLine helpers and charm palette), a tagline, and a single 'Get Started' CTA into the shared Dex flow — sign-in and sign-up are the same URL (ADR-012). Logged-in visitors get a greeting plus links back into the app and to log out. Regenerated views_templ.go committed alongside. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -266,6 +266,32 @@ var (
|
||||
tapirFrameHTML3 = tapirFrameHTML("~")
|
||||
)
|
||||
|
||||
// welcomeHeroHTML is the static Charm-box tapir mascot on the public landing
|
||||
// page — the same rounded purple box / pink tapir / mint accents as the spinner,
|
||||
// but a single still frame with a friendly tagline instead of the animation.
|
||||
// Built from the shared tapirLine helpers so the aesthetic stays in one place.
|
||||
func welcomeHeroHTML() string {
|
||||
top := tapirSpan(CharmPurple, "╭"+strings.Repeat("─", tapirInteriorW)+"╮")
|
||||
bottom := tapirSpan(CharmPurple, "╰"+strings.Repeat("─", tapirInteriorW)+"╯")
|
||||
lines := []string{
|
||||
top,
|
||||
tapirLine(tapirRun{s: " "}, tapirRun{s: "◆", color: CharmMint}, tapirRun{s: " "}, tapirRun{s: "tapir", color: CharmCream}),
|
||||
tapirLine(),
|
||||
tapirLine(tapirRun{s: " "}, tapirRun{s: "▄▄▄▄▄", color: CharmPink}),
|
||||
tapirLine(tapirRun{s: " "}, tapirRun{s: "▄█▓▓▓▓█▄", color: CharmPink}, tapirRun{s: " "}, tapirRun{s: "∩", color: CharmMint}),
|
||||
tapirLine(tapirRun{s: " "}, tapirRun{s: "█▓(", color: CharmPink}, tapirRun{s: " "}, tapirRun{s: "◕ ◕", color: CharmMint}, tapirRun{s: ")▓█", color: CharmPink}, tapirRun{s: "──┘", color: CharmMint}),
|
||||
tapirLine(tapirRun{s: " "}, tapirRun{s: "▀█▓▓▓▓█▀", color: CharmPink}),
|
||||
tapirLine(tapirRun{s: " "}, tapirRun{s: "██▄▄██", color: CharmPink}),
|
||||
tapirLine(tapirRun{s: " "}, tapirRun{s: "▀▀", color: CharmPink}, tapirRun{s: " "}, tapirRun{s: "▀▀", color: CharmPink}),
|
||||
tapirLine(),
|
||||
tapirLine(tapirRun{s: " "}, tapirRun{s: "watch less, know more", color: CharmMint}),
|
||||
bottom,
|
||||
}
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
var welcomeHero = welcomeHeroHTML()
|
||||
|
||||
// summarizeModeLabel names the current mode for display.
|
||||
func summarizeModeLabel(auto bool) string {
|
||||
if auto {
|
||||
@@ -573,6 +599,16 @@ main { max-width: 60rem; margin: 0 auto; padding: var(--s4) var(--s3); }
|
||||
.confirm-delete > summary:hover { background: #3a1714; }
|
||||
}
|
||||
|
||||
/* public landing page (/welcome) — the Charm-box mascot hero plus the sign-in CTA */
|
||||
.welcome { text-align: center; padding: var(--s5) var(--s3); display: flex; flex-direction: column; align-items: center; gap: var(--s4); }
|
||||
.welcome-hero { background: #0d0d12; border-radius: 10px; padding: .9em 1.1em; display: inline-block; box-shadow: 0 2px 14px rgba(118, 83, 252, .25); }
|
||||
.welcome-hero pre { margin: 0; white-space: pre; font: .82rem/1.15 ui-monospace, SFMono-Regular, Menlo, "Cascadia Code", monospace; }
|
||||
.welcome-title { font-size: 1.9rem; line-height: 1.2; margin: 0; }
|
||||
.welcome-tagline { color: var(--muted); font-size: 1.05rem; line-height: 1.5; margin: 0; max-width: 32rem; }
|
||||
.welcome-cta { display: flex; gap: var(--s3); flex-wrap: wrap; justify-content: center; align-items: center; }
|
||||
.welcome-sub { color: var(--muted); font-size: .9rem; margin: 0; }
|
||||
.btn-lg { padding: .6rem 1.6rem; font-size: 1.05rem; }
|
||||
|
||||
@media (max-width: 640px) {
|
||||
main { padding: var(--s3) var(--s2); }
|
||||
.filters { gap: var(--s2); }
|
||||
|
||||
@@ -31,6 +31,40 @@ templ Layout(title string) {
|
||||
</html>
|
||||
}
|
||||
|
||||
// WelcomePage is the public landing page (served at /welcome, outside the auth
|
||||
// guard — ADR-012). Logged out: the tapir mascot, a one-line tagline, and a
|
||||
// single "Get Started" CTA into the shared Dex flow (sign-in and sign-up are the
|
||||
// same URL). Logged in: a greeting plus links back into the app and to log out.
|
||||
templ WelcomePage(user User, loggedIn bool) {
|
||||
@Layout("Tapir — Watch less, know more") {
|
||||
<section class="welcome">
|
||||
<div class="welcome-hero">
|
||||
<pre aria-hidden="true">@templ.Raw(welcomeHero)</pre>
|
||||
</div>
|
||||
if loggedIn {
|
||||
<h1 class="welcome-title">Welcome back</h1>
|
||||
if user.Email != "" {
|
||||
<p class="welcome-tagline">Signed in as { user.Email }.</p>
|
||||
}
|
||||
<div class="welcome-cta">
|
||||
<a class="btn btn-lg" href="/">Go to my Tapir</a>
|
||||
<a class="btn-secondary" href="/auth/logout">Log Out</a>
|
||||
</div>
|
||||
} else {
|
||||
<h1 class="welcome-title">Watch less, know more</h1>
|
||||
<p class="welcome-tagline">
|
||||
Tapir summarizes the videos your subscriptions publish, so you can
|
||||
skim the gist and decide what is worth your time.
|
||||
</p>
|
||||
<div class="welcome-cta">
|
||||
<a class="btn btn-lg" href="/auth/login">Get Started</a>
|
||||
</div>
|
||||
<p class="welcome-sub">Already have an account? You'll go straight through.</p>
|
||||
}
|
||||
</section>
|
||||
}
|
||||
}
|
||||
|
||||
// flashBanner renders a one-shot notification for a flash code (connect success/
|
||||
// failure, disconnect, delete, registration). An empty or unknown code renders
|
||||
// nothing, so it is safe to drop into any page unconditionally. Reused across the
|
||||
|
||||
+563
-466
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user