feat: coming-soon page as a real SolidJS route, host-redirected from nxtgauge.com
All checks were successful
build-and-release / build (push) Successful in 2m18s
All checks were successful
build-and-release / build (push) Successful in 2m18s
Replaces the standalone static-nginx coming-soon deployment (nxtgauge-gitops/coming-soon/ + apps/nxtgauge-coming-soon/) with a proper route in this app - same content/design, ported to SolidJS (signals for the form state instead of vanilla DOM manipulation), CSS classes prefixed cs- to avoid colliding with the rest of the app's global styles. src/middleware.ts (already intercepts every request for the /api/* proxy workaround) now also redirects '/' to '/coming-soon' when the request Host is nxtgauge.com or www.nxtgauge.com - test111.nxtgauge.com still shows the real app. Same deployment, same ingress backend, no separate infra to build+deploy+eventually tear down when launching - flipping the switch at launch time is just deleting that redirect block and the route. Reuses existing public/nxtgauge-logo.png and public/traceworks-logo-white.svg (confirmed byte-identical to the old coming-soon/assets/ copies) rather than duplicating assets. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
f719879e72
commit
f51a94b777
2 changed files with 320 additions and 0 deletions
|
|
@ -164,10 +164,21 @@ async function handlePayuReturn(fetchEvent: any): Promise<Response> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pre-launch: nxtgauge.com/www.nxtgauge.com show the coming-soon page instead
|
||||||
|
// of the real app. This is the *only* difference between that domain and the
|
||||||
|
// live app (same deployment, same ingress backend) - flip it off by deleting
|
||||||
|
// this block (and the /coming-soon route) once ready to launch.
|
||||||
|
const COMING_SOON_HOSTS = new Set(["nxtgauge.com", "www.nxtgauge.com"]);
|
||||||
|
|
||||||
export default createMiddleware({
|
export default createMiddleware({
|
||||||
onRequest: async (fetchEvent) => {
|
onRequest: async (fetchEvent) => {
|
||||||
const url = new URL(fetchEvent.request.url);
|
const url = new URL(fetchEvent.request.url);
|
||||||
const path = url.pathname;
|
const path = url.pathname;
|
||||||
|
const host = fetchEvent.request.headers.get("host")?.split(":")[0] ?? "";
|
||||||
|
|
||||||
|
if (COMING_SOON_HOSTS.has(host) && path === "/") {
|
||||||
|
return Response.redirect(new URL("/coming-soon", url), 302);
|
||||||
|
}
|
||||||
|
|
||||||
// Only handle /api/* paths
|
// Only handle /api/* paths
|
||||||
if (!path.startsWith("/api/")) return;
|
if (!path.startsWith("/api/")) return;
|
||||||
|
|
|
||||||
309
src/routes/coming-soon.tsx
Normal file
309
src/routes/coming-soon.tsx
Normal file
|
|
@ -0,0 +1,309 @@
|
||||||
|
import { createSignal, Show } from "solid-js";
|
||||||
|
import { Title, Meta, Link } from "@solidjs/meta";
|
||||||
|
|
||||||
|
async function apiFetch(path: string, opts?: RequestInit) {
|
||||||
|
return fetch(path, {
|
||||||
|
...opts,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(opts?.headers ?? {}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ComingSoonPage() {
|
||||||
|
const [email, setEmail] = createSignal("");
|
||||||
|
const [submitting, setSubmitting] = createSignal(false);
|
||||||
|
const [submitted, setSubmitted] = createSignal(false);
|
||||||
|
const [error, setError] = createSignal(false);
|
||||||
|
|
||||||
|
const handleSubmit = async (e: Event) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const value = email().trim();
|
||||||
|
if (!value || submitting()) return;
|
||||||
|
|
||||||
|
setError(false);
|
||||||
|
setSubmitting(true);
|
||||||
|
try {
|
||||||
|
const res = await apiFetch("/api/waitlist", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ email: value }),
|
||||||
|
});
|
||||||
|
if (!res.ok) throw new Error("Request failed");
|
||||||
|
setSubmitted(true);
|
||||||
|
} catch {
|
||||||
|
setError(true);
|
||||||
|
} finally {
|
||||||
|
setSubmitting(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Title>Nxtgauge — Coming Soon</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content="Nxtgauge is launching soon — India's marketplace for jobs and professional services, powered by AI."
|
||||||
|
/>
|
||||||
|
<Meta property="og:title" content="Nxtgauge — Coming Soon" />
|
||||||
|
<Meta
|
||||||
|
property="og:description"
|
||||||
|
content="India's marketplace for jobs and professional services. Launching soon."
|
||||||
|
/>
|
||||||
|
<Link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<Link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
|
||||||
|
<Link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=Exo+2:wght@400;600;700;800;900&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<style>{`
|
||||||
|
.cs-page {
|
||||||
|
--cs-orange: #fd6116;
|
||||||
|
--cs-orange-dark: #e45a14;
|
||||||
|
--cs-navy: #050026;
|
||||||
|
--cs-font: "Exo 2", "Segoe UI", system-ui, -apple-system, sans-serif;
|
||||||
|
|
||||||
|
font-family: var(--cs-font);
|
||||||
|
background: var(--cs-navy);
|
||||||
|
color: #fff;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 100dvh;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 32px 24px 100px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.cs-page * { box-sizing: border-box; }
|
||||||
|
|
||||||
|
.cs-bg { position: fixed; inset: 0; pointer-events: none; z-index: 0; }
|
||||||
|
.cs-bg-base {
|
||||||
|
position: absolute; inset: 0;
|
||||||
|
background: radial-gradient(ellipse 80% 60% at 50% 0%, #17003e 0%, var(--cs-navy) 70%);
|
||||||
|
}
|
||||||
|
.cs-bg-mesh {
|
||||||
|
position: absolute; inset: 0;
|
||||||
|
background:
|
||||||
|
radial-gradient(ellipse 65% 55% at 50% 30%, rgba(253,97,22,0.22) 0%, transparent 65%),
|
||||||
|
radial-gradient(ellipse 45% 40% at 10% 80%, rgba(50,30,120,0.18) 0%, transparent 60%),
|
||||||
|
radial-gradient(ellipse 45% 40% at 90% 75%, rgba(253,97,22,0.09) 0%, transparent 60%);
|
||||||
|
}
|
||||||
|
.cs-bg-grid {
|
||||||
|
position: absolute; inset: 0;
|
||||||
|
background-image:
|
||||||
|
linear-gradient(rgba(255,255,255,0.025) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgba(255,255,255,0.025) 1px, transparent 1px);
|
||||||
|
background-size: 48px 48px;
|
||||||
|
}
|
||||||
|
.cs-orb {
|
||||||
|
position: absolute; border-radius: 50%;
|
||||||
|
background: radial-gradient(circle, rgba(253,97,22,0.14) 0%, transparent 70%);
|
||||||
|
animation: cs-orbFloat linear infinite;
|
||||||
|
}
|
||||||
|
.cs-orb-1 { width: 600px; height: 600px; top: -220px; left: -180px; animation-duration: 20s; }
|
||||||
|
.cs-orb-2 { width: 380px; height: 380px; bottom: -100px; right: -60px; animation-duration: 15s; animation-delay: -7s; }
|
||||||
|
@keyframes cs-orbFloat {
|
||||||
|
0% { transform: translateY(0) scale(1); }
|
||||||
|
50% { transform: translateY(-28px) scale(1.04); }
|
||||||
|
100% { transform: translateY(0) scale(1); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.cs-content {
|
||||||
|
position: relative; z-index: 1;
|
||||||
|
display: flex; flex-direction: column;
|
||||||
|
align-items: center; text-align: center;
|
||||||
|
max-width: 580px; width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cs-brand-logo {
|
||||||
|
height: 50px; width: auto;
|
||||||
|
margin-bottom: 52px;
|
||||||
|
filter: brightness(0) invert(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cs-badge {
|
||||||
|
display: inline-flex; align-items: center; gap: 9px;
|
||||||
|
font-size: 11px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
|
||||||
|
color: var(--cs-orange);
|
||||||
|
border: 1px solid rgba(253,97,22,0.38);
|
||||||
|
padding: 7px 18px; border-radius: 999px;
|
||||||
|
background: rgba(253,97,22,0.08);
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
.cs-badge-dot {
|
||||||
|
width: 6px; height: 6px; border-radius: 50%;
|
||||||
|
background: var(--cs-orange);
|
||||||
|
box-shadow: 0 0 7px var(--cs-orange);
|
||||||
|
animation: cs-blink 2.2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
@keyframes cs-blink { 0%,100%{opacity:1} 50%{opacity:0.28} }
|
||||||
|
|
||||||
|
.cs-h1 {
|
||||||
|
font-size: clamp(44px, 10vw, 86px);
|
||||||
|
font-weight: 900;
|
||||||
|
letter-spacing: -0.04em;
|
||||||
|
line-height: 1.08;
|
||||||
|
color: #fff;
|
||||||
|
margin-bottom: 26px;
|
||||||
|
}
|
||||||
|
.cs-accent {
|
||||||
|
display: block;
|
||||||
|
background: linear-gradient(105deg, var(--cs-orange) 0%, #ff9c65 55%, #ffcba0 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cs-tagline {
|
||||||
|
font-size: clamp(14px, 2vw, 17px);
|
||||||
|
color: rgba(255,255,255,0.48);
|
||||||
|
line-height: 1.68;
|
||||||
|
max-width: 420px;
|
||||||
|
margin-bottom: 52px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cs-form {
|
||||||
|
display: flex;
|
||||||
|
width: 100%; max-width: 420px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.cs-form input {
|
||||||
|
flex: 1; height: 50px; padding: 0 18px;
|
||||||
|
border: 1.5px solid rgba(255,255,255,0.12); border-right: none;
|
||||||
|
border-radius: 10px 0 0 10px;
|
||||||
|
background: rgba(255,255,255,0.05);
|
||||||
|
color: #fff; font-family: var(--cs-font); font-size: 14px;
|
||||||
|
outline: none; transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
.cs-form input::placeholder { color: rgba(255,255,255,0.24); }
|
||||||
|
.cs-form input:focus { border-color: rgba(253,97,22,0.5); }
|
||||||
|
.cs-form button {
|
||||||
|
height: 50px; padding: 0 22px;
|
||||||
|
border: none; border-radius: 0 10px 10px 0;
|
||||||
|
background: var(--cs-orange); color: var(--cs-navy);
|
||||||
|
font-family: var(--cs-font); font-size: 14px; font-weight: 700;
|
||||||
|
cursor: pointer; white-space: nowrap;
|
||||||
|
transition: background 0.15s;
|
||||||
|
}
|
||||||
|
.cs-form button:hover { background: var(--cs-orange-dark); }
|
||||||
|
.cs-form button:active { transform: scale(0.98); }
|
||||||
|
.cs-form button:disabled { opacity: 0.6; cursor: default; }
|
||||||
|
|
||||||
|
.cs-form-note {
|
||||||
|
font-size: 11px;
|
||||||
|
color: rgba(255,255,255,0.22);
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.cs-form-success {
|
||||||
|
font-size: 14px; font-weight: 600; color: #4ade80;
|
||||||
|
animation: cs-fadeIn 0.4s ease;
|
||||||
|
}
|
||||||
|
.cs-form-error {
|
||||||
|
font-size: 13px; font-weight: 500; color: #f87171;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
@keyframes cs-fadeIn { from{opacity:0;transform:translateY(6px)} to{opacity:1;transform:translateY(0)} }
|
||||||
|
|
||||||
|
.cs-footer {
|
||||||
|
position: fixed; bottom: 0; left: 0; right: 0;
|
||||||
|
z-index: 1;
|
||||||
|
display: flex; flex-direction: column; align-items: center;
|
||||||
|
gap: 6px; padding: 14px 0 18px;
|
||||||
|
background: linear-gradient(to top, rgba(5,0,38,0.9) 0%, transparent 100%);
|
||||||
|
}
|
||||||
|
.cs-footer-copy {
|
||||||
|
font-size: 11px; color: rgba(255,255,255,0.2); letter-spacing: 0.04em;
|
||||||
|
}
|
||||||
|
.cs-footer-powered {
|
||||||
|
display: flex; align-items: center; gap: 10px;
|
||||||
|
}
|
||||||
|
.cs-footer-powered-label {
|
||||||
|
font-size: 11px; font-weight: 700; letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase; color: rgba(255,255,255,0.55);
|
||||||
|
}
|
||||||
|
.cs-footer-powered-logo {
|
||||||
|
height: 26px; width: auto;
|
||||||
|
filter: brightness(0) invert(1);
|
||||||
|
opacity: 0.85;
|
||||||
|
transition: opacity 0.15s;
|
||||||
|
}
|
||||||
|
.cs-footer-powered-logo:hover { opacity: 1; }
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.cs-form { flex-direction: column; }
|
||||||
|
.cs-form input {
|
||||||
|
flex: none;
|
||||||
|
height: 50px;
|
||||||
|
border-right: 1.5px solid rgba(255,255,255,0.12);
|
||||||
|
border-bottom: none;
|
||||||
|
border-radius: 10px 10px 0 0;
|
||||||
|
}
|
||||||
|
.cs-form button { border-radius: 0 0 10px 10px; }
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
|
||||||
|
<div class="cs-page">
|
||||||
|
<div class="cs-bg" aria-hidden="true">
|
||||||
|
<div class="cs-bg-base" />
|
||||||
|
<div class="cs-bg-mesh" />
|
||||||
|
<div class="cs-bg-grid" />
|
||||||
|
<div class="cs-orb cs-orb-1" />
|
||||||
|
<div class="cs-orb cs-orb-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<main class="cs-content">
|
||||||
|
<img class="cs-brand-logo" src="/nxtgauge-logo.png" alt="Nxtgauge" />
|
||||||
|
|
||||||
|
<div class="cs-badge">
|
||||||
|
<div class="cs-badge-dot" />
|
||||||
|
Coming Soon
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 class="cs-h1">
|
||||||
|
Something Big<br />
|
||||||
|
<span class="cs-accent">Is Coming.</span>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p class="cs-tagline">
|
||||||
|
India's marketplace for jobs and professional services —
|
||||||
|
verified professionals, AI-powered tools, fair for everyone.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<Show
|
||||||
|
when={!submitted()}
|
||||||
|
fallback={<p class="cs-form-success">✓ You're on the list! We'll reach out when we go live.</p>}
|
||||||
|
>
|
||||||
|
<form class="cs-form" onSubmit={handleSubmit}>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
placeholder="Enter your email"
|
||||||
|
required
|
||||||
|
autocomplete="email"
|
||||||
|
value={email()}
|
||||||
|
onInput={(e) => setEmail(e.currentTarget.value)}
|
||||||
|
/>
|
||||||
|
<button type="submit" disabled={submitting()}>
|
||||||
|
{submitting() ? "..." : "Notify Me"}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
<p class="cs-form-note">No spam. We'll only email when we launch.</p>
|
||||||
|
<Show when={error()}>
|
||||||
|
<p class="cs-form-error">Something went wrong. Please try again.</p>
|
||||||
|
</Show>
|
||||||
|
</Show>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="cs-footer">
|
||||||
|
<div class="cs-footer-copy">© 2026 Nxtgauge. All rights reserved.</div>
|
||||||
|
<div class="cs-footer-powered">
|
||||||
|
<span class="cs-footer-powered-label">Powered by</span>
|
||||||
|
<img class="cs-footer-powered-logo" src="/traceworks-logo-white.svg" alt="Traceworks" />
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue