web/app/landing.tsxblame
View source
4bb999b1"use client";
4bb999b2
4bb999b3import { useEffect, useRef, useState } from "react";
4bb999b4import { GroveLogo } from "@/app/components/grove-logo";
44863ab5import { useTheme } from "@/lib/theme";
4bb999b6
4bb999b7export function LandingPage() {
4bb999b8 const [islDomain, setIslDomain] = useState("");
44863ab9 const { theme } = useTheme();
44863ab10 const islRef = useRef<HTMLIFrameElement>(null);
4bb999b11
4bb999b12 useEffect(() => {
4bb999b13 const host = window.location.hostname;
4bb999b14 if (host !== "localhost" && !host.match(/^\d/)) {
7e5aa7715 setIslDomain("https://isl.grove.host");
4bb999b16 }
4bb999b17 }, []);
4bb999b18
44863ab19 // Send theme changes to ISL iframe via postMessage
44863ab20 useEffect(() => {
44863ab21 if (islRef.current?.contentWindow) {
44863ab22 islRef.current.contentWindow.postMessage({ type: "theme", value: theme }, "*");
44863ab23 }
44863ab24 }, [theme]);
44863ab25
4bb999b26 return (
d6f162027 <div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
44863ab28 {/* Hero + Terminal + Features */}
44863ab29 <div style={{ maxWidth: "800px", margin: "0 auto", padding: "60px 24px 0", width: "100%" }}>
44863ab30
4bb999b31 {/* Hero */}
4bb999b32 <div style={{ textAlign: "center", marginBottom: "64px" }}>
4bb999b33 <div style={{ display: "inline-block", marginBottom: "24px" }}>
4bb999b34 <GroveLogo size={64} />
4bb999b35 </div>
4bb999b36 <h1
4bb999b37 style={{
4bb999b38 fontSize: "2rem",
4bb999b39 fontWeight: 400,
4bb999b40 color: "var(--text-primary)",
4bb999b41 marginBottom: "12px",
4bb999b42 }}
4bb999b43 >
4bb999b44 Source control, self-hosted
4bb999b45 </h1>
4bb999b46 <p
4bb999b47 style={{
4bb999b48 fontSize: "1rem",
4bb999b49 color: "var(--text-muted)",
4bb999b50 maxWidth: "480px",
4bb999b51 margin: "0 auto 32px",
4bb999b52 lineHeight: 1.6,
4bb999b53 }}
4bb999b54 >
4bb999b55 Grove is a complete code hosting platform built on Sapling SCM and Mononoke.
4bb999b56 Stacked diffs, interactive smartlog, CI pipelines — on your own infrastructure.
4bb999b57 </p>
4bb999b58 <a
4bb999b59 href="/login"
4bb999b60 style={{
4bb999b61 display: "inline-block",
4bb999b62 padding: "10px 24px",
4bb999b63 backgroundColor: "var(--accent)",
4bb999b64 color: "var(--accent-text)",
4bb999b65 fontSize: "0.875rem",
4bb999b66 textDecoration: "none",
4bb999b67 }}
4bb999b68 >
4bb999b69 Get started
4bb999b70 </a>
4bb999b71 </div>
4bb999b72
d8281c073 {/* Install */}
d8281c074 <div
d8281c075 style={{
d8281c076 maxWidth: "480px",
d8281c077 margin: "0 auto",
d8281c078 padding: "0 0 64px",
d8281c079 width: "100%",
d8281c080 }}
d8281c081 >
d8281c082 <div
d8281c083 style={{
d8281c084 backgroundColor: "var(--bg-card)",
d8281c085 border: "1px solid var(--border-subtle)",
d8281c086 padding: "16px 20px",
d8281c087 fontFamily: "var(--font-mono, monospace)",
d8281c088 fontSize: "0.875rem",
d8281c089 color: "var(--text-muted)",
d8281c090 display: "flex",
d8281c091 flexDirection: "column",
d8281c092 gap: "4px",
d8281c093 }}
d8281c094 >
d8281c095 <span><span style={{ color: "var(--text-faint)" }}>$</span> npm i -g @letterpress-labs/grove-scm</span>
d8281c096 <span><span style={{ color: "var(--text-faint)" }}>$</span> grove auth login</span>
d8281c097 <span><span style={{ color: "var(--text-faint)" }}>$</span> grove clone owner/repo</span>
d8281c098 </div>
d8281c099 </div>
d8281c0100
44863ab101 </div>{/* end centered wrapper */}
44863ab102
44863ab103 {/* ISL — fills remaining viewport */}
44863ab104 {islDomain && (
d6f1620105 <section
d6f1620106 style={{
d6f1620107 padding: "24px",
d6f1620108 }}
d6f1620109 >
d6f1620110 <iframe
d6f1620111 ref={islRef}
d6f1620112 src={`${islDomain}?theme=${theme}`}
44863ab113 style={{
d6f1620114 width: "100%",
d6f1620115 height: "calc(100vh - 3.5rem)",
d6f1620116 border: "1px solid var(--border-subtle)",
d6f1620117 display: "block",
d6f1620118 }}
d6f1620119 title="Interactive Smartlog"
d6f1620120 onLoad={() => {
d6f1620121 islRef.current?.contentWindow?.postMessage({ type: "theme", value: theme }, "*");
44863ab122 }}
d6f1620123 />
44863ab124 </section>
44863ab125 )}
4bb999b126 </div>
4bb999b127 );
4bb999b128}