Add embed focus mode and adjust layouts

This commit is contained in:
Alex Lion
2026-07-16 22:03:27 +02:00
parent faccbfa5e7
commit 5bbff7701c
5 changed files with 33 additions and 14 deletions

View File

@@ -126,7 +126,7 @@
} }
@media (max-height: 500px) { @media (max-height: 500px) {
#focus-slot { #focus-slot:not([data-interaction-mode="true"]) {
height: 7rem; height: 7rem;
min-height: 7rem; min-height: 7rem;
} }

View File

@@ -3,9 +3,12 @@ defmodule ClaperWeb.EventLive.EmbedComponent do
@impl true @impl true
def render(assigns) do def render(assigns) do
assigns = assign_new(assigns, :focus_mode, fn -> false end)
~H""" ~H"""
<div class="font-display"> <div class="font-display">
<div <div
:if={!@focus_mode}
id="collapsed-embed" id="collapsed-embed"
class="mx-auto hidden w-max rounded-full bg-gray-900 px-5 py-3 shadow-xl ring-1 ring-white/10" class="mx-auto hidden w-max rounded-full bg-gray-900 px-5 py-3 shadow-xl ring-1 ring-white/10"
> >
@@ -36,10 +39,15 @@ defmodule ClaperWeb.EventLive.EmbedComponent do
</div> </div>
<div <div
id="extended-embed" id="extended-embed"
class="w-full rounded-2xl bg-gray-900 p-4 text-gray-100 shadow-2xl ring-1 ring-white/10" class={[
"w-full rounded-2xl bg-gray-900 p-4 text-gray-100",
@focus_mode && "shadow-none ring-0",
!@focus_mode && "shadow-2xl ring-1 ring-white/10"
]}
> >
<div class="relative pr-8"> <div class="relative pr-8">
<button <button
:if={!@focus_mode}
id="embed-pane" id="embed-pane"
type="button" type="button"
aria-label={gettext("Close")} aria-label={gettext("Close")}

View File

@@ -76,7 +76,7 @@ defmodule ClaperWeb.EventLive.PollComponent do
<% end %> <% end %>
</div> </div>
<div> <div>
<div class="flex max-h-[500px] flex-col gap-2 overflow-y-auto"> <div id="poll-options" class="flex flex-col gap-2">
<%= if (length @poll.poll_opts) > 0 do %> <%= if (length @poll.poll_opts) > 0 do %>
<%= for {opt, idx} <- Enum.with_index(@poll.poll_opts) do %> <%= for {opt, idx} <- Enum.with_index(@poll.poll_opts) do %>
<%= if (length @current_poll_vote) > 0 do %> <%= if (length @current_poll_vote) > 0 do %>

View File

