From 101c9a7f69807f59390160e158a3a84393d4cd68 Mon Sep 17 00:00:00 2001 From: Mattias Bodlund Date: Wed, 26 Aug 2026 16:13:06 +0200 Subject: [PATCH] na --- app/assets/stylesheets/application.css | 25 +++++++++++++++++++++++++ app/javascript/modal_controller.js | 22 +++++++++++++++++++++- app/views/game/_facts_content.html.erb | 3 ++- app/views/game/_preload_intro.html.erb | 11 +++++++++++ app/views/game/facts.html.erb | 2 ++ app/views/game/start.html.erb | 4 +++- app/views/game/start.turbo_stream.erb | 2 +- 7 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 app/views/game/_preload_intro.html.erb diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index b5089e0..a66480d 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -388,6 +388,22 @@ main, .modal-panel { animation: wave-slide-out var(--dur-fast) var(--ease-in) var(--dur-base) both; } + .facts-modal { + transition: translate var(--dur-base) var(--ease-in); + } + + .facts-modal::backdrop { + transition: background-color var(--dur-base) var(--ease-in); + } + + .facts-modal.is-leaving { + translate: 0 100%; + } + + .facts-modal.is-leaving::backdrop { + background-color: rgba(0, 0, 0, 0); + } + .facts-modal .carousel > li { overflow: clip; } @@ -713,6 +729,15 @@ main, .modal-panel { } } +.preload-media { + position: fixed; + inset: auto auto 0 0; + width: 1px; + height: 1px; + opacity: 0; + pointer-events: none; +} + .hero-container, .carousel, .carousel-frame { flex: 1 1 0; min-height: 0; diff --git a/app/javascript/modal_controller.js b/app/javascript/modal_controller.js index 8ea691a..d869617 100644 --- a/app/javascript/modal_controller.js +++ b/app/javascript/modal_controller.js @@ -22,6 +22,22 @@ export default class extends Controller { this.element.remove() } + // The panel sits above the game frame rather than inside it, so the next + // screen renders behind it. Once it is there, the panel drops off the bottom + // and leaves the intro playing underneath. + leave() { + if (this.leaving) return + + this.leaving = true + document.addEventListener("turbo:frame-render", this.#slideAway, { once: true }) + } + + #slideAway = async () => { + this.element.classList.add("is-leaving") + await this.#settle(this.element, "transitionend") + this.close() + } + // The screen underneath may still be animating out. The wave is the last // thing to leave, so waiting on it holds the modal until the exit is done. async #openWhenSettled() { @@ -89,7 +105,11 @@ export default class extends Controller { ? parseFloat(style.animationDuration) + parseFloat(style.animationDelay) : parseFloat(style.transitionDuration) + parseFloat(style.transitionDelay) - const finish = () => { + // Descendants and ::backdrop send their own events up through the same + // element, and either would settle this early. + const finish = (event) => { + if (event && (event.target !== element || event.pseudoElement)) return + element.removeEventListener(eventName, finish) clearTimeout(timer) resolve() diff --git a/app/views/game/_facts_content.html.erb b/app/views/game/_facts_content.html.erb index 46ddf2a..0ff1e16 100644 --- a/app/views/game/_facts_content.html.erb +++ b/app/views/game/_facts_content.html.erb @@ -30,6 +30,7 @@
- <%= link_to tag.span(t("game.got_it_lets_get_started")), { action: "intro" }, class: "cta" %> + <%= link_to tag.span(t("game.got_it_lets_get_started")), { action: "intro" }, class: "cta", + data: { turbo_frame: "game", action: "click->modal#leave" } %>
diff --git a/app/views/game/_preload_intro.html.erb b/app/views/game/_preload_intro.html.erb new file mode 100644 index 0000000..a26b8bf --- /dev/null +++ b/app/views/game/_preload_intro.html.erb @@ -0,0 +1,11 @@ +<% intro_video = root_node&.children&.intro&.first&.attachments&.find { |a| a.asset&.file&.video? } %> + +<% if intro_video %> + <%= video_tag rails_storage_proxy_path(intro_video.asset.file), + preload: "auto", + muted: true, + playsinline: true, + class: "preload-media", + "aria-hidden": true, + tabindex: -1 %> +<% end %> diff --git a/app/views/game/facts.html.erb b/app/views/game/facts.html.erb index a873715..ae69089 100644 --- a/app/views/game/facts.html.erb +++ b/app/views/game/facts.html.erb @@ -1,3 +1,5 @@ <%- content_for :title, node_title(@node) %> <%= render "facts_content" %> + +<%= render partial: "preload_intro" %> diff --git a/app/views/game/start.html.erb b/app/views/game/start.html.erb index 6013805..aefb7de 100644 --- a/app/views/game/start.html.erb +++ b/app/views/game/start.html.erb @@ -23,4 +23,6 @@ <%= svg "ico-clock" %> <%= tag.span t("game.play_time") %> <% end %> - \ No newline at end of file + + +<%= render partial: "preload_intro" %> diff --git a/app/views/game/start.turbo_stream.erb b/app/views/game/start.turbo_stream.erb index 1411237..0dec844 100644 --- a/app/views/game/start.turbo_stream.erb +++ b/app/views/game/start.turbo_stream.erb @@ -1,4 +1,4 @@ -<%= turbo_stream.append "game" do %> +<%= turbo_stream.append "page" do %>