mirror of
https://github.com/algora-io/tv.git
synced 2025-01-15 01:28:30 +02:00
add transcript tab (#4)
* init side panel * reorganize stuff * delete unused components * fix some ids * more fixes * conditionally render transcript tab * reorder some code * delete redundant line * remove unused alias
This commit is contained in:
parent
baa130f942
commit
b7ed13e06f
@ -7,9 +7,9 @@ const init = () => {
|
||||
socket.connect();
|
||||
|
||||
const main = document.querySelector("body");
|
||||
const sidePanel = document.querySelector("#video-side-panel");
|
||||
|
||||
let channel;
|
||||
let chatBox;
|
||||
let chatInput;
|
||||
let chatMessages;
|
||||
let handleSend;
|
||||
@ -20,9 +20,9 @@ const init = () => {
|
||||
chatInput.value = "";
|
||||
chatInput.removeEventListener("keypress", handleSend);
|
||||
}
|
||||
chatBox.classList.add("lg:w-0");
|
||||
chatBox.classList.remove("lg:w-[24rem]");
|
||||
chatBox.classList.remove("lg:flex");
|
||||
sidePanel.classList.add("lg:w-0");
|
||||
sidePanel.classList.remove("lg:w-[24rem]");
|
||||
sidePanel.classList.remove("lg:flex");
|
||||
main.classList.remove("lg:mr-[24rem]");
|
||||
};
|
||||
|
||||
@ -31,15 +31,13 @@ const init = () => {
|
||||
leave(channel);
|
||||
}
|
||||
|
||||
player = player;
|
||||
channel = socket.channel(`room:${id}`, {});
|
||||
chatBox = document.querySelector("#chat-box");
|
||||
chatInput = document.querySelector("#chat-input");
|
||||
chatMessages = document.querySelector("#chat-messages");
|
||||
chatMessages.scrollTop = chatMessages.scrollHeight;
|
||||
chatBox.classList.add("lg:w-[24rem]");
|
||||
chatBox.classList.add("lg:flex");
|
||||
chatBox.classList.remove("lg:w-0");
|
||||
sidePanel.classList.add("lg:w-[24rem]");
|
||||
sidePanel.classList.add("lg:flex");
|
||||
sidePanel.classList.remove("lg:w-0");
|
||||
main.classList.add("lg:mr-[24rem]");
|
||||
|
||||
handleSend = (event) => {
|
||||
|
@ -145,6 +145,10 @@ defmodule Algora.Library do
|
||||
|> Enum.map_join(":", fn count -> String.pad_leading("#{count}", 2, ["0"]) end)
|
||||
end
|
||||
|
||||
def to_hhmmss(duration) when is_float(duration) do
|
||||
to_hhmmss(trunc(duration))
|
||||
end
|
||||
|
||||
def unsubscribe_to_channel(%Channel{} = channel) do
|
||||
Phoenix.PubSub.unsubscribe(@pubsub, topic(channel.user_id))
|
||||
end
|
||||
|
@ -79,7 +79,7 @@ defmodule AlgoraWeb.CoreComponents do
|
||||
id={@id}
|
||||
class="cursor-pointer truncate"
|
||||
phx-click={
|
||||
JS.push("join", value: %{video_id: @video.id}, target: "#chat-box")
|
||||
JS.push("show", value: %{video_id: @video.id}, target: "#side-panel")
|
||||
|> JS.dispatch("js:play_video",
|
||||
to: "#video-player",
|
||||
detail: %{player: %{src: @video.url, type: Library.player_type(@video)}}
|
||||
@ -117,7 +117,7 @@ defmodule AlgoraWeb.CoreComponents do
|
||||
id={@id}
|
||||
class="cursor-pointer truncate"
|
||||
phx-click={
|
||||
JS.push("join", value: %{video_id: @video.id}, target: "#chat-box")
|
||||
JS.push("show", value: %{video_id: @video.id}, target: "#side-panel")
|
||||
|> JS.dispatch("js:play_video",
|
||||
to: "#video-player",
|
||||
detail: %{player: %{src: @video.url, type: Library.player_type(@video)}}
|
||||
|
@ -126,7 +126,9 @@
|
||||
|
||||
<.live_component module={AlgoraWeb.LayoutComponent} id="layout" />
|
||||
|
||||
<%= live_render(@socket, AlgoraWeb.ChatLive, id: "chat", session: %{}, sticky: true) %>
|
||||
<aside id="video-side-panel" class="hidden fixed top-[64px] right-0 w-0 pr-4">
|
||||
<%= live_render(@socket, AlgoraWeb.SidePanelLive, id: "side-panel", session: %{}) %>
|
||||
</aside>
|
||||
<main class="flex-1 relative z-0 overflow-y-auto focus:outline-none">
|
||||
<%= live_render(@socket, AlgoraWeb.PlayerLive, id: "player", session: %{}, sticky: true) %>
|
||||
<%= @inner_content %>
|
||||
|
@ -1,66 +0,0 @@
|
||||
defmodule AlgoraWeb.ChatLive do
|
||||
alias Algora.Chat.Message
|
||||
alias Algora.{Library, Chat}
|
||||
alias Algora.Library.Video
|
||||
use AlgoraWeb, {:live_view, container: {:div, []}}
|
||||
|
||||
on_mount {AlgoraWeb.UserAuth, :current_user}
|
||||
|
||||
defp system_message?(%Message{} = message) do
|
||||
message.sender_handle == "algora"
|
||||
end
|
||||
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<aside id="chat-box" class="hidden fixed top-[64px] right-0 w-0 flex-col pr-4">
|
||||
<div class="p-4 bg-gray-800/40 backdrop-blur-xl rounded-2xl shadow-inner shadow-white/[10%] border border-white/[15%]">
|
||||
<div class="pb-2 text-center text-gray-400 text-xs font-medium uppercase tracking-wide">
|
||||
Chat
|
||||
</div>
|
||||
<div
|
||||
id="chat-messages"
|
||||
class="text-sm break-words flex-1 overflow-y-auto h-[calc(100vh-11rem)]"
|
||||
>
|
||||
<div :for={message <- @messages} id={"message-#{message.id}"}>
|
||||
<span class={"font-semibold #{if(system_message?(message), do: "text-emerald-400", else: "text-indigo-400")}"}>
|
||||
<%= message.sender_handle %>:
|
||||
</span>
|
||||
<span class="font-medium text-gray-100">
|
||||
<%= message.body %>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
:if={@current_user}
|
||||
id="chat-input"
|
||||
placeholder="Send a message"
|
||||
disabled={@current_user == nil}
|
||||
class="mt-2 bg-gray-950 h-[30px] text-white focus:outline-none focus:ring-purple-400 block w-full min-w-0 rounded-md sm:text-sm ring-1 ring-gray-600 px-2"
|
||||
/>
|
||||
<a
|
||||
:if={!@current_user}
|
||||
href={Algora.Github.authorize_url()}
|
||||
class="mt-2 w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-purple-600 hover:bg-purple-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-400"
|
||||
>
|
||||
Sign in to chat
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
"""
|
||||
end
|
||||
|
||||
def mount(_params, _session, socket) do
|
||||
{:ok, socket, layout: false, temporary_assigns: [messages: []]}
|
||||
end
|
||||
|
||||
def handle_info({Library, _}, socket), do: {:noreply, socket}
|
||||
|
||||
def handle_event("join", %{"video_id" => video_id}, socket) do
|
||||
socket =
|
||||
socket
|
||||
|> assign(messages: Chat.list_messages(%Video{id: video_id}))
|
||||
|> push_event("join_chat", %{id: video_id})
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
127
lib/algora_web/live/side_panel_live.ex
Normal file
127
lib/algora_web/live/side_panel_live.ex
Normal file
@ -0,0 +1,127 @@
|
||||
defmodule AlgoraWeb.SidePanelLive do
|
||||
use AlgoraWeb, {:live_view, container: {:div, class: "flex-1"}}
|
||||
alias Algora.{Chat, Library}
|
||||
|
||||
on_mount {AlgoraWeb.UserAuth, :current_user}
|
||||
|
||||
def render(assigns) do
|
||||
tabs =
|
||||
[:chat]
|
||||
|> append_if(length(assigns.subtitles) > 0, :transcript)
|
||||
|
||||
assigns = assigns |> assign(:tabs, tabs)
|
||||
|
||||
~H"""
|
||||
<div class="p-4 bg-gray-800/40 w-[23rem] backdrop-blur-xl rounded-2xl shadow-inner shadow-white/[10%] border border-white/[15%]">
|
||||
<div>
|
||||
<ul class="pb-2 flex items-center justify-center gap-2 mx-auto text-gray-400">
|
||||
<li :for={{tab, i} <- Enum.with_index(@tabs)}>
|
||||
<button
|
||||
id={"side-panel-tab-#{tab}"}
|
||||
class={[
|
||||
"text-xs font-semibold uppercase tracking-wide",
|
||||
i == 0 && "active-tab text-white pointer-events-none"
|
||||
]}
|
||||
phx-click={
|
||||
set_active_tab("#side-panel-tab-#{tab}")
|
||||
|> set_active_content("#side-panel-content-#{tab}")
|
||||
}
|
||||
>
|
||||
<%= tab %>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div
|
||||
:for={{tab, i} <- Enum.with_index(@tabs)}
|
||||
id={"side-panel-content-#{tab}"}
|
||||
class={["side-panel-content", i != 0 && "hidden"]}
|
||||
>
|
||||
<div
|
||||
:if={tab == :transcript}
|
||||
id="transcript-subtitles"
|
||||
class="text-sm break-words flex-1 overflow-y-auto h-[calc(100vh-11rem)]"
|
||||
>
|
||||
<div :for={subtitle <- @subtitles} id={"subtitle-#{subtitle.id}"}>
|
||||
<span class="font-semibold text-indigo-400">
|
||||
<%= Library.to_hhmmss(subtitle.start) %>
|
||||
</span>
|
||||
<span class="font-medium text-gray-100">
|
||||
<%= subtitle.body %>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div :if={tab == :chat}>
|
||||
<div
|
||||
id="chat-messages"
|
||||
class="text-sm break-words flex-1 overflow-y-auto h-[calc(100vh-11rem)]"
|
||||
>
|
||||
<div :for={message <- @messages} id={"message-#{message.id}"}>
|
||||
<span class={"font-semibold #{if(system_message?(message), do: "text-emerald-400", else: "text-indigo-400")}"}>
|
||||
<%= message.sender_handle %>:
|
||||
</span>
|
||||
<span class="font-medium text-gray-100">
|
||||
<%= message.body %>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
:if={@current_user}
|
||||
id="chat-input"
|
||||
placeholder="Send a message"
|
||||
disabled={@current_user == nil}
|
||||
class="mt-2 bg-gray-950 h-[30px] text-white focus:outline-none focus:ring-purple-400 block w-full min-w-0 rounded-md sm:text-sm ring-1 ring-gray-600 px-2"
|
||||
/>
|
||||
<a
|
||||
:if={!@current_user}
|
||||
href={Algora.Github.authorize_url()}
|
||||
class="mt-2 w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-purple-600 hover:bg-purple-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-400"
|
||||
>
|
||||
Sign in to chat
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
def mount(_params, _session, socket) do
|
||||
{:ok, socket, temporary_assigns: [subtitles: [], messages: []]}
|
||||
end
|
||||
|
||||
def handle_event("show", %{"video_id" => video_id}, socket) do
|
||||
socket =
|
||||
socket
|
||||
|> assign(subtitles: Library.list_subtitles(%Library.Video{id: video_id}))
|
||||
|> assign(messages: Chat.list_messages(%Library.Video{id: video_id}))
|
||||
|> push_event("join_chat", %{id: video_id})
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
defp set_active_content(js \\ %JS{}, to) do
|
||||
js
|
||||
|> JS.hide(to: ".side-panel-content")
|
||||
|> JS.show(to: to)
|
||||
end
|
||||
|
||||
defp set_active_tab(js \\ %JS{}, tab) do
|
||||
js
|
||||
|> JS.remove_class("active-tab text-white pointer-events-none",
|
||||
to: "#video-side-panel .active-tab"
|
||||
)
|
||||
|> JS.add_class("active-tab text-white pointer-events-none", to: tab)
|
||||
end
|
||||
|
||||
defp system_message?(%Chat.Message{} = message) do
|
||||
message.sender_handle == "algora"
|
||||
end
|
||||
|
||||
defp append_if(list, cond, extra) do
|
||||
if cond, do: list ++ [extra], else: list
|
||||
end
|
||||
end
|
Loading…
x
Reference in New Issue
Block a user