UX: Introduces a splash screen behind a hidden site setting (#17094)
This PR introduces a new hidden site setting that allows admins to display a splash screen while site assets load.
The splash screen can be enabled via the `splash_screen` hidden site setting.
This is what the splash screen currently looks like
5ceb72f085
.mp4
Once site assets load, the splash screen is automatically removed.
To control the loading text that shows in the splash screen, you can change the preloader_text translation string in admin > customize > text
This commit is contained in:
parent
624c684d51
commit
e82a2ce9ae
|
@ -52,6 +52,9 @@ const Discourse = Application.extend({
|
|||
start() {
|
||||
document.querySelector("noscript")?.remove();
|
||||
|
||||
// The app booted. Remove the splash screen
|
||||
document.querySelector("#d-splash")?.remove();
|
||||
|
||||
if (Error.stackTraceLimit) {
|
||||
// We need Errors to have full stack traces for `lib/source-identifier`
|
||||
Error.stackTraceLimit = Infinity;
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
html {
|
||||
background: var(--secondary);
|
||||
// needed because this sheet loads early and we want no scroll bars until
|
||||
// the splash is removed.
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
#d-splash {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
position: relative;
|
||||
backface-visibility: hidden;
|
||||
|
||||
.preloader-image {
|
||||
max-width: 100%;
|
||||
height: 100vh;
|
||||
object-fit: none;
|
||||
}
|
||||
|
||||
.preloader-text {
|
||||
padding-top: 5em;
|
||||
position: absolute;
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
place-items: center;
|
||||
|
||||
&:after {
|
||||
animation: loading-text 3s infinite;
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 5em;
|
||||
margin: 0 0.1em;
|
||||
left: 100%;
|
||||
// TODO: this needs R2 RTL magic
|
||||
.rtl & {
|
||||
left: 0;
|
||||
right: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes loading-text {
|
||||
0% {
|
||||
content: "";
|
||||
}
|
||||
|
||||
25% {
|
||||
content: ".";
|
||||
}
|
||||
|
||||
50% {
|
||||
content: "..";
|
||||
}
|
||||
|
||||
75% {
|
||||
content: "...";
|
||||
}
|
||||
}
|
|
@ -429,6 +429,11 @@ module ApplicationHelper
|
|||
", app-argument=discourse://new?siteUrl=#{Discourse.base_url}" : ""
|
||||
end
|
||||
|
||||
def include_splash_screen?
|
||||
# A bit basic for now but will be expanded later
|
||||
SiteSetting.splash_screen
|
||||
end
|
||||
|
||||
def allow_plugins?
|
||||
!request.env[ApplicationController::NO_PLUGINS]
|
||||
end
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<%- unless customization_disabled? %>
|
||||
<section id="d-splash">
|
||||
<%= discourse_stylesheet_link_tag 'd_splash', theme_id: nil %>
|
||||
|
||||
<img
|
||||
class="preloader-image"
|
||||
src="/images/preloader.svg"
|
||||
alt="<%=SiteSetting.title%>"
|
||||
>
|
||||
|
||||
<div class="preloader-text">
|
||||
<span>
|
||||
<%= I18n.t("js.preloader_text") %>
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
<%- end %>
|
|
@ -9,6 +9,10 @@
|
|||
<%= render partial: "layouts/head" %>
|
||||
<%= discourse_csrf_tags %>
|
||||
|
||||
<%- if include_splash_screen? %>
|
||||
<link rel="preload" as="image" href="/images/preloader.svg">
|
||||
<%- end %>
|
||||
|
||||
<%- if SiteSetting.enable_escaped_fragments? %>
|
||||
<meta name="fragment" content="!">
|
||||
<%- end %>
|
||||
|
@ -70,6 +74,10 @@
|
|||
</head>
|
||||
|
||||
<body class="<%= body_classes %>">
|
||||
<%- if include_splash_screen? %>
|
||||
<%= render partial: "common/discourse_splash" %>
|
||||
<%- end %>
|
||||
|
||||
<discourse-assets>
|
||||
<discourse-assets-stylesheets>
|
||||
<%= render partial: "common/discourse_stylesheet" %>
|
||||
|
|
|
@ -3691,6 +3691,8 @@ en:
|
|||
create_post: "Reply / See"
|
||||
readonly: "See"
|
||||
|
||||
preloader_text: "Loading"
|
||||
|
||||
lightbox:
|
||||
download: "download"
|
||||
open: "original image"
|
||||
|
|
|
@ -2369,6 +2369,8 @@ en:
|
|||
use_name_for_username_suggestions: "Use a user's full name when suggesting usernames."
|
||||
suggest_weekends_in_date_pickers: "Include weekends (Saturday and Sunday) in date picker suggestions (disable this if you use Discourse only on weekdays, Monday through Friday)."
|
||||
|
||||
splash_screen: "Displays a temporary loading screen while site assets load"
|
||||
|
||||
errors:
|
||||
invalid_css_color: "Invalid color. Enter a color name or hex value."
|
||||
invalid_email: "Invalid email address."
|
||||
|
|
|
@ -2424,6 +2424,10 @@ uncategorized:
|
|||
default: true
|
||||
hidden: true
|
||||
|
||||
splash_screen:
|
||||
default: false
|
||||
hidden: true
|
||||
|
||||
suggest_weekends_in_date_pickers:
|
||||
client: true
|
||||
default: true
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
<svg
|
||||
version="1.1"
|
||||
height="2000"
|
||||
width="2000"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<style>
|
||||
:root {
|
||||
/* these need to be injected dynamicly to match theme colors */
|
||||
--primary: #222222;
|
||||
--secondary: #ffffff;
|
||||
--tertiary: #f15c21;
|
||||
--highlight: #f0ea88;
|
||||
--quaternary: #65ccff;
|
||||
--success: #009900;
|
||||
}
|
||||
|
||||
/* these styles need to live here because the SVG has a different scope */
|
||||
.dots {
|
||||
animation-name: loader;
|
||||
animation-timing-function: ease-in-out;
|
||||
animation-duration: 3s;
|
||||
animation-iteration-count: infinite;
|
||||
stroke: #fff;
|
||||
stroke-width: 0.5px;
|
||||
}
|
||||
|
||||
.dots:first-child {
|
||||
fill: var(--tertiary);
|
||||
animation-delay: 1.4s;
|
||||
}
|
||||
|
||||
.dots:nth-child(2) {
|
||||
fill: var(--tertiary);
|
||||
animation-delay: 1.3s;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.dots:nth-child(3) {
|
||||
fill: var(--highlight);
|
||||
animation-delay: 1.2s;
|
||||
}
|
||||
|
||||
.dots:nth-child(4) {
|
||||
fill: var(--quaternary);
|
||||
animation-delay: 1.1s;
|
||||
}
|
||||
|
||||
.dots:nth-child(5) {
|
||||
fill: var(--quaternary);
|
||||
animation-delay: 1s;
|
||||
}
|
||||
|
||||
.container {
|
||||
transform: translateX(-125px);
|
||||
}
|
||||
|
||||
@keyframes loader {
|
||||
15% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
45% {
|
||||
transform: translatex(calc(250px));
|
||||
}
|
||||
|
||||
65% {
|
||||
transform: translatex(calc(250px));
|
||||
}
|
||||
|
||||
95% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<g class="container">
|
||||
<circle class="dots" cy="50%" r="10" cx="50vw"></circle>
|
||||
<circle class="dots" cy="50%" r="10" cx="50vw"></circle>
|
||||
<circle class="dots" cy="50%" r="10" cx="50vw"></circle>
|
||||
<circle class="dots" cy="50%" r="10" cx="50vw"></circle>
|
||||
<circle class="dots" cy="50%" r="10" cx="50vw"></circle>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
|
@ -11,7 +11,7 @@ describe Stylesheet::Compiler do
|
|||
|
||||
it "can compile '#{path}' css" do
|
||||
css, _map = Stylesheet::Compiler.compile_asset(path)
|
||||
expect(css.length).to be > 1000
|
||||
expect(css.length).to be > 500
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -529,6 +529,28 @@ RSpec.describe ApplicationController do
|
|||
end
|
||||
end
|
||||
|
||||
describe "splash_screen" do
|
||||
let(:admin) { Fabricate(:admin) }
|
||||
|
||||
before do
|
||||
admin
|
||||
end
|
||||
|
||||
it 'adds a preloader splash screen when enabled' do
|
||||
get '/'
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.body).not_to include("d-splash")
|
||||
|
||||
SiteSetting.splash_screen = true
|
||||
|
||||
get '/'
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.body).to include("d-splash")
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Delegated auth' do
|
||||
let :public_key do
|
||||
<<~TXT
|
||||
|
|
Loading…
Reference in New Issue