Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
96b5154
feat(lens): data-testid sweep — organizations page + custom-select
cbroberg Jun 2, 2026
8662260
feat(lens): data-testid sweep — approval + preview pages
cbroberg Jun 2, 2026
8c8196f
feat(lens): data-testid sweep — mode toggle, time input
cbroberg Jun 2, 2026
dc69a8d
feat(lens): data-testid sweep — help button component
cbroberg Jun 2, 2026
6e9b2a6
feat(lens): data-testid sweep — tab bar component
cbroberg Jun 2, 2026
be7cb80
test(cms-admin): add data-testid attributes for Lens visual testing
cbroberg Jun 2, 2026
5216b88
test(cms-admin): add data-testid to general-settings, totp-panel, mod…
cbroberg Jun 2, 2026
0a6df8e
test(cms-admin): add data-testid to dev-inspector and deploy-wizard
cbroberg Jun 2, 2026
4cd86d8
test(cms-admin): add data-testid to map-leaflet container
cbroberg Jun 2, 2026
2dea53b
test(cms-admin): data-testid sweep — curation, calendar, settings pan…
cbroberg Jun 2, 2026
b115fef
test(cms-admin): add comprehensive data-testid coverage to rich-text-…
cbroberg Jun 2, 2026
7284740
test: add data-testid attributes to document-editor.tsx for Lens veri…
cbroberg Jun 2, 2026
5a46bbe
test(cms-admin): data-testid sweep wave 4 — document-editor, deploy-s…
cbroberg Jun 2, 2026
b78f5a0
test(cms-admin): data-testid sweep wave 5 — final real-UI gap closure…
cbroberg Jun 2, 2026
c54ab5c
fix(lens): correct 3 sweep-introduced type errors (item.name not .slu…
cbroberg Jun 2, 2026
4840497
feat(lens): lens.manifest.json (26 surfaces) + <page>-root anchors
cbroberg Jun 2, 2026
18106be
feat(lens): fixture site + storageState auth + settle-timer waitFor f…
cbroberg Jun 2, 2026
297c57f
fix(lens): drop admin-setup surface + dashboard assert (cardmem captu…
cbroberg Jun 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,4 @@ localhost+*.pem
# Claude Code runtime state — local only, never commit
.claude/scheduled_tasks.lock
.claude/scheduled_tasks.json
.lens/
35 changes: 35 additions & 0 deletions examples/lens-fixture/cms.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { defineConfig, defineCollection } from "@webhouse/cms";

/**
* Lens fixture site — a deterministic local-only tenant used by the Lens
* visual-regression manifest (lens.manifest.json) so admin surfaces have
* stable, predictable content to render and capture. Registered locally as
* site slug `lens-fixture-site` (org `lens`). Not a real customer site.
*/
export default defineConfig({
collections: [
defineCollection({
name: "posts",
label: "Posts",
fields: [
{ name: "title", type: "text", label: "Title", required: true },
{ name: "excerpt", type: "textarea", label: "Excerpt" },
{ name: "content", type: "richtext", label: "Content" },
{ name: "date", type: "date", label: "Publish Date" },
],
}),
defineCollection({
name: "pages",
label: "Pages",
urlPrefix: "/",
fields: [
{ name: "title", type: "text", label: "Title", required: true },
{ name: "content", type: "richtext", label: "Content" },
],
}),
],
storage: {
adapter: "filesystem",
filesystem: { contentDir: "content" },
},
});
12 changes: 12 additions & 0 deletions examples/lens-fixture/content/posts/second-post.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"slug": "second-post",
"status": "draft",
"data": {
"title": "A Second Fixture Post",
"excerpt": "A draft post so the content list shows mixed statuses.",
"content": "A second deterministic post, kept as a draft so the collection list renders both a published and a draft row.",
"date": "2026-01-02"
},
"id": "lens-fixture-post-second",
"_fieldMeta": {}
}
12 changes: 12 additions & 0 deletions examples/lens-fixture/content/posts/welcome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"slug": "welcome",
"status": "published",
"data": {
"title": "Welcome to the Lens Fixture",
"excerpt": "A deterministic post used by Lens visual-regression baselines.",
"content": "This is fixture content for the Lens visual-regression suite. It never changes, so admin surfaces render predictably for stable screenshots.\n\n## Section one\n\nDeterministic body text for the content surface.",
"date": "2026-01-01"
},
"id": "lens-fixture-post-welcome",
"_fieldMeta": {}
}
213 changes: 213 additions & 0 deletions lens.manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
{
"project": "cms",
"base_url": "https://localhost:3010",
"diff_threshold": 0.01,
"auth": {
"adapter": "storageState",
"statePath": "./.lens/storage-state.json"
},
"surfaces": [
{
"name": "admin-login",
"path": "/admin/login",
"mode": "element",
"selector": "[data-testid=\"login-root\"]",
"waitFor": "[data-testid=\"login-root\"]",
"baseline_key": "admin-login",
"auth": null
},
{
"name": "admin-signup",
"path": "/admin/signup",
"mode": "element",
"selector": "[data-testid=\"signup-root\"]",
"waitFor": "[data-testid=\"signup-root\"]",
"baseline_key": "admin-signup",
"auth": null
},
{
"name": "admin-command",
"path": "/admin/lens-fixture-site/command",
"mode": "element",
"selector": "[data-testid=\"command-root\"]",
"waitFor": "[data-testid=\"command-root\"]",
"baseline_key": "admin-command"
},
{
"name": "admin-dashboard",
"path": "/admin/lens-fixture-site",
"mode": "element",
"selector": "[data-testid=\"dashboard-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-content",
"path": "/admin/lens-fixture-site/content/posts",
"mode": "element",
"selector": "[data-testid=\"content-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-media",
"path": "/admin/lens-fixture-site/media",
"mode": "element",
"selector": "[data-testid=\"media-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-forms",
"path": "/admin/lens-fixture-site/forms",
"mode": "element",
"selector": "[data-testid=\"forms-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-interactives",
"path": "/admin/lens-fixture-site/interactives",
"mode": "element",
"selector": "[data-testid=\"interactives-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-agents",
"path": "/admin/lens-fixture-site/agents",
"mode": "element",
"selector": "[data-testid=\"agents-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-curation",
"path": "/admin/lens-fixture-site/curation",
"mode": "element",
"selector": "[data-testid=\"curation-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-log",
"path": "/admin/lens-fixture-site/log",
"mode": "element",
"selector": "[data-testid=\"log-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-scheduled",
"path": "/admin/lens-fixture-site/scheduled",
"mode": "element",
"selector": "[data-testid=\"scheduled-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-backup",
"path": "/admin/lens-fixture-site/backup",
"mode": "element",
"selector": "[data-testid=\"backup-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-trash",
"path": "/admin/lens-fixture-site/trash",
"mode": "element",
"selector": "[data-testid=\"trash-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-seo",
"path": "/admin/lens-fixture-site/seo",
"mode": "element",
"selector": "[data-testid=\"seo-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-lighthouse",
"path": "/admin/lens-fixture-site/lighthouse",
"mode": "element",
"selector": "[data-testid=\"lighthouse-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-link-checker",
"path": "/admin/lens-fixture-site/link-checker",
"mode": "element",
"selector": "[data-testid=\"link-checker-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-performance",
"path": "/admin/lens-fixture-site/performance",
"mode": "element",
"selector": "[data-testid=\"performance-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-sites",
"path": "/admin/lens-fixture-site/sites",
"mode": "element",
"selector": "[data-testid=\"sites-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-organizations",
"path": "/admin/lens-fixture-site/organizations",
"mode": "element",
"selector": "[data-testid=\"organizations-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-visibility",
"path": "/admin/lens-fixture-site/visibility",
"mode": "element",
"selector": "[data-testid=\"visibility-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-favorites",
"path": "/admin/lens-fixture-site/favorites",
"mode": "element",
"selector": "[data-testid=\"favorites-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-preview",
"path": "/admin/lens-fixture-site/preview",
"mode": "element",
"selector": "[data-testid=\"preview-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-settings",
"path": "/admin/lens-fixture-site/settings",
"mode": "element",
"selector": "[data-testid=\"settings-root\"]",
"waitFor": 2500,
"no_diff": true
},
{
"name": "admin-account",
"path": "/admin/lens-fixture-site/account",
"mode": "element",
"selector": "[data-testid=\"account-root\"]",
"waitFor": 2500,
"no_diff": true
}
]
}
52 changes: 26 additions & 26 deletions packages/cms-admin/public/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -645,36 +645,36 @@

<!-- NAV -->
<nav id="nav">
<a href="/" class="nav-logo">
<a data-testid="landing-nav-logo-link" href="/" class="nav-logo">
<img class="nav-icon" src="/webhouse-icon.svg" alt="" />
<img class="nav-wordmark" src="/webhouse-wordmark-dark.svg" alt="webhouse.app" />
</a>
<div class="nav-links">
<a href="#features">Features</a>
<a href="#architecture">Architecture</a>
<a href="#mcp">MCP</a>
<a href="https://docs.webhouse.app" target="_blank">Docs</a>
<a href="https://github.com/webhousecode/cms" target="_blank">GitHub</a>
<a href="/login">Log In</a>
<a href="/signup" class="nav-cta">Sign Up</a>
<a data-testid="landing-nav-features-link" href="#features">Features</a>
<a data-testid="landing-nav-architecture-link" href="#architecture">Architecture</a>
<a data-testid="landing-nav-mcp-link" href="#mcp">MCP</a>
<a data-testid="landing-nav-docs-link" href="https://docs.webhouse.app" target="_blank">Docs</a>
<a data-testid="landing-nav-github-link" href="https://github.com/webhousecode/cms" target="_blank">GitHub</a>
<a data-testid="landing-nav-login-link" href="/login">Log In</a>
<a data-testid="landing-nav-signup-button" href="/signup" class="nav-cta">Sign Up</a>
</div>
<button class="nav-hamburger" id="nav-hamburger" aria-label="Open menu">
<button data-testid="nav-hamburger-button" class="nav-hamburger" id="nav-hamburger" aria-label="Open menu">
<svg width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" viewBox="0 0 24 24"><path d="M4 6h16M4 12h16M4 18h16"/></svg>
</button>
</nav>

<!-- MOBILE MENU -->
<div class="nav-mobile-menu" id="mobile-menu">
<button class="nav-mobile-close" id="mobile-close" aria-label="Close menu">
<button data-testid="nav-mobile-close-button" class="nav-mobile-close" id="mobile-close" aria-label="Close menu">
<svg width="28" height="28" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" viewBox="0 0 24 24"><path d="M18 6 6 18M6 6l12 12"/></svg>
</button>
<a href="#features" class="mobile-nav-link">Features</a>
<a href="#architecture" class="mobile-nav-link">Architecture</a>
<a href="#mcp" class="mobile-nav-link">MCP</a>
<a href="https://docs.webhouse.app" target="_blank" class="mobile-nav-link">Docs</a>
<a href="https://github.com/webhousecode/cms" target="_blank">GitHub</a>
<a href="/login">Log In</a>
<a href="/signup" class="mobile-cta">Sign Up</a>
<a data-testid="landing-mobile-features-link" href="#features" class="mobile-nav-link">Features</a>
<a data-testid="landing-mobile-architecture-link" href="#architecture" class="mobile-nav-link">Architecture</a>
<a data-testid="landing-mobile-mcp-link" href="#mcp" class="mobile-nav-link">MCP</a>
<a data-testid="landing-mobile-docs-link" href="https://docs.webhouse.app" target="_blank" class="mobile-nav-link">Docs</a>
<a data-testid="landing-mobile-github-link" href="https://github.com/webhousecode/cms" target="_blank">GitHub</a>
<a data-testid="landing-mobile-login-link" href="/login">Log In</a>
<a data-testid="landing-mobile-signup-button" href="/signup" class="mobile-cta">Sign Up</a>
</div>

<!-- HERO -->
Expand All @@ -701,11 +701,11 @@
<p class="hero-tagline reveal reveal-delay-2">AI-native content engine</p>

<div class="hero-actions reveal reveal-delay-3">
<a href="/signup" class="btn-primary">
<a data-testid="hero-signup-button" href="/signup" class="btn-primary">
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>
Get Started Free
</a>
<a href="/login" class="btn-secondary">
<a data-testid="hero-login-button" href="/login" class="btn-secondary">
Log In →
</a>
</div>
Expand Down Expand Up @@ -841,11 +841,11 @@ <h3>cms-mcp-server</h3>
<h2 class="cta-title reveal reveal-delay-1">Describe what you want.<br>Get a <span style="color: var(--gold);">production-ready</span> site.</h2>
<p class="cta-subtitle reveal reveal-delay-2">Then keep iterating with AI or by hand.</p>
<div class="hero-actions reveal reveal-delay-3" style="justify-content: center;">
<a href="/signup" class="btn-primary">
<a data-testid="cta-signup-button" href="/signup" class="btn-primary">
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>
Create Free Account
</a>
<a href="https://github.com/webhousecode/cms" class="btn-secondary" target="_blank">
<a data-testid="cta-github-button" href="https://github.com/webhousecode/cms" class="btn-secondary" target="_blank">
<svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>
View on GitHub →
</a>
Expand All @@ -869,11 +869,11 @@ <h2 class="cta-title reveal reveal-delay-1">Describe what you want.<br>Get a <sp
<span>© 2026 WebHouse · webhouse.app</span>
</div>
<div class="footer-links">
<a href="https://docs.webhouse.app" target="_blank">Docs</a>
<a href="https://github.com/webhousecode" target="_blank">GitHub</a>
<a href="https://www.npmjs.com/package/@webhouse/cms" target="_blank">npm</a>
<a href="https://www.linkedin.com/company/webhouse" target="_blank">LinkedIn</a>
<a href="mailto:info@webhouse.net">Contact</a>
<a data-testid="landing-footer-docs-link" href="https://docs.webhouse.app" target="_blank">Docs</a>
<a data-testid="landing-footer-github-link" href="https://github.com/webhousecode" target="_blank">GitHub</a>
<a data-testid="landing-footer-npm-link" href="https://www.npmjs.com/package/@webhouse/cms" target="_blank">npm</a>
<a data-testid="landing-footer-linkedin-link" href="https://www.linkedin.com/company/webhouse" target="_blank">LinkedIn</a>
<a data-testid="landing-footer-contact-link" href="mailto:info@webhouse.net">Contact</a>
</div>
</footer>

Expand Down
Loading
Loading