diff --git a/app/assets/javascripts/discourse/app/app.js b/app/assets/javascripts/discourse/app/app.js
index 19da3d28362..5d620caf85d 100644
--- a/app/assets/javascripts/discourse/app/app.js
+++ b/app/assets/javascripts/discourse/app/app.js
@@ -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;
diff --git a/app/assets/stylesheets/d_splash.scss b/app/assets/stylesheets/d_splash.scss
new file mode 100644
index 00000000000..c56c915f936
--- /dev/null
+++ b/app/assets/stylesheets/d_splash.scss
@@ -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: "...";
+ }
+}
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 3b2306eae21..de081f8b943 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -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
diff --git a/app/views/common/_discourse_splash.html.erb b/app/views/common/_discourse_splash.html.erb
new file mode 100644
index 00000000000..e48c75e1ef3
--- /dev/null
+++ b/app/views/common/_discourse_splash.html.erb
@@ -0,0 +1,17 @@
+<%- unless customization_disabled? %>
+
+ <%= discourse_stylesheet_link_tag 'd_splash', theme_id: nil %>
+
+
+
+
+
+ <%= I18n.t("js.preloader_text") %>
+
+
+
+<%- end %>
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index f0cef4d66b3..abbca6bb2b3 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -9,6 +9,10 @@
<%= render partial: "layouts/head" %>
<%= discourse_csrf_tags %>
+ <%- if include_splash_screen? %>
+
+ <%- end %>
+
<%- if SiteSetting.enable_escaped_fragments? %>
<%- end %>
@@ -70,6 +74,10 @@
+ <%- if include_splash_screen? %>
+ <%= render partial: "common/discourse_splash" %>
+ <%- end %>
+
<%= render partial: "common/discourse_stylesheet" %>
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index b25a4e1b85d..a18024bd71d 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -3691,6 +3691,8 @@ en:
create_post: "Reply / See"
readonly: "See"
+ preloader_text: "Loading"
+
lightbox:
download: "download"
open: "original image"
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index b20588a37cd..31fd766d6e1 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -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:
diff --git a/config/site_settings.yml b/config/site_settings.yml
index 35a6720a537..577bc780766 100644
--- a/config/site_settings.yml
+++ b/config/site_settings.yml
@@ -2424,6 +2424,10 @@ uncategorized:
default: true
hidden: true
+ splash_screen:
+ default: false
+ hidden: true
+
suggest_weekends_in_date_pickers:
client: true
default: true
diff --git a/public/images/preloader.svg b/public/images/preloader.svg
new file mode 100644
index 00000000000..b2088cee5e4
--- /dev/null
+++ b/public/images/preloader.svg
@@ -0,0 +1,85 @@
+
diff --git a/spec/lib/stylesheet/compiler_spec.rb b/spec/lib/stylesheet/compiler_spec.rb
index ef1a3b5c754..4245bdb377e 100644
--- a/spec/lib/stylesheet/compiler_spec.rb
+++ b/spec/lib/stylesheet/compiler_spec.rb
@@ -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
diff --git a/spec/requests/application_controller_spec.rb b/spec/requests/application_controller_spec.rb
index 0a7c4eb87bc..a3cd36fda7b 100644
--- a/spec/requests/application_controller_spec.rb
+++ b/spec/requests/application_controller_spec.rb
@@ -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