Skip to content

Commit f5abaa3

Browse files
authoredJan 12, 2021
feat: add 404 page (#902)
Sets up a dedicated 404 page, rather than redirecting everything to the front page which doesn't tell the user that their link is incorrect. The design is based on the one from angular.io. I also had to make some adjustments to the routing setup, because everything was being picked up by the `:section` route and we didn't have defined routes for `/cdk` and `/components` to which we link from the top nav.
1 parent 9cf54bc commit f5abaa3

File tree

8 files changed

+147
-21
lines changed

8 files changed

+147
-21
lines changed
 

‎material.angular.io/src/_app-theme.scss

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
@import './app/pages/component-viewer/component-viewer-theme';
66
@import './app/pages/guide-list/guide-list-theme';
77
@import './app/pages/homepage/homepage-theme';
8+
@import './app/pages/not-found/not-found-theme';
89
@import './app/shared/carousel/carousel-theme';
910
@import './app/shared/example-viewer/example-viewer-theme';
1011
@import './app/shared/footer/footer-theme';
@@ -56,6 +57,7 @@
5657
@include footer-theme($theme);
5758
@include guide-list-theme($theme);
5859
@include home-page-theme($theme);
60+
@include not-found-theme($theme);
5961
@include nav-bar-theme($theme);
6062
@include table-of-contents-theme($theme);
6163
}

‎material.angular.io/src/app/pages/component-sidenav/component-sidenav.ts

+18-19
Original file line numberDiff line numberDiff line change
@@ -118,32 +118,31 @@ export class ComponentNav {
118118
constructor(public docItems: DocumentationItems) {}
119119
}
120120

121-
const routes: Routes = [ {
122-
path : '',
123-
component : ComponentSidenav,
124-
children : [
125-
{path : '', redirectTo : 'categories', pathMatch : 'full'},
126-
{path : 'component/:id', redirectTo : ':id', pathMatch : 'full'},
127-
{path : 'category/:id', redirectTo : '/categories/:id', pathMatch : 'full'},
121+
const routes: Routes = [{
122+
path: '',
123+
component: ComponentSidenav,
124+
children: [
125+
{path: 'component/:id', redirectTo: ':id', pathMatch: 'full'},
126+
{path: 'category/:id', redirectTo: '/categories/:id', pathMatch: 'full'},
128127
{
129-
path : 'categories',
130-
children : [
131-
{path : '', component : ComponentCategoryList},
128+
path: 'categories',
129+
children: [
130+
{path: '', component: ComponentCategoryList},
132131
],
133132
},
134133
{
135-
path : ':id',
136-
component : ComponentViewer,
137-
children : [
138-
{path : '', redirectTo : 'overview', pathMatch : 'full'},
139-
{path : 'overview', component : ComponentOverview, pathMatch : 'full'},
140-
{path : 'api', component : ComponentApi, pathMatch : 'full'},
141-
{path : 'examples', component : ComponentExamples, pathMatch : 'full'},
142-
{path : '**', redirectTo : 'overview'},
134+
path: ':id',
135+
component: ComponentViewer,
136+
children: [
137+
{path: '', redirectTo: 'overview', pathMatch: 'full'},
138+
{path: 'overview', component: ComponentOverview, pathMatch: 'full'},
139+
{path: 'api', component: ComponentApi, pathMatch: 'full'},
140+
{path: 'examples', component: ComponentExamples, pathMatch: 'full'}
143141
],
144142
},
143+
{path: '**', redirectTo: '/404'}
145144
]
146-
} ];
145+
}];
147146

148147
@NgModule({
149148
imports: [
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
@mixin not-found-theme($theme) {
2+
$primary: map-get($theme, primary);
3+
$foreground: map-get($theme, foreground);
4+
$background: map-get($theme, background);
5+
$frown-color: mat-color($background, background);
6+
$shield-color: mat-color($primary);
7+
8+
app-not-found {
9+
color: mat-color($foreground, text);
10+
11+
.shield-left {
12+
fill: $shield-color;
13+
}
14+
15+
.shield-right {
16+
fill: darken($shield-color, 10%);
17+
}
18+
19+
.eye {
20+
fill: $frown-color;
21+
}
22+
23+
.frown {
24+
stroke: $frown-color;
25+
}
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './not-found';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<main>
2+
<div class="wrapper">
3+
<svg
4+
version="1.1"
5+
xmlns="http://www.w3.org/2000/svg"
6+
xmlns:xlink="http://www.w3.org/1999/xlink"
7+
viewBox="0 0 200 200"
8+
xml:space="preserve">
9+
<path class="shield-left" d="M5.7,33.2L98.8,0l95.5,32.6l-15.4,123.1L98.8,200L20,156.3L5.7,33.2z"/>
10+
<path class="shield-right" d="M194.3,32.6L98.8,0v200l80.1-44.3L194.3,32.6L194.3,32.6z"/>
11+
<circle class="eye" cx="61.7" cy="80" r="10.7"/>
12+
<circle class="eye" cx="138.3" cy="80" r="10.7"/>
13+
<path
14+
class="frown"
15+
stroke-width="10"
16+
stroke-linecap="round"
17+
fill="none"
18+
d="M138,130.6c0,0-33.5-42.5-76,0"/>
19+
</svg>
20+
21+
<div>
22+
<h1>Page Not Found</h1>
23+
<p>We're sorry. The page you are looking for cannot be found.</p>
24+
<a routerLink="/" mat-raised-button color="primary">Go Home</a>
25+
<a routerLink="/guides" mat-raised-button>Read Guides</a>
26+
</div>
27+
</div>
28+
</main>
29+
30+
<app-footer></app-footer>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
$vertical-spacing: 64px;
2+
$horizontal-spacing: 32px;
3+
4+
main {
5+
min-height: 100vh;
6+
font-size: 1.25rem;
7+
}
8+
9+
.wrapper {
10+
display: flex;
11+
align-items: center;
12+
justify-content: center;
13+
padding: $vertical-spacing;
14+
}
15+
16+
svg {
17+
height: 300px;
18+
max-width: 100%;
19+
margin-right: $horizontal-spacing;
20+
}
21+
22+
a + a {
23+
margin-left: 16px;
24+
}
25+
26+
@media (max-width: 720px) {
27+
.wrapper {
28+
flex-direction: column;
29+
}
30+
31+
svg {
32+
height: auto;
33+
max-height: 300px;
34+
margin-right: 0;
35+
margin-bottom: $vertical-spacing;
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import {Component, NgModule} from '@angular/core';
2+
import {MatButtonModule} from '@angular/material/button';
3+
import {FooterModule} from '../../shared/footer/footer';
4+
import {RouterModule, Routes} from '@angular/router';
5+
6+
@Component({
7+
selector: 'app-not-found',
8+
templateUrl: './not-found.html',
9+
styleUrls: ['./not-found.scss']
10+
})
11+
export class NotFound {
12+
}
13+
14+
const routes: Routes = [{path: '', component: NotFound}];
15+
16+
@NgModule({
17+
imports: [MatButtonModule, FooterModule, RouterModule.forChild(routes)],
18+
exports: [NotFound],
19+
declarations: [NotFound]
20+
})
21+
export class NotFoundModule {
22+
}

‎material.angular.io/src/app/routes.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@ import {CanActivateComponentSidenav} from './pages/component-sidenav/component-s
33

44
export const MATERIAL_DOCS_ROUTES: Routes = [
55
{
6-
path: '', pathMatch: 'full',
6+
path: '',
7+
pathMatch: 'full',
78
loadChildren: () => import('./pages/homepage').then(m => m.HomepageModule)
89
},
910
{path: 'categories', redirectTo: '/components/categories'},
11+
{path: 'cdk', pathMatch: 'full', redirectTo: '/cdk/categories'},
12+
{path: 'components', pathMatch: 'full', redirectTo: '/components/categories'},
1013
{
1114
path: 'guides',
1215
loadChildren: () => import('./pages/guide-list').then(m => m.GuideListModule)
@@ -18,11 +21,16 @@ export const MATERIAL_DOCS_ROUTES: Routes = [
1821
path: 'guide/:id',
1922
loadChildren: () => import('./pages/guide-viewer').then(m => m.GuideViewerModule)
2023
},
24+
// Needs to be defined before `:section` so it gets picked first when redirecting a missing page.
25+
{
26+
path: '404',
27+
loadChildren: () => import('./pages/not-found').then(m => m.NotFoundModule)
28+
},
2129
{
2230
path: ':section',
2331
canActivate: [CanActivateComponentSidenav],
2432
loadChildren: () =>
2533
import('./pages/component-sidenav/component-sidenav').then(m => m.ComponentSidenavModule)
2634
},
27-
{path: '**', redirectTo: ''},
35+
{path: '**', redirectTo: '/404'},
2836
];

0 commit comments

Comments
 (0)
Please sign in to comment.