// sc-components.jsx — shared Nav, Footer, AnimateIn, UI primitives
const LINE_URL = "https://lin.ee/1YA6KpG";
const LOGO_URL = "images/logo.png";
const PAGE_URLS = {
home: "index.html",
begin: "begin.html",
course: "service.html",
voice: "voice.html",
bio: "about.html",
contact: "contact.html",
};
function pageUrl(id) { return PAGE_URLS[id] || "index.html"; }
/* ── AnimateIn ─────────────────────────────────────────────── */
function AnimateIn({ children, delay = 0, className = "", style = {} }) {
const ref = React.useRef(null);
const [visible, setVisible] = React.useState(false);
React.useEffect(() => {
const el = ref.current;
if (!el) return;
const obs = new IntersectionObserver(
([e]) => { if (e.isIntersecting) { setVisible(true); obs.disconnect(); } },
{ threshold: 0.08 }
);
obs.observe(el);
return () => obs.disconnect();
}, []);
return (
{children}
);
}
/* ── SectionHeader ─────────────────────────────────────────── */
function SectionHeader({ label, title, sub, center = false, light = false }) {
const align = center ? "center" : "left";
return (
{label && (
{label}
)}
{title}
{sub && (
{sub}
)}
);
}
/* ── LineButton — CTA → contact.html ──────────────────────── */
function LineButton({ children = "1週間の無料トライアルはこちら", large = false, ghost = false }) {
const base = {
display: "inline-flex", alignItems: "center", gap: "10px",
fontFamily: "var(--font-sans)", fontWeight: 500, letterSpacing: "0.06em",
borderRadius: "2px", cursor: "pointer", textDecoration: "none",
transition: "all 0.25s ease",
};
const filled = {
background: "var(--accent)", color: "#fff",
padding: large ? "18px 44px" : "14px 32px",
fontSize: large ? "15px" : "14px",
border: "1.5px solid var(--accent)",
};
const ghostStyle = {
background: "transparent", color: "var(--accent)",
padding: large ? "18px 44px" : "14px 32px",
fontSize: large ? "15px" : "14px",
border: "1.5px solid var(--accent)",
};
return (
{ e.currentTarget.style.opacity = "0.82"; e.currentTarget.style.transform = "translateY(-1px)"; }}
onMouseLeave={e => { e.currentTarget.style.opacity = "1"; e.currentTarget.style.transform = "none"; }}>
{children}
);
}
/* ── GoldLine ──────────────────────────────────────────────── */
function GoldLine({ width = "48px", margin = "0" }) {
return ;
}
/* ── Nav ───────────────────────────────────────────────────── */
function Nav({ currentPage }) {
const [scrolled, setScrolled] = React.useState(false);
const [mobileOpen, setMobileOpen] = React.useState(false);
React.useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 40);
window.addEventListener("scroll", onScroll, { passive: true });
return () => window.removeEventListener("scroll", onScroll);
}, []);
const links = [
{ id: "home", label: "ホーム" },
{ id: "begin", label: "初めての方へ" },
{ id: "course", label: "サービス内容" },
{ id: "voice", label: "利用者の声" },
{ id: "bio", label: "運営者" },
];
const navBg = scrolled || mobileOpen ? "rgba(255,255,255,0.97)" : "transparent";
const navBorder = scrolled || mobileOpen ? "1px solid var(--border)" : "1px solid transparent";
const linkColor = (!scrolled && !mobileOpen && currentPage === "home") ? "#fff" : "var(--text)";
return (
);
}
/* ── Footer ────────────────────────────────────────────────── */
function Footer() {
const links = [
{ id: "begin", label: "初めての方へ" },
{ id: "course", label: "サービス内容" },
{ id: "voice", label: "利用者の声" },
{ id: "bio", label: "運営者" },
];
return (
);
}
/* ── CtaSection ────────────────────────────────────────────── */
function CtaSection({ title = "まず、1週間。無料で試してください。", sub = "現状のタスクを整理し、行動の道筋をつける初回セッションから始めます。" }) {
return (
);
}
Object.assign(window, { AnimateIn, SectionHeader, LineButton, GoldLine, Nav, Footer, CtaSection, LINE_URL, pageUrl, PAGE_URLS });