fix(examples): example pages re-render when the overlay registers late examples

registerProExamples() now notifies useSyncExternalStore subscribers (same
contract as proRoutes): a direct URL to an overlay-registered example resolved
before the dynamic @pro import landed and stuck on the 404 branch. The three
example pages subscribe to the version counter.
This commit is contained in:
David Montero Crespo 2026-07-22 21:43:03 +02:00
parent a7c36f7a7b
commit d90e738995
4 changed files with 32 additions and 3 deletions

View File

@ -10023,10 +10023,27 @@ export function getExampleById(id: string): ExampleProject | undefined {
* registers at runtime. Push-based (the exported array is the single source
* the gallery and /example/:slug both read), idempotent per example id.
*/
let proExamplesVersion = 0;
const proExamplesListeners = new Set<() => void>();
export function registerProExamples(examples: ExampleProject[]): void {
for (const ex of examples) {
if (!exampleProjects.some((e) => e.id === ex.id)) exampleProjects.push(ex);
}
// Overlay registration can land AFTER a direct-URL page render resolved the
// array (the @pro import is dynamic) — notify subscribers so example pages
// re-render instead of sticking on a 404 (same contract as proRoutes).
proExamplesVersion++;
for (const l of proExamplesListeners) l();
}
export function subscribeProExamples(cb: () => void): () => void {
proExamplesListeners.add(cb);
return () => proExamplesListeners.delete(cb);
}
export function getProExamplesVersion(): number {
return proExamplesVersion;
}
// Get all categories

View File

@ -10,8 +10,9 @@
*/
import React from 'react';
import { useSyncExternalStore } from 'react';
import { useParams, useNavigate, Link } from 'react-router-dom';
import { exampleProjects } from '../data/examples';
import { exampleProjects, subscribeProExamples, getProExamplesVersion } from '../data/examples';
import { AppHeader } from '../components/layout/AppHeader';
import { ExampleThumbnail } from '../components/examples/ExampleThumbnail';
import { useSEO } from '../utils/useSEO';
@ -44,6 +45,9 @@ const DIFFICULTY_COLOR: Record<string, string> = {
};
export const ExampleDetailPage: React.FC = () => {
// Re-render when the pro overlay registers late examples (dynamic import).
useSyncExternalStore(subscribeProExamples, getProExamplesVersion, getProExamplesVersion);
const { exampleId } = useParams<{ exampleId: string }>();
const navigate = useNavigate();

View File

@ -21,9 +21,9 @@
* id is set on useProjectStore, so it can't overwrite anything).
*/
import { useEffect, useRef, useState } from 'react';
import { useEffect, useRef, useState, useSyncExternalStore } from 'react';
import { useParams } from 'react-router-dom';
import { exampleProjects } from '../data/examples';
import { exampleProjects, subscribeProExamples, getProExamplesVersion } from '../data/examples';
import { loadExample, type LibraryInstallProgress } from '../utils/loadExample';
import { EditorPage } from './EditorPage';
import { AppHeader } from '../components/layout/AppHeader';
@ -32,6 +32,9 @@ import { useSEO } from '../utils/useSEO';
const DOMAIN = 'https://velxio.dev';
export const ExampleEditorPage: React.FC = () => {
// Re-render when the pro overlay registers late examples (dynamic import).
useSyncExternalStore(subscribeProExamples, getProExamplesVersion, getProExamplesVersion);
const { exampleId } = useParams<{ exampleId: string }>();
const [ready, setReady] = useState(false);
const [error, setError] = useState(false);

View File

@ -8,6 +8,8 @@
*/
import React from 'react';
import { useSyncExternalStore } from 'react';
import { subscribeProExamples, getProExamplesVersion } from '../data/examples';
import { useNavigate } from 'react-router-dom';
import { ExamplesGallery } from '../components/examples/ExamplesGallery';
import { CommunityProjectsGrid } from '../components/examples/CommunityProjectsGrid';
@ -18,6 +20,9 @@ import { getSeoMeta } from '../seoRoutes';
import type { ExampleProject } from '../data/examples';
export const ExamplesPage: React.FC = () => {
// Re-render when the pro overlay registers late examples (dynamic import).
useSyncExternalStore(subscribeProExamples, getProExamplesVersion, getProExamplesVersion);
const localize = useLocalizedHref();
useSEO(getSeoMeta('/examples')!);