docs(docs-infra): move the navigation related files (#63729)

* separate directory
* dedicated file for redirections

PR Close #63729
This commit is contained in:
Matthieu Riegler
2025-09-11 12:00:07 +02:00
committed by Jessica Janiuk
parent 895f0fb814
commit 9de50b1e7d
9 changed files with 329 additions and 315 deletions
+1 -1
View File
@@ -9,7 +9,7 @@
import {TestBed} from '@angular/core/testing';
import {AppComponent} from './app.component';
import {provideRouter, withComponentInputBinding} from '@angular/router';
import {routes} from './routes';
import {routes} from './routing/routes';
import {Search, WINDOW} from '@angular/docs';
import {provideHttpClient} from '@angular/common/http';
import {provideHttpClientTesting} from '@angular/common/http/testing';
+1 -1
View File
@@ -31,7 +31,7 @@ import {AnalyticsService} from './core/services/analytics/analytics.service';
import {ContentLoader} from './core/services/content-loader.service';
import {CustomErrorHandler} from './core/services/errors-handling/error-handler';
import {ExampleContentLoader} from './core/services/example-content-loader.service';
import {routerProviders} from './router_providers';
import {routerProviders} from './routing/router_providers';
export const appConfig: ApplicationConfig = {
providers: [
@@ -20,7 +20,7 @@ import {
} from '@angular/docs';
import {NavigationEnd, Router, RouterLink} from '@angular/router';
import {filter, map, startWith} from 'rxjs/operators';
import {DOCS_ROUTES, REFERENCE_ROUTES, TUTORIALS_ROUTES} from '../../../routes';
import {DOCS_ROUTES, REFERENCE_ROUTES, TUTORIALS_ROUTES} from '../../../routing/routes';
import {Theme, ThemeManager} from '../../services/theme-manager.service';
import {VersionManager} from '../../services/version-manager.service';
import {ConnectionPositionPair} from '@angular/cdk/overlay';
@@ -28,7 +28,7 @@ import {
shouldReduceMotion,
} from '@angular/docs';
import {distinctUntilChanged, filter, map, skip, startWith} from 'rxjs/operators';
import {SUB_NAVIGATION_DATA} from '../../../sub-navigation-data';
import {SUB_NAVIGATION_DATA} from '../../../routing/sub-navigation-data';
import {ActivatedRouteSnapshot, NavigationEnd, Router, RouterStateSnapshot} from '@angular/router';
import {isPlatformBrowser} from '@angular/common';
import {PRIMARY_NAV_ID, SECONDARY_NAV_ID} from '../../constants/element-ids';
-300
View File
@@ -1,300 +0,0 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {contentResolver, flatNavigationData, mapNavigationItemsToRoutes} from '@angular/docs';
import {Route} from '@angular/router';
import {SUB_NAVIGATION_DATA} from './sub-navigation-data';
import {mapApiManifestToRoutes} from './features/references/helpers/manifest.helper';
import MainComponent from './main.component';
import {DEFAULT_PAGES, PAGE_PREFIX} from './core/constants/pages';
// Docs navigation data contains routes which navigates to /tutorials pages, in
// that case we should load Tutorial component
export const DOCS_ROUTES: Route[] = mapNavigationItemsToRoutes(
flatNavigationData(SUB_NAVIGATION_DATA.docs).filter(
(route) =>
!route.path?.startsWith(PAGE_PREFIX.TUTORIALS) && route.path !== PAGE_PREFIX.PLAYGROUND,
),
{
loadComponent: () => import('./features/docs/docs.component'),
data: {
displaySecondaryNav: true,
},
},
);
const referenceNavigationItems = flatNavigationData(SUB_NAVIGATION_DATA.reference);
const commonReferenceRouteData = {
displaySecondaryNav: true,
};
const referencePageRoutes = mapNavigationItemsToRoutes(
referenceNavigationItems.filter((r) => r.path === DEFAULT_PAGES.REFERENCE),
{
loadComponent: () =>
import('./features/references/api-reference-list/api-reference-list.component'),
data: commonReferenceRouteData,
},
);
const updateGuidePageRoute: Route = {
path: referenceNavigationItems.find((r) => r.path === DEFAULT_PAGES.UPDATE)!.path,
loadComponent: () => import('./features/update/update.component'),
data: commonReferenceRouteData,
};
const cliReferencePageRoutes = mapNavigationItemsToRoutes(
referenceNavigationItems.filter((r) => r.path?.startsWith(`${PAGE_PREFIX.CLI}/`)),
{
loadComponent: () =>
import(
'./features/references/cli-reference-details-page/cli-reference-details-page.component'
),
data: commonReferenceRouteData,
},
).map((route) => ({
...route,
resolve: {
docContent: contentResolver(`${route.path}.html`),
},
}));
const docsReferencePageRoutes = mapNavigationItemsToRoutes(
referenceNavigationItems.filter(
(r) =>
r.path !== DEFAULT_PAGES.REFERENCE &&
r.path !== DEFAULT_PAGES.UPDATE &&
!r.path?.startsWith(`${PAGE_PREFIX.API}/`) &&
!r.path?.startsWith(`${PAGE_PREFIX.CLI}/`),
),
{
loadComponent: () => import('./features/docs/docs.component'),
data: {
...commonReferenceRouteData,
},
},
);
export const REFERENCE_ROUTES = [
...referencePageRoutes,
...docsReferencePageRoutes,
...cliReferencePageRoutes,
];
const tutorialsNavigationItems = flatNavigationData(SUB_NAVIGATION_DATA.tutorials);
const commonTutorialRouteData = {
hideFooter: true,
};
const docsTutorialsRoutes = mapNavigationItemsToRoutes(
tutorialsNavigationItems.filter((route) => route.path === DEFAULT_PAGES.TUTORIALS),
{
loadComponent: () => import('./features/docs/docs.component'),
data: {
...commonTutorialRouteData,
},
},
);
const tutorialComponentRoutes = mapNavigationItemsToRoutes(
tutorialsNavigationItems.filter((route) => route.path !== DEFAULT_PAGES.TUTORIALS),
{
loadComponent: () => import('./features/tutorial/tutorial.component'),
data: {...commonTutorialRouteData},
},
);
export const TUTORIALS_ROUTES = [...docsTutorialsRoutes, ...tutorialComponentRoutes];
// Based on SUB_NAVIGATION_DATA structure, we need to build the routing table
// for content pages.
export const SUB_NAVIGATION_ROUTES: Route[] = [
...DOCS_ROUTES,
...REFERENCE_ROUTES,
...TUTORIALS_ROUTES,
];
const FOOTER_ROUTES: Route[] = mapNavigationItemsToRoutes(
flatNavigationData(SUB_NAVIGATION_DATA.footer),
{loadComponent: () => import('./features/docs/docs.component')},
);
const API_REFERENCE_ROUTES: Route[] = mapApiManifestToRoutes();
const REDIRECT_ROUTES: Route[] = [
{
path: 'guide/defer',
redirectTo: '/guide/templates/defer',
},
{
path: 'guide/components/importing',
redirectTo: '/guide/components/anatomy-of-components#using-components',
},
{
path: 'guide/templates/attribute-binding',
redirectTo: '/guide/templates/binding#binding-dynamic-properties-and-attributes',
},
{
path: 'guide/templates/interpolation',
redirectTo: '/guide/templates/binding#render-dynamic-text-with-text-interpolation',
},
{
path: 'guide/templates/class-binding',
redirectTo: '/guide/templates/binding#css-class-and-style-property-bindings',
},
{
path: 'guide/templates/event-binding',
redirectTo: '/guide/templates/event-listeners',
},
{
path: 'guide/templates/let-template-variables',
redirectTo: '/guide/templates/variables#local-template-variables-with-let',
},
{
path: 'guide/templates/property-binding',
redirectTo: '/guide/templates/binding#binding-dynamic-properties-and-attributes',
},
{
path: 'guide/templates/property-binding-best-practices',
redirectTo: '/guide/templates/binding#binding-dynamic-properties-and-attributes',
},
{
path: 'guide/templates/reference-variables',
redirectTo: '/guide/templates/variables#template-reference-variables',
},
{
path: 'guide/templates/svg-in-templates',
redirectTo: '/guide/templates/binding',
},
{
path: 'guide/templates/template-statements',
redirectTo: '/guide/templates/event-listeners',
},
{
path: 'guide/signals/rxjs-interop',
redirectTo: '/ecosystem/rxjs-interop',
},
{
path: 'guide/components/output-function',
redirectTo: '/guide/components/outputs',
},
{
path: 'guide/signals/queries',
redirectTo: '/guide/components/queries',
},
{
path: 'guide/signals/model',
redirectTo: '/guide/signals/inputs',
},
{
path: 'guide/signals/inputs',
redirectTo: '/guide/components/inputs',
},
{
path: 'guide/ngmodules',
redirectTo: '/guide/ngmodules/overview',
},
{
path: 'guide/ngmodules/providers',
redirectTo: '/guide/ngmodules/overview',
},
{
path: 'guide/ngmodules/singleton-services',
redirectTo: '/guide/ngmodules/overview',
},
{
path: 'guide/ngmodules/lazy-loading',
redirectTo: '/guide/ngmodules/overview',
},
{
path: 'guide/ngmodules/faq',
redirectTo: '/guide/ngmodules/overview',
},
{
path: 'guide/components/anatomy-of-components',
redirectTo: '/guide/components',
},
{
path: 'guide/hybrid-rendering',
redirectTo: '/guide/ssr',
},
{
path: 'guide/prerendering',
redirectTo: '/guide/ssr',
},
{
path: 'hmr',
redirectTo: '/tools/cli/build-system-migration#hot-module-replacement',
},
{
path: 'guide',
children: [
{
path: 'pipes',
redirectTo: '/guide/templates/pipes',
},
],
},
{
path: 'guide/experimental/zoneless',
redirectTo: '/guide/zoneless',
},
{
path: 'guide/animations/route-animations',
redirectTo: '/guide/routing/route-transition-animations',
},
{
path: 'guide/animations/enter-and-leave',
redirectTo: '/guide/animations',
},
{
path: 'guide/animations/transitions-and-triggers',
redirectTo: '/guide/legacy-animations/transitions-and-triggers',
},
{
path: 'guide/animations/complex-sequences',
redirectTo: '/guide/legacy-animations/complex-sequences',
},
{
path: 'guide/animations/reusable-animations',
redirectTo: '/guide/legacy-animations/reusable-animations',
},
];
export const routes: Route[] = [
{
path: '',
component: MainComponent,
children: [
{
path: '',
loadComponent: () => import('./features/home/home.component'),
data: {label: 'Home'},
},
{
path: PAGE_PREFIX.DOCS,
redirectTo: DEFAULT_PAGES.DOCS,
},
{
path: PAGE_PREFIX.REFERENCE,
redirectTo: DEFAULT_PAGES.REFERENCE,
},
{
path: PAGE_PREFIX.PLAYGROUND,
loadComponent: () => import('./features/playground/playground.component'),
data: {...commonTutorialRouteData, label: 'Playground'},
},
...SUB_NAVIGATION_ROUTES,
...API_REFERENCE_ROUTES,
...FOOTER_ROUTES,
updateGuidePageRoute,
...REDIRECT_ROUTES,
],
},
// Error page
{
path: '**',
loadComponent: () => import('./features/docs/docs.component'),
resolve: {'docContent': contentResolver('error')},
},
];
+153
View File
@@ -0,0 +1,153 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {Route} from '@angular/router';
/**
* This file contains the redirections we keep to prevent breakages on existing links
* that may exist on the internet and over which we have no control.
*/
export const REDIRECT_ROUTES: Route[] = [
{
path: 'guide/defer',
redirectTo: '/guide/templates/defer',
},
{
path: 'guide/components/importing',
redirectTo: '/guide/components/anatomy-of-components#using-components',
},
{
path: 'guide/templates/attribute-binding',
redirectTo: '/guide/templates/binding#binding-dynamic-properties-and-attributes',
},
{
path: 'guide/templates/interpolation',
redirectTo: '/guide/templates/binding#render-dynamic-text-with-text-interpolation',
},
{
path: 'guide/templates/class-binding',
redirectTo: '/guide/templates/binding#css-class-and-style-property-bindings',
},
{
path: 'guide/templates/event-binding',
redirectTo: '/guide/templates/event-listeners',
},
{
path: 'guide/templates/let-template-variables',
redirectTo: '/guide/templates/variables#local-template-variables-with-let',
},
{
path: 'guide/templates/property-binding',
redirectTo: '/guide/templates/binding#binding-dynamic-properties-and-attributes',
},
{
path: 'guide/templates/property-binding-best-practices',
redirectTo: '/guide/templates/binding#binding-dynamic-properties-and-attributes',
},
{
path: 'guide/templates/reference-variables',
redirectTo: '/guide/templates/variables#template-reference-variables',
},
{
path: 'guide/templates/svg-in-templates',
redirectTo: '/guide/templates/binding',
},
{
path: 'guide/templates/template-statements',
redirectTo: '/guide/templates/event-listeners',
},
{
path: 'guide/signals/rxjs-interop',
redirectTo: '/ecosystem/rxjs-interop',
},
{
path: 'guide/components/output-function',
redirectTo: '/guide/components/outputs',
},
{
path: 'guide/signals/queries',
redirectTo: '/guide/components/queries',
},
{
path: 'guide/signals/model',
redirectTo: '/guide/signals/inputs',
},
{
path: 'guide/signals/inputs',
redirectTo: '/guide/components/inputs',
},
{
path: 'guide/ngmodules',
redirectTo: '/guide/ngmodules/overview',
},
{
path: 'guide/ngmodules/providers',
redirectTo: '/guide/ngmodules/overview',
},
{
path: 'guide/ngmodules/singleton-services',
redirectTo: '/guide/ngmodules/overview',
},
{
path: 'guide/ngmodules/lazy-loading',
redirectTo: '/guide/ngmodules/overview',
},
{
path: 'guide/ngmodules/faq',
redirectTo: '/guide/ngmodules/overview',
},
{
path: 'guide/components/anatomy-of-components',
redirectTo: '/guide/components',
},
{
path: 'guide/hybrid-rendering',
redirectTo: '/guide/ssr',
},
{
path: 'guide/prerendering',
redirectTo: '/guide/ssr',
},
{
path: 'hmr',
redirectTo: '/tools/cli/build-system-migration#hot-module-replacement',
},
{
path: 'guide',
children: [
{
path: 'pipes',
redirectTo: '/guide/templates/pipes',
},
],
},
{
path: 'guide/experimental/zoneless',
redirectTo: '/guide/zoneless',
},
{
path: 'guide/animations/route-animations',
redirectTo: '/guide/routing/route-transition-animations',
},
{
path: 'guide/animations/enter-and-leave',
redirectTo: '/guide/animations',
},
{
path: 'guide/animations/transitions-and-triggers',
redirectTo: '/guide/legacy-animations/transitions-and-triggers',
},
{
path: 'guide/animations/complex-sequences',
redirectTo: '/guide/legacy-animations/complex-sequences',
},
{
path: 'guide/animations/reusable-animations',
redirectTo: '/guide/legacy-animations/reusable-animations',
},
];
@@ -24,9 +24,9 @@ import {
withRouterConfig,
} from '@angular/router';
import {routes} from './routes';
import {ADevTitleStrategy} from './core/services/a-dev-title-strategy';
import {ReuseTutorialsRouteStrategy} from './features/tutorial/tutorials-route-reuse-strategy';
import {AppScroller} from './app-scroller';
import {ADevTitleStrategy} from '../core/services/a-dev-title-strategy';
import {ReuseTutorialsRouteStrategy} from '../features/tutorial/tutorials-route-reuse-strategy';
import {AppScroller} from '../app-scroller';
import {Subject} from 'rxjs/internal/Subject';
import {HttpErrorResponse} from '@angular/common/http';
import {WINDOW} from '@angular/docs';
+161
View File
@@ -0,0 +1,161 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {contentResolver, flatNavigationData, mapNavigationItemsToRoutes} from '@angular/docs';
import {Route} from '@angular/router';
import {SUB_NAVIGATION_DATA} from './sub-navigation-data';
import {mapApiManifestToRoutes} from '../features/references/helpers/manifest.helper';
import MainComponent from '../main.component';
import {DEFAULT_PAGES, PAGE_PREFIX} from '../core/constants/pages';
import {REDIRECT_ROUTES} from './redirections';
// Docs navigation data contains routes which navigates to /tutorials pages, in
// that case we should load Tutorial component
export const DOCS_ROUTES: Route[] = mapNavigationItemsToRoutes(
flatNavigationData(SUB_NAVIGATION_DATA.docs).filter(
(route) =>
!route.path?.startsWith(PAGE_PREFIX.TUTORIALS) && route.path !== PAGE_PREFIX.PLAYGROUND,
),
{
loadComponent: () => import('../features/docs/docs.component'),
data: {
displaySecondaryNav: true,
},
},
);
const referenceNavigationItems = flatNavigationData(SUB_NAVIGATION_DATA.reference);
const commonReferenceRouteData = {
displaySecondaryNav: true,
};
const referencePageRoutes = mapNavigationItemsToRoutes(
referenceNavigationItems.filter((r) => r.path === DEFAULT_PAGES.REFERENCE),
{
loadComponent: () =>
import('../features/references/api-reference-list/api-reference-list.component'),
data: commonReferenceRouteData,
},
);
const updateGuidePageRoute: Route = {
path: referenceNavigationItems.find((r) => r.path === DEFAULT_PAGES.UPDATE)!.path,
loadComponent: () => import('../features/update/update.component'),
data: commonReferenceRouteData,
};
const cliReferencePageRoutes = mapNavigationItemsToRoutes(
referenceNavigationItems.filter((r) => r.path?.startsWith(`${PAGE_PREFIX.CLI}/`)),
{
loadComponent: () =>
import(
'../features/references/cli-reference-details-page/cli-reference-details-page.component'
),
data: commonReferenceRouteData,
},
).map((route) => ({
...route,
resolve: {
docContent: contentResolver(`${route.path}.html`),
},
}));
const docsReferencePageRoutes = mapNavigationItemsToRoutes(
referenceNavigationItems.filter(
(r) =>
r.path !== DEFAULT_PAGES.REFERENCE &&
r.path !== DEFAULT_PAGES.UPDATE &&
!r.path?.startsWith(`${PAGE_PREFIX.API}/`) &&
!r.path?.startsWith(`${PAGE_PREFIX.CLI}/`),
),
{
loadComponent: () => import('../features/docs/docs.component'),
data: {
...commonReferenceRouteData,
},
},
);
export const REFERENCE_ROUTES = [
...referencePageRoutes,
...docsReferencePageRoutes,
...cliReferencePageRoutes,
];
const tutorialsNavigationItems = flatNavigationData(SUB_NAVIGATION_DATA.tutorials);
const commonTutorialRouteData = {
hideFooter: true,
};
const docsTutorialsRoutes = mapNavigationItemsToRoutes(
tutorialsNavigationItems.filter((route) => route.path === DEFAULT_PAGES.TUTORIALS),
{
loadComponent: () => import('../features/docs/docs.component'),
data: {
...commonTutorialRouteData,
},
},
);
const tutorialComponentRoutes = mapNavigationItemsToRoutes(
tutorialsNavigationItems.filter((route) => route.path !== DEFAULT_PAGES.TUTORIALS),
{
loadComponent: () => import('../features/tutorial/tutorial.component'),
data: {...commonTutorialRouteData},
},
);
export const TUTORIALS_ROUTES = [...docsTutorialsRoutes, ...tutorialComponentRoutes];
// Based on SUB_NAVIGATION_DATA structure, we need to build the routing table
// for content pages.
export const SUB_NAVIGATION_ROUTES: Route[] = [
...DOCS_ROUTES,
...REFERENCE_ROUTES,
...TUTORIALS_ROUTES,
];
const FOOTER_ROUTES: Route[] = mapNavigationItemsToRoutes(
flatNavigationData(SUB_NAVIGATION_DATA.footer),
{loadComponent: () => import('../features/docs/docs.component')},
);
const API_REFERENCE_ROUTES: Route[] = mapApiManifestToRoutes();
export const routes: Route[] = [
{
path: '',
component: MainComponent,
children: [
{
path: '',
loadComponent: () => import('../features/home/home.component'),
data: {label: 'Home'},
},
{
path: PAGE_PREFIX.DOCS,
redirectTo: DEFAULT_PAGES.DOCS,
},
{
path: PAGE_PREFIX.REFERENCE,
redirectTo: DEFAULT_PAGES.REFERENCE,
},
{
path: PAGE_PREFIX.PLAYGROUND,
loadComponent: () => import('../features/playground/playground.component'),
data: {...commonTutorialRouteData, label: 'Playground'},
},
...SUB_NAVIGATION_ROUTES,
...API_REFERENCE_ROUTES,
...FOOTER_ROUTES,
updateGuidePageRoute,
...REDIRECT_ROUTES,
],
},
// Error page
{
path: '**',
loadComponent: () => import('../features/docs/docs.component'),
resolve: {'docContent': contentResolver('error')},
},
];
@@ -10,15 +10,15 @@ import {isDevMode} from '@angular/core';
import {NavigationItem} from '@angular/docs';
// These 2 imports are expected to be red because they are generated a build time
import FIRST_APP_TUTORIAL_NAV_DATA from '../../src/assets/tutorials/first-app/routes.json';
import LEARN_ANGULAR_TUTORIAL_NAV_DATA from '../../src/assets/tutorials/learn-angular/routes.json';
import DEFERRABLE_VIEWS_TUTORIAL_NAV_DATA from '../../src/assets/tutorials/deferrable-views/routes.json';
import SIGNALS_TUTORIAL_NAV_DATA from '../../src/assets/tutorials/signals/routes.json';
import ERRORS_NAV_DATA from '../../src/assets/content/reference/errors/routes.json';
import EXT_DIAGNOSTICS_NAV_DATA from '../../src/assets/content/reference/extended-diagnostics/routes.json';
import FIRST_APP_TUTORIAL_NAV_DATA from '../../../src/assets/tutorials/first-app/routes.json';
import LEARN_ANGULAR_TUTORIAL_NAV_DATA from '../../../src/assets/tutorials/learn-angular/routes.json';
import DEFERRABLE_VIEWS_TUTORIAL_NAV_DATA from '../../../src/assets/tutorials/deferrable-views/routes.json';
import SIGNALS_TUTORIAL_NAV_DATA from '../../../src/assets/tutorials/signals/routes.json';
import ERRORS_NAV_DATA from '../../../src/assets/content/reference/errors/routes.json';
import EXT_DIAGNOSTICS_NAV_DATA from '../../../src/assets/content/reference/extended-diagnostics/routes.json';
import {getApiNavigationItems} from './features/references/helpers/manifest.helper';
import {DEFAULT_PAGES} from './core/constants/pages';
import {getApiNavigationItems} from '../features/references/helpers/manifest.helper';
import {DEFAULT_PAGES} from '../core/constants/pages';
interface SubNavigationData {
docs: NavigationItem[];