editor: tolerate the trailing slash now that /editor is prerendered; nav links to /editor/

A fresh load of /editor is 301'd to /editor/ by nginx (prerendered dir),
while client-side navigation still lands on /editor. The three exact
pathname comparisons (header active state, header share button, starter
dialog gate) now ignore the trailing slash, and the header nav links to
/editor/ so crawled internal links match the canonical with no redirect
hop.
This commit is contained in:
David Montero 2026-08-18 17:22:47 +02:00
parent 54e25cfed5
commit 18b133311e
2 changed files with 10 additions and 4 deletions

View File

@ -104,8 +104,12 @@ export const AppHeader: React.FC<AppHeaderProps> = ({ editorMenu, editorToolbar
return null;
}
// Compare with the trailing slash ignored: /editor is served (and
// canonicalized) as /editor/ since it is prerendered, while client-side
// navigation still lands on /editor.
const samePath = (a: string, b: string) => a.replace(/\/+$/, '') === b.replace(/\/+$/, '');
const isActive = (path: string) =>
location.pathname === localize(path) ? ' header-nav-link-active' : '';
samePath(location.pathname, localize(path)) ? ' header-nav-link-active' : '';
return (
<header ref={headerRef} className={"app-header" + (editorToolbar ? ' app-header--with-toolbar' : '')}>
@ -159,7 +163,7 @@ export const AppHeader: React.FC<AppHeaderProps> = ({ editorMenu, editorToolbar
<Link to={localize('/examples')} className={'header-nav-link' + isActive('/examples')}>
{t('header.nav.examples')}
</Link>
<Link to={localize('/editor')} className={'header-nav-link' + isActive('/editor')}>
<Link to={localize('/editor/')} className={'header-nav-link' + isActive('/editor')}>
{t('header.nav.editor')}
</Link>
{import.meta.env.VITE_PRO_BUILD && (
@ -243,7 +247,7 @@ export const AppHeader: React.FC<AppHeaderProps> = ({ editorMenu, editorToolbar
<LanguageSwitcher />
{/* Share button — visible when a project is loaded */}
{currentProject && location.pathname === '/editor' && (
{currentProject && samePath(location.pathname, localize('/editor')) && (
<button
onClick={() => setShowShareModal(true)}
style={{

View File

@ -136,7 +136,9 @@ export const EditorPage: React.FC = () => {
useEffect(() => {
if (starterDialogShownThisLoad) return;
const locale = getLocaleFromPath(window.location.pathname);
if (window.location.pathname !== localizedPath('/editor', locale)) return;
// /editor is prerendered, so a fresh load arrives as /editor/ (nginx
// adds the slash); client-side navigation lands on /editor. Both count.
if (window.location.pathname.replace(/\/+$/, '') !== localizedPath('/editor', locale)) return;
if (window.location.search) return;
if (useProjectStore.getState().currentProject) return;
const sim = useSimulatorStore.getState();