Website: update 404 page (#47726)

Changes:
- Added api/responses/notFound.js, an updated version of the notFound
response built into Sails that sets a `hideFooter` page local variable
to hide the website footer on the 404 page.
- Updated the styles and layout of the 404 page to match the latest
wireframes.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Release Notes

* **New Features**
* Completely redesigned the 404 error page with refreshed content and a
more modern layout.
* Added new visual styling, including animated interactive elements on
the 404 page.

* **Bug Fixes**
* Improved 404 response handling to consistently return the correct
status for JSON requests and render the 404 page when available.
* Ensures the 404 page can render cleanly even if view rendering fails,
and hides the footer for a cleaner error-page presentation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Eric
2026-06-18 18:34:28 +09:00
committed by GitHub
parent c36cd671e1
commit 0579699ae0
5 changed files with 158 additions and 8 deletions
+62
View File
@@ -0,0 +1,62 @@
/**
* Module dependencies
*/
// n/a
/**
* 404 (Not Found) Handler
*
* Usage:
* return res.notFound();
* return res.notFound(err);
* return res.notFound(err, 'some/specific/notfound/view');
*
* e.g.:
* ```
* return res.notFound();
* ```
*
* NOTE:
* If a request doesn't match any explicit routes (i.e. `config/routes.js`)
* or route blueprints (i.e. "shadow routes", Sails will call `res.notFound()`
* automatically.
*/
module.exports = function notFound () {
// Get access to `req` and `res`
var req = this.req;
var res = this.res;
// Get access to `sails`
var sails = req._sails;
// Set status code
res.status(404);
// If the request wants JSON, send back the appropriate status code.
if (req.wantsJSON || !res.view) {
return res.sendStatus(404);
}
return res.view('404', { hideFooter: true }, (err, html)=> {
// If a view error occured, fall back to JSON.
if (err) {
//
// Additionally:
// • If the view was missing, ignore the error but provide a verbose log.
if (err.code === 'E_VIEW_FAILED') {
sails.log.verbose('res.notFound() :: Could not locate view for error page (sending text instead). Details: ', err);
}
// Otherwise, if this was a more serious error, log to the console with the details.
else {
sails.log.warn('res.notFound() :: When attempting to render error page view, an error occured (sending text instead). Details: ', err);
}
return res.sendStatus(404);
}
return res.send(html);
});
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

+76 -1
View File
@@ -1,5 +1,80 @@
[id='404'] {
background: linear-gradient(180deg, #FFF 45%, #E1F1F1 100%);
min-height: calc(~'100vh - 80px');
h2 {
.section-heading();
margin-bottom: 8px;
}
//…
p {
.body-l();
margin-bottom: 8px;
}
[purpose='page-container'] {
padding-left: 24px;
padding-right: 24px;
padding-bottom: 64px;
padding-top: 64px;
margin-left: auto;
margin-right: auto;
}
[purpose='page-content'] {
max-width: 1072px;
display: flex;
flex-direction: column;
align-items: center;
margin-left: auto;
margin-right: auto;
text-align: center;
}
[purpose='404-image'] {
max-width: 774px;
img {
width: 100%;
aspect-ratio: 43 / 27;
}
}
[purpose='animated-arrow-button'] {
width: fit-content;
display: flex;
align-items: center;
padding: 6px 0px;
text-decoration: none;
font-size: 16px;
color: @core-fleet-black;
font-weight: 700;
[purpose='button-text'] {
color: @core-fleet-black;
}
[purpose='animated-arrow'] {
margin-left: 8px;
stroke-width: 2px;
height: 12px;
width: 12px;
fill: none;
stroke: @core-vibrant-green;
}
[purpose='arrow-line'] {
opacity: 0;
transition: opacity 10ms ease-out;
}
[purpose='chevron'] {
transition: transform 100ms ease-out;
}
&:hover {
text-decoration: none;
[purpose='button-text'] {
color: @core-fleet-black;
}
[purpose='arrow-line'] {
opacity: 1;
transition: opacity 150ms ease-out;
}
[purpose='chevron'] {
transform: translateX(5px);
}
}
}
}
+16 -6
View File
@@ -1,10 +1,20 @@
<div id="404">
<div style="max-width: 650px;" class="container text-center pt-5 pb-5">
<h1 class="display-1 mb-3">404</h1>
<hr/>
<h2>The page you seek doesn't exist.</h2>
<div>
<p>Think you're seeing this message in error?<br class="d-none d-sm-inline" /><span class="d-inline d-sm-none">&nbsp;</span>Please <a href="/contact?sendMessage">let us know.</a></p>
<div purpose="page-container">
<div purpose="page-content">
<div purpose="404-image">
<img alt="404" src="/images/404-774x486@2x.png">
</div>
<h2>404: We cant find that page!</h2>
<p>The page you are looking for has either moved, or doesnt exist.</p>
<div>
<a purpose="animated-arrow-button" href="/support" no-underline>
Get help with Fleet
<svg purpose="animated-arrow" xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
<path purpose="arrow-line" d="M1 6H9" stroke-width="2" stroke-linecap="round"/>
<path purpose="chevron" d="M1.35712 1L5.64283 6L1.35712 11" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</a>
</div>
</div>
</div>
</div>
+4 -1
View File
@@ -7,6 +7,7 @@
var currentSection;
var hideHeaderLinks;// Hides the header navigation links.
var hideFooterLinks;// Hides footer links, reduces the height of the footer to 60px;
var hideFooter;// Hides the footer.
var showAdminLinks;// Shows links to admin pages to admin users.
var showConfigurationProfileLayout;
var disableChatbotAndIndexing;// Disables the chatbot and adds a noindex meta tag. Used on pages linked to from Fleet.
@@ -162,7 +163,7 @@
<!--STYLES END-->
</head>
<body>
<div purpose="page-wrap" class="<%= hideFooterLinks ? 'reduced-footer-links' : showConfigurationProfileLayout ? 'header-hidden' : '' %> collapse" id="navbarToggleExternalContent">
<div purpose="page-wrap" class="<%= hideFooterLinks ? 'reduced-footer-links' : (showConfigurationProfileLayout || hideFooter) ? 'header-hidden' : '' %> collapse" id="navbarToggleExternalContent">
<%// Page header%>
<% if(!showConfigurationProfileLayout) {%>
<div class="header" purpose="header-container" hide-when-scrolled data-nosnippet>
@@ -758,6 +759,7 @@
<% } %>
<%- body %>
<% if(!hideFooter) {%>
<% if(!showConfigurationProfileLayout) {%>
<%/* Note: footer is hidden until the page is loaded. See «script» tag at the bottom of this file. */%>
<% if(!hideFooterLinks) { %>
@@ -881,6 +883,7 @@
</div>
<% } %>
<% } %>
<% } %>
</div>
<% /*
Client-side JavaScript