@@ -8,7 +8,8 @@
<% interaction_mode? = <% interaction_mode? =
match?(%Claper.Polls.Poll{}, @current_interaction) || match?(%Claper.Polls.Poll{}, @current_interaction) ||
match?(%Claper.Forms.Form{}, @current_interaction) || match?(%Claper.Forms.Form{}, @current_interaction) ||
match?(%Claper.Quizzes.Quiz{}, @current_interaction) %> match?(%Claper.Quizzes.Quiz{}, @current_interaction) ||
match?(%Claper.Embeds.Embed{attendee_visibility: true}, @current_interaction) %>
<div class="h-[100dvh] overflow-hidden bg-black lg:bg-primary-700"> <div class="h-[100dvh] overflow-hidden bg-black lg:bg-primary-700">
<main <main
id="attendee-room" id="attendee-room"
@@ -131,7 +132,8 @@
data-interaction-mode={to_string(interaction_mode?)} data-interaction-mode={to_string(interaction_mode?)}
class={[ class={[
"relative z-10 min-h-0 overflow-hidden border-y border-white/10 bg-gray-950 transition-[height] duration-300", "relative z-10 min-h-0 overflow-hidden border-y border-white/10 bg-gray-950 transition-[height] duration-300",
focus_content? && "h-[40dvh] min-h-40 max-h-[26rem]", focus_content? && interaction_mode? && "h-auto max-h-[40dvh]",
focus_content? && !interaction_mode? && "h-[40dvh] min-h-40 max-h-[26rem]",
!focus_content? && "h-12" !focus_content? && "h-12"
]} ]}
> >
@@ -144,7 +146,7 @@
<%= case @current_interaction do %> <%= case @current_interaction do %>
<% %Claper.Polls.Poll{} -> %> <% %Claper.Polls.Poll{} -> %>
<div class="h-full overflow-y-auto overscroll-contain p-3"> <div class="max-h-[40dvh] overflow-y-auto overscroll-contain p-3">
<.live_component <.live_component
module={ClaperWeb.EventLive.PollComponent} module={ClaperWeb.EventLive.PollComponent}
id={"#{@current_interaction.id}-poll"} id={"#{@current_interaction.id}-poll"}
@@ -159,7 +161,7 @@
/> />
</div> </div>
<% %Claper.Forms.Form{} -> %> <% %Claper.Forms.Form{} -> %>
<div class="h-full overflow-y-auto overscroll-contain p-3"> <div class="max-h-[40dvh] overflow-y-auto overscroll-contain p-3">
<.live_component <.live_component
module={ClaperWeb.EventLive.FormComponent} module={ClaperWeb.EventLive.FormComponent}
id={"#{@current_interaction.id}-form"} id={"#{@current_interaction.id}-form"}
@@ -172,7 +174,7 @@
/> />
</div> </div>
<% %Claper.Quizzes.Quiz{} -> %> <% %Claper.Quizzes.Quiz{} -> %>
<div class="h-full overflow-y-auto overscroll-contain p-3"> <div class="max-h-[40dvh] overflow-y-auto overscroll-contain p-3">
<.live_component <.live_component
module={ClaperWeb.EventLive.QuizComponent} module={ClaperWeb.EventLive.QuizComponent}
id={"#{@current_interaction.id}-quiz"} id={"#{@current_interaction.id}-quiz"}
@@ -188,13 +190,12 @@
/> />
</div> </div>
<% %Claper.Embeds.Embed{attendee_visibility: true} -> %> <% %Claper.Embeds.Embed{attendee_visibility: true} -> %>
<div id="focus-media" class="relative h-full w-full bg-black"> <div class="max-h-[40dvh] overflow-y-auto overscroll-contain p-3">
<.live_component <.live_component
id={"focus-embed-#{@current_interaction.id}"} id={"#{@current_interaction.id}-embed"}
module={ClaperWeb.EventLive.EmbedIframeComponent} module={ClaperWeb.EventLive.EmbedComponent}
provider={@current_interaction.provider} embed={@current_interaction}
content={@current_interaction.content} focus_mode
title={@current_interaction.title}
/> />
</div> </div>
<% _ -> %> <% _ -> %>

View File

@@ -40,6 +40,7 @@ defmodule ClaperWeb.EventLive.InteractionComponentsTest do
assert "bg-primary-900/40" in option_classes assert "bg-primary-900/40" in option_classes
assert "py-2" in option_classes assert "py-2" in option_classes
assert "shrink-0" in option_classes assert "shrink-0" in option_classes
refute "overflow-y-auto" in classes(document, "#poll-options")
refute "min-h-11" in option_classes refute "min-h-11" in option_classes
assert Floki.attribute(document, "#poll-opt-0", "aria-pressed") == ["true"] assert Floki.attribute(document, "#poll-opt-0", "aria-pressed") == ["true"]
assert "btn-gradient" in vote_classes assert "btn-gradient" in vote_classes
@@ -284,6 +285,15 @@ defmodule ClaperWeb.EventLive.InteractionComponentsTest do
assert "h-full" in classes(document, "iframe") assert "h-full" in classes(document, "iframe")
assert "w-full" in classes(document, "iframe") assert "w-full" in classes(document, "iframe")
assert Floki.attribute(document, "iframe", "title") == ["Watch the demo"] assert Floki.attribute(document, "iframe", "title") == ["Watch the demo"]
focus_document =
EmbedComponent
|> render_component(id: "focus-embed-component", embed: embed, focus_mode: true)
|> Floki.parse_document!()
assert Floki.find(focus_document, "#collapsed-embed") == []
assert Floki.find(focus_document, "#embed-pane") == []
assert "shadow-none" in classes(focus_document, "#extended-embed")
end end
test "custom web content is not cropped into a video aspect ratio" do test "custom web content is not cropped into a video aspect ratio" do