feat(landing-purchase): new Landing/Purchase page + weownchat-design skill - #163
feat(landing-purchase): new Landing/Purchase page + weownchat-design skill#163SinachPat wants to merge 2 commits into
Conversation
…skill New Next.js 15 + TypeScript + Tailwind v4 project implementing PRD roadmap item 2 (top-of-funnel marketing site). Full first build: nav, animated live-chat hero, a "Live preview" section embedding the real dashboard HTML in an iframe with seeded demo content, how-it-works, the two-tab (private/public) explainer, value pillars, pricing (no dollar figure — commercial terms are still draft/unsigned), FAQ, footer. Design tokens are copied verbatim from the real product — the dashboard's own :root (anythingllm-docker/template/dashboard/public/index.html) and the Keycloak weown login theme — not invented independently. Codified as a Claude Code skill (.claude/skills/weownchat-design/) so future frontend work reuses this source of truth instead of drifting from it. An earlier draft of both the skill and the page shipped an independently-invented light/serif palette before this was caught and corrected mid-build. .gitignore narrowed from a blanket `.claude/` exclusion to `.claude/*` + `!.claude/skills/`, so skills are shareable while local session state (worktrees, transcripts) stays ignored. Verification: `next build` clean (types + lint + static generation, 108 KB first-load JS); checked at desktop/1440px/mobile widths; manual secret/PII grep over all newly-tracked files came back clean (gitleaks/pre-commit not available in this environment). Open follow-ups tracked in landing-purchase/CHANGELOG.md and README.md: hosting/deployment target not yet decided; npm audit flags 3 high-severity issues nested inside Next.js's own postcss/sharp (fix requires a Next 16 major bump, not taken unilaterally); no legal/analytics/real billing wiring yet. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds a new Next.js-based Landing/Purchase site and codifies the existing WeOwn Chat visual design system as a shareable Claude skill, including a live dashboard preview embedded via iframe.
Changes:
- Introduces
landing-purchase/(Next.js App Router + TS + Tailwind v4) with composable marketing sections. - Adds a demo “real dashboard” HTML asset in
public/_demo/with a fetch-mock so the iframe renders seeded fictional content. - Updates repo changelogs and
.gitignoreto track/share.claude/skills/while ignoring other local Claude workspace artifacts.
Reviewed changes
Copilot reviewed 31 out of 33 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| landing-purchase/tsconfig.json | Adds TypeScript configuration for the new Next.js app. |
| landing-purchase/public/_demo/dashboard-preview.html | Adds embedded demo dashboard HTML used by the landing page’s live preview. |
| landing-purchase/postcss.config.mjs | Configures PostCSS for Tailwind v4. |
| landing-purchase/package.json | Adds Next/React/TS/Tailwind/ESLint dependencies and scripts for the new app. |
| landing-purchase/next.config.ts | Adds Next.js configuration for the new app. |
| landing-purchase/components/icons.tsx | Adds shared inline SVG icon components for landing page sections. |
| landing-purchase/components/hooks.ts | Adds client hook for reduced-motion preference detection. |
| landing-purchase/components/ValuePillars.tsx | Adds “value pillars” marketing section. |
| landing-purchase/components/TwoTabExplainer.tsx | Adds private/public tab concept explainer section. |
| landing-purchase/components/TrustLabelStrip.tsx | Adds “trust label” strip component for proof points. |
| landing-purchase/components/Reveal.tsx | Adds scroll-into-view reveal animation wrapper using IntersectionObserver. |
| landing-purchase/components/ProductShowcase.tsx | Adds iframe-based “live preview” showcase with tab switching. |
| landing-purchase/components/Pricing.tsx | Adds pricing section (intentionally no dollar amounts). |
| landing-purchase/components/Nav.tsx | Adds responsive navigation with mobile menu. |
| landing-purchase/components/HowItWorks.tsx | Adds “how it works” steps section. |
| landing-purchase/components/Hero.tsx | Adds hero section including animated chat preview. |
| landing-purchase/components/Footer.tsx | Adds footer with nav columns and trust labels. |
| landing-purchase/components/FAQ.tsx | Adds FAQ accordion section. |
| landing-purchase/components/Container.tsx | Adds layout container primitive. |
| landing-purchase/components/Button.tsx | Adds internal/external link button component. |
| landing-purchase/components/BrandMark.tsx | Adds WeOwn “W” brand mark component. |
| landing-purchase/components/AnimatedChatMock.tsx | Adds animated chat UI recreation for the hero. |
| landing-purchase/app/page.tsx | Wires landing page sections into the root page. |
| landing-purchase/app/layout.tsx | Adds root layout and metadata for the new app. |
| landing-purchase/app/globals.css | Adds Tailwind v4 theme tokens and base styles/animations. |
| landing-purchase/README.md | Documents the new landing/purchase app and how to run it locally. |
| landing-purchase/CHANGELOG.md | Adds a per-project changelog for landing-purchase. |
| landing-purchase/.gitignore | Adds ignores for Next/Node/TS artifacts within landing-purchase. |
| CHANGELOG.md | Adds landing-purchase to the global changelog index + release entry. |
| .gitignore | Adjusts Claude workspace ignores to include .claude/skills/ in repo. |
| .claude/skills/weownchat-design/references/tokens.md | Adds canonical design token reference sourced from production UI. |
| .claude/skills/weownchat-design/SKILL.md | Adds design-system rules for consistent frontend work across surfaces. |
Suppressed comments (2)
landing-purchase/public/_demo/dashboard-preview.html:1
- The demo fetch mock matches routes via
path.indexOf(key) !== -1, which causes collisions for nested endpoints. For example,/api/threads/<slug>/chatswill match the/api/threadskey and return the thread list JSON shape (nohistory), breaking per-thread chat loading in the preview. Prefer matching a normalized/api/...path (e.g., extract substring starting at/api/) and use exact matches for known demo routes, plus add explicit handling for/api/threads/:slug/chatssoswitchThread()receives{ history: [...] }.
landing-purchase/public/_demo/dashboard-preview.html:1 #chatlogis the scroll container in the CSS (overflow-y:auto), butrenderChat()scrolls#msgs(wrap.scrollTop = ...). This likely won’t actually scroll the visible container when messages overflow. Update the code to scroll the element that actually has overflow (e.g.,document.getElementById('chatlog')), or scroll the last message into view.
| as: Tag = "div", | ||
| }: { | ||
| children: ReactNode; | ||
| delay?: number; | ||
| className?: string; | ||
| as?: "div" | "li"; | ||
| }) { | ||
| const ref = useRef<HTMLDivElement>(null); |
| const Comp = Tag as "div"; | ||
|
|
||
| return ( | ||
| <Comp | ||
| ref={ref} |
| next-env.d.ts | ||
| *.tsbuildinfo |
| const mq = window.matchMedia("(prefers-reduced-motion: reduce)"); | ||
| setReduced(mq.matches); | ||
| const onChange = () => setReduced(mq.matches); | ||
| mq.addEventListener("change", onChange); | ||
| return () => mq.removeEventListener("change", onChange); |
WeOwn AI is the venture studio; WeOwnChat is the product this page sells. Updates the page title/metadata, hero copy, nav + footer wordmark (was split across a <span> for accent-color styling, so it didn't match a plain-text search for "WeOwn AI" and needed a separate check), and the dashboard-preview iframe's title attribute. Also re-syncs public/_demo/dashboard-preview.html with the same fix landing in the real dashboard template (anythingllm-docker — separate PR), per that file's own maintenance rule: it follows the real template, never the reverse. Also includes the .vercel entry the Vercel CLI added to .gitignore on first deploy link (project-link metadata, correctly excluded). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 31 out of 33 changed files in this pull request and generated no new comments.
Suppressed comments (3)
landing-purchase/components/Reveal.tsx:22
Revealallowsas: "div" | "li", but the ref is typed asHTMLDivElement, which becomes incorrect as soon asas="li"is used (type mismatch and potential incorrect assumptions in future edits). This should be typed to a genericHTMLElement(or fully generic over the intrinsic element). (NIST CSF §3.1 PR.IP — secure/robust implementation; MEDIUM)
as?: "div" | "li";
}) {
const ref = useRef<HTMLDivElement>(null);
const [visible, setVisible] = useState(false);
landing-purchase/components/Reveal.tsx:45
const Comp = Tag as "div"forces the component type todiveven whenas="li"is passed, andref={ref}then no longer matches the rendered element type. This defeats the point of theasprop and can hide real typing issues. Useconst Comp = Tag;and cast the ref (or make the component generic) so the runtime element and types stay aligned. (NIST CSF §3.1 PR.IP — robust client code; MEDIUM)
const Comp = Tag as "div";
return (
<Comp
ref={ref}
landing-purchase/components/ProductShowcase.tsx:83
- The embedded dashboard preview runs same-origin and executes scripts. Without a
sandbox, the iframe content can freely interact with the parent page (e.g., navigate top-level, read/modify parent DOM) if it ever regresses or is modified later. Add a restrictivesandboxthat still permits required functionality (scripts + same-origin + forms) to reduce blast radius. (NIST CSF §3.1 PR.PS — browser isolation/hardening; HIGH)
<iframe
ref={iframeRef}
src="/_demo/dashboard-preview.html"
title="WeOwnChat dashboard preview, with example content"
className="h-[420px] w-full sm:h-[540px]"
|
Closing this in favor of a fresh PR — the page has been rewritten wholesale on Astro (was Next.js) per direct direction to match the framework used elsewhere in the WeOwn ecosystem. All content/design/animation work carries over unchanged (WeOwnChat branding, real dashboard tokens, the live-preview iframe, etc.); the rewrite also hardened the scroll-reveal system after testing surfaced a real gap in it. Same page, different (and cleaner — 0 npm audit findings vs. 3) foundation, in a new PR rather than a confusing delete-everything-add-everything diff on this one. |
Summary
First build of the WeOwn Chat Landing/Purchase page (PRD roadmap item 2 — the top-of-funnel marketing site; the transactional purchase/checkout flow itself already lives separately at
billing.weown.dev, live in test-mode). Newlanding-purchase/project: Next.js 15 (App Router) + TypeScript + Tailwind v4.Also adds
.claude/skills/weownchat-design/— a Claude Code skill capturing the real WeOwn brand tokens, so this page (and any future frontend work) is built from the actual product's design system instead of an independently-invented one. See "Design tokens" below — this went through one real correction mid-build and I'm surfacing that rather than hiding it.What's in the page
Design tokens — sourced from the real product
Colors (
--bg: #0e1726,--accent: #00A3FF, ...), the system-ui font stack (no webfonts — the real product loads none), and the 8/10/16/999px radius scale are copied verbatim from:anythingllm-docker/template/dashboard/public/index.html's:rootweownlogin theme (keycloak-docker/.../theme/weown/login/resources/css/weown.css)Corrected mid-build: an earlier pass had invented its own light/warm/serif palette before checking whether a real brand already existed. It did. Everything was rebuilt against the real tokens once caught — see
.claude/skills/weownchat-design/SKILL.md's own changelog (v1 → v2) for the full account. The skill exists specifically so this doesn't happen again on the next frontend surface.The dashboard iframe, in detail
landing-purchase/public/_demo/dashboard-preview.htmlis an unmodified copy of the real dashboard template with one addition: awindow.fetchmock feeding it realistic fictional content (a placeholder tenant,Harborview CPA— matching the existingweown-cpa-demo.pages.devplaceholder-brand convention already used elsewhere in this repo) instead of hitting a live backend. The real app's own code, hash router, and tab logic run completely unmodified — the Private/Public toggle on the landing page just setsiframe.contentWindow.location.hash.Maintenance contract (stated in the file's own header comment): edit this file to match the real template if the dashboard's markup changes — never the reverse.
.gitignoreNarrowed from a blanket
.claude/exclusion to.claude/*+!.claude/skills/. Skills are authored, shareable content (not session/worktree/transcript noise, which is what that rule was originally written for) — this makes.claude/skills/trackable while everything else under.claude/stays ignored.Verification
next build— clean: types check, lint passes, static generation succeeds (108 KB first-load JS, fully prerendered).gitleaks/pre-commitweren't available in this environment to run directly; CI's own secret-scan is the backstop.)Explicitly out of scope / open follow-ups
Tracked in
landing-purchase/CHANGELOG.mdandREADME.md:*-docker/service) vs. a static host. Nothing here forecloses either path.npm audit: 3 high-severity issues, both nested inside Next.js's ownpostcss/sharp. The only available fix is a Next 16 major-version bump — not taken unilaterally given the breaking-change risk; flagging for a deliberate look rather than silently ignoring or force-upgrading.billing.weown.dev.🤖 Generated with Claude Code