site-builder: lock landing page to index.html regardless of name

The first page is now treated as the landing page: it always publishes to
index.html no matter what the user names it, and its slug is forced to
'index' in state so .htaccess clean-URL rewrites stay consistent.

- useWhpApi.ts: force pages[0].filename='index.html' at save time
- PageContext.tsx: heal pages[0].slug to 'index' on load and on rename
- PagesPanel.tsx: "LANDING" badge on first page, slug shown as '/',
  rename hides slug input (locked), delete button hidden

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-25 12:14:26 -07:00
parent 330032eea3
commit 7b747f775f
3 changed files with 76 additions and 24 deletions
+13 -5
View File
@@ -276,9 +276,14 @@ export const PageProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
const renamePage = useCallback((pageId: string, name: string, slug: string) => {
setPages((prev) =>
prev.map((p) =>
p.id === pageId ? { ...p, name, slug: slug || slugify(name) } : p,
),
prev.map((p, i) => {
if (p.id !== pageId) return p;
// First page is the landing page — its slug is locked to 'index' so
// the file always publishes to index.html regardless of the user-set
// name. The display name can change freely.
const nextSlug = i === 0 ? 'index' : (slug || slugify(name));
return { ...p, name, slug: nextSlug };
}),
);
}, []);
@@ -294,10 +299,13 @@ export const PageProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
/** Allow external code (e.g., load from API) to restore pages with craft states */
const setPagesCraftState = useCallback((pagesData: { id: string; name: string; slug: string; craftState: string | null }[]) => {
setPages(pagesData.map((p) => ({
setPages(pagesData.map((p, i) => ({
id: p.id,
name: p.name,
slug: p.slug,
// Heal legacy projects whose first page was saved with slug='home' (or
// any other) before the landing-page rule existed. The first page is
// ALWAYS the landing page → slug 'index' → file index.html.
slug: i === 0 ? 'index' : p.slug,
craftState: p.craftState,
headCode: '',
})));