← back to Homesonspec
admin: Live site toggle (/live) — embeds the customer storefront with desktop/mobile preview + open-full
6d7e380292c4c298aca09f9c6a5845c98976ccc9 · 2026-07-28 12:31:15 -0700 · Steve Abrams
Files touched
M apps/admin/src/app/layout.tsxA apps/admin/src/app/live/LivePreview.tsxA apps/admin/src/app/live/page.tsx
Diff
commit 6d7e380292c4c298aca09f9c6a5845c98976ccc9
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Jul 28 12:31:15 2026 -0700
admin: Live site toggle (/live) — embeds the customer storefront with desktop/mobile preview + open-full
---
apps/admin/src/app/layout.tsx | 1 +
apps/admin/src/app/live/LivePreview.tsx | 56 +++++++++++++++++++++++++++++++++
apps/admin/src/app/live/page.tsx | 15 +++++++++
3 files changed, 72 insertions(+)
diff --git a/apps/admin/src/app/layout.tsx b/apps/admin/src/app/layout.tsx
index 7e0d6ce0..c02a640d 100644
--- a/apps/admin/src/app/layout.tsx
+++ b/apps/admin/src/app/layout.tsx
@@ -16,6 +16,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
<Link href="/" className="text-lg font-bold text-neutral-900">
HomesOnSpec <span className="text-teal-700">Admin</span>
</Link>
+ <Link href="/live" className="rounded-full border border-teal-300 bg-teal-50 px-3 py-1 font-medium text-teal-700 hover:bg-teal-100">◉ Live site</Link>
<Link href="/business" className="font-semibold text-teal-700 hover:text-teal-900">Business</Link>
<Link href="/ingestion" className="hover:text-teal-700">Live ingestion</Link>
<Link href="/engine" className="hover:text-teal-700">Engine</Link>
diff --git a/apps/admin/src/app/live/LivePreview.tsx b/apps/admin/src/app/live/LivePreview.tsx
new file mode 100644
index 00000000..c7f54245
--- /dev/null
+++ b/apps/admin/src/app/live/LivePreview.tsx
@@ -0,0 +1,56 @@
+"use client";
+
+import { useState } from "react";
+
+const URL = "https://homesonspec.com/";
+
+export default function LivePreview() {
+ const [mode, setMode] = useState<"desktop" | "mobile">("desktop");
+ const [nonce, setNonce] = useState(0); // bump to force-reload the iframe
+ const width = mode === "mobile" ? 390 : "100%";
+
+ return (
+ <div className="mt-4">
+ <div className="mb-3 flex flex-wrap items-center gap-2 text-sm">
+ <div className="inline-flex rounded-lg border border-neutral-200 bg-white p-0.5">
+ {(["desktop", "mobile"] as const).map((m) => (
+ <button
+ key={m}
+ onClick={() => setMode(m)}
+ className={`rounded-md px-3 py-1 text-xs capitalize ${mode === m ? "bg-teal-600 text-white" : "text-neutral-600 hover:text-teal-700"}`}
+ >
+ {m}
+ </button>
+ ))}
+ </div>
+ <button
+ onClick={() => setNonce((n) => n + 1)}
+ className="rounded-md border border-neutral-200 bg-white px-2 py-1 text-xs text-neutral-600 hover:text-teal-700"
+ >
+ ↻ Reload
+ </button>
+ <span className="text-xs text-neutral-400">viewing the customer-facing storefront</span>
+ <a
+ href={URL}
+ target="_blank"
+ rel="noopener noreferrer"
+ className="ml-auto rounded-md border border-teal-200 bg-teal-50 px-3 py-1 text-xs font-medium text-teal-700 hover:bg-teal-100"
+ >
+ Open full ↗
+ </a>
+ </div>
+ <div
+ className="flex justify-center overflow-hidden rounded-xl border border-neutral-200 bg-neutral-100 p-2"
+ style={{ height: "calc(100vh - 230px)", minHeight: 480 }}
+ >
+ <iframe
+ key={nonce}
+ src={URL}
+ title="homesonspec.com — live storefront"
+ style={{ width, height: "100%", border: 0, borderRadius: 8, background: "#fff", maxWidth: "100%" }}
+ className="shadow-sm"
+ />
+ </div>
+ </div>
+ );
+}
diff --git a/apps/admin/src/app/live/page.tsx b/apps/admin/src/app/live/page.tsx
new file mode 100644
index 00000000..21ac25b7
--- /dev/null
+++ b/apps/admin/src/app/live/page.tsx
@@ -0,0 +1,15 @@
+import LivePreview from "./LivePreview";
+
+export const dynamic = "force-dynamic";
+
+export default function LivePage() {
+ return (
+ <div>
+ <h1 className="text-2xl font-bold">Live site</h1>
+ <p className="mt-1 text-sm text-neutral-500">
+ The customer-facing storefront (<code>homesonspec.com</code>) embedded here — toggle desktop / mobile, reload, or open it full. Everything the ingestion loop publishes shows up here.
+ </p>
+ <LivePreview />
+ </div>
+ );
+}
← f90ea4b6 build-loop: Lennar + DR Horton page limit 120->300 (Cody: CA
·
back to Homesonspec
·
build-loop: uncap CAP (download ALL homes per state) + 40 sw 775ea10a →