Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,7 @@ next-env.d.ts

# Tree maker
tree-maker
.claude
.cursor
.claude/
.cursor/
17 changes: 8 additions & 9 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@ import Preview from "@/components/Preview";
// Home page component - serves as the main entry point for the application
// This is an async server component that can fetch data at build time or request time
export default async function Home() {
// Check if the application is running in preview mode
// Preview mode enables live editing capabilities for content creators
// Fetch the entry on the server in both branches so the SSR'd HTML always
// contains the real content. This is what makes browser Back navigation
// restore the page correctly instead of a "Loading…" placeholder.
const page = await getPage("/");

// In preview mode, hand the entry to the client component so it can keep
// syncing with the Visual Builder via the live-preview listener.
if (isPreview) {
// Return the Preview component which handles real-time content updates
// The path "/" represents the home page URL in Contentstack
return <Preview path="/" />;
return <Preview path="/" initialPage={page} />;
}

// In production mode, fetch the page data server-side for better performance
const page = await getPage("/"); // Fetch home page content from Contentstack

// Return the static Page component with the pre-fetched data
return <Page page={page} />;
}
30 changes: 21 additions & 9 deletions components/Preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,16 @@ const LoadingState = () => (
);

// Preview component that handles live preview functionality for Contentstack
export default function Preview({ path }: { path: string }) {
// State to store the fetched page data
const [page, setPage] = useState<PageProps>();
export default function Preview({
path,
initialPage,
}: {
path: string;
initialPage?: PageProps;
}) {
// Seed state with the server-fetched entry so the SSR'd HTML contains the
// real content and back/forward navigation restores a populated page.
const [page, setPage] = useState<PageProps | undefined>(initialPage);

// Memoized function to fetch content data based on the current path
// useCallback prevents unnecessary re-renders when path doesn't change
Expand All @@ -34,15 +41,20 @@ export default function Preview({ path }: { path: string }) {
// Effect hook to initialize live preview and set up content change listener
useEffect(() => {
initLivePreview(); // Initialize Contentstack Live Preview functionality
// Set up listener for content changes in the Contentstack interface
ContentstackLivePreview.onEntryChange(getContent); // Refetch content when changes occur
}, [path]); // Re-run effect when path changes
// Subscribe to Visual Builder edits. skipInitialRender prevents a redundant
// fetch on mount — the initial entry already came from the server.
const uid = ContentstackLivePreview.onEntryChange(getContent, {
skipInitialRender: true,
});
return () => {
ContentstackLivePreview.unsubscribeOnEntryChange(uid);
};
}, [path, getContent]);

// Show loading state while page data is being fetched
// Defensive fallback for when the entry isn't available (e.g. no matching URL).
if (!page) {
return <LoadingState />;
}

// Render the Page component with the fetched page data
return <Page page={page as PageProps} />;
return <Page page={page} />;
}
Loading