diff --git a/.gitignore b/.gitignore index 2bac87140..faca41e70 100644 --- a/.gitignore +++ b/.gitignore @@ -195,3 +195,4 @@ localhost+*.pem # Claude Code runtime state — local only, never commit .claude/scheduled_tasks.lock .claude/scheduled_tasks.json +.lens/ diff --git a/examples/lens-fixture/cms.config.ts b/examples/lens-fixture/cms.config.ts new file mode 100644 index 000000000..a43eb7ee5 --- /dev/null +++ b/examples/lens-fixture/cms.config.ts @@ -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" }, + }, +}); diff --git a/examples/lens-fixture/content/posts/second-post.json b/examples/lens-fixture/content/posts/second-post.json new file mode 100644 index 000000000..d8fa674a6 --- /dev/null +++ b/examples/lens-fixture/content/posts/second-post.json @@ -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": {} +} diff --git a/examples/lens-fixture/content/posts/welcome.json b/examples/lens-fixture/content/posts/welcome.json new file mode 100644 index 000000000..eb5ad3405 --- /dev/null +++ b/examples/lens-fixture/content/posts/welcome.json @@ -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": {} +} diff --git a/lens.manifest.json b/lens.manifest.json new file mode 100644 index 000000000..8035278e9 --- /dev/null +++ b/lens.manifest.json @@ -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 + } + ] +} diff --git a/packages/cms-admin/public/home.html b/packages/cms-admin/public/home.html index 837513b04..f1e3f0b5b 100644 --- a/packages/cms-admin/public/home.html +++ b/packages/cms-admin/public/home.html @@ -645,36 +645,36 @@
@@ -701,11 +701,11 @@AI-native content engine
@@ -841,11 +841,11 @@Then keep iterating with AI or by hand.