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 %> + + <%=SiteSetting.title%> + +
+ + <%= 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