Mattias Bodlund 3 weeks ago
parent
commit
101c9a7f69
7 changed files with 65 additions and 4 deletions
  1. +25
    -0
      app/assets/stylesheets/application.css
  2. +21
    -1
      app/javascript/modal_controller.js
  3. +2
    -1
      app/views/game/_facts_content.html.erb
  4. +11
    -0
      app/views/game/_preload_intro.html.erb
  5. +2
    -0
      app/views/game/facts.html.erb
  6. +3
    -1
      app/views/game/start.html.erb
  7. +1
    -1
      app/views/game/start.turbo_stream.erb

+ 25
- 0
app/assets/stylesheets/application.css View File

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


+ 21
- 1
app/javascript/modal_controller.js View File

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


+ 2
- 1
app/views/game/_facts_content.html.erb View File

@ -30,6 +30,7 @@
</div>
<article>
<%= 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" } %>
</article>
</div>

+ 11
- 0
app/views/game/_preload_intro.html.erb View File

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

+ 2
- 0
app/views/game/facts.html.erb View File

@ -1,3 +1,5 @@
<%- content_for :title, node_title(@node) %>
<%= render "facts_content" %>
<%= render partial: "preload_intro" %>

+ 3
- 1
app/views/game/start.html.erb View File

@ -23,4 +23,6 @@
<%= svg "ico-clock" %>
<%= tag.span t("game.play_time") %>
<% end %>
</article>
</article>
<%= render partial: "preload_intro" %>

+ 1
- 1
app/views/game/start.turbo_stream.erb View File

@ -1,4 +1,4 @@
<%= turbo_stream.append "game" do %>
<%= turbo_stream.append "page" do %>
<dialog class="facts-modal"
data-controller="modal"
data-modal-target="dialog"


Loading…
Cancel
Save