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:
Joe 2022-06-22 04:35:46 +08:00 committed by GitHub
parent 624c684d51
commit e82a2ce9ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 209 additions and 2 deletions

View File

@ -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;

View File

@ -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: "...";
}
}

View File

@ -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

View File

@ -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 %>

View File

@ -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" %>

View File

@ -3691,6 +3691,8 @@ en:
create_post: "Reply / See"
readonly: "See"
preloader_text: "Loading"
lightbox:
download: "download"
open: "original image"

View File

@ -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."
@ -2422,7 +2424,7 @@ en:
google_oauth2_hd_groups: "You must first set 'google oauth2 hd' before enabling this setting."
search_tokenize_chinese_enabled: "You must disable 'search_tokenize_chinese' before enabling this setting."
search_tokenize_japanese_enabled: "You must disable 'search_tokenize_japanese' before enabling this setting."
discourse_connect_cannot_be_enabled_if_second_factor_enforced: "You cannot enable DiscourseConnect if 2FA is enforced."
discourse_connect_cannot_be_enabled_if_second_factor_enforced: "You cannot enable DiscourseConnect if 2FA is enforced."
placeholder:
discourse_connect_provider_secrets:

View File

@ -2424,6 +2424,10 @@ uncategorized:
default: true
hidden: true
splash_screen:
default: false
hidden: true
suggest_weekends_in_date_pickers:
client: true
default: true

View File

@ -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

View File

@ -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

View File

@ -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