mirror of
https://github.com/algora-io/tv.git
synced 2024-11-26 01:00:20 +02:00
revamp chat
This commit is contained in:
parent
ece3051b50
commit
cfe3f03bf4
@ -34,6 +34,8 @@ defmodule Algora.Chat do
|
||||
select_merge: %{
|
||||
platform: e.platform,
|
||||
sender_handle: coalesce(u.handle, e.handle),
|
||||
sender_name: coalesce(coalesce(u.name, e.name), e.handle),
|
||||
sender_avatar_url: coalesce(u.avatar_url, e.avatar_url),
|
||||
channel_id: c.id
|
||||
},
|
||||
where: m.video_id == ^video.id
|
||||
@ -63,6 +65,8 @@ defmodule Algora.Chat do
|
||||
select_merge: %{
|
||||
platform: e.platform,
|
||||
sender_handle: coalesce(u.handle, e.handle),
|
||||
sender_name: coalesce(coalesce(u.name, e.name), e.handle),
|
||||
sender_avatar_url: coalesce(u.avatar_url, e.avatar_url),
|
||||
channel_id: c.id
|
||||
},
|
||||
where: m.id == ^id
|
||||
|
@ -8,6 +8,8 @@ defmodule Algora.Chat.Message do
|
||||
field :body, :string
|
||||
field :platform, :string, virtual: true
|
||||
field :sender_handle, :string, virtual: true
|
||||
field :sender_name, :string, virtual: true
|
||||
field :sender_avatar_url, :string, virtual: true
|
||||
field :channel_id, :integer, virtual: true
|
||||
belongs_to :entity, Entity
|
||||
belongs_to :user, User
|
||||
|
71
lib/algora_web/components/avatar.ex
Normal file
71
lib/algora_web/components/avatar.ex
Normal file
@ -0,0 +1,71 @@
|
||||
defmodule AlgoraWeb.Components.Avatar do
|
||||
@moduledoc false
|
||||
use Phoenix.Component
|
||||
|
||||
attr(:src, :string)
|
||||
attr(:alt, :string)
|
||||
attr(:class, :string, default: nil)
|
||||
attr(:rest, :global)
|
||||
|
||||
def user_avatar(assigns) do
|
||||
~H"""
|
||||
<.avatar class={@class} {@rest}>
|
||||
<.avatar_fallback class="fallback">
|
||||
<%= @alt
|
||||
|> String.first()
|
||||
|> String.upcase() %>
|
||||
</.avatar_fallback>
|
||||
<.avatar_image src={@src} alt={@alt} />
|
||||
</.avatar>
|
||||
"""
|
||||
end
|
||||
|
||||
attr(:class, :string, default: nil)
|
||||
attr(:rest, :global)
|
||||
slot(:inner_block, required: true)
|
||||
|
||||
def avatar(assigns) do
|
||||
~H"""
|
||||
<span class={cn(["flex relative overflow-hidden", @class])} {@rest}>
|
||||
<%= render_slot(@inner_block) %>
|
||||
</span>
|
||||
"""
|
||||
end
|
||||
|
||||
attr(:src, :string)
|
||||
attr(:alt, :string)
|
||||
attr(:class, :string, default: nil)
|
||||
attr(:rest, :global)
|
||||
|
||||
def avatar_image(assigns) do
|
||||
~H"""
|
||||
<img
|
||||
class={cn(["aspect-square h-full w-full absolute", @class])}
|
||||
src={@src}
|
||||
alt={@alt}
|
||||
{@rest}
|
||||
phx-update="ignore"
|
||||
style="display:none"
|
||||
onload="this.style.display=''"
|
||||
/>
|
||||
"""
|
||||
end
|
||||
|
||||
attr(:class, :string, default: nil)
|
||||
attr(:rest, :global)
|
||||
slot(:inner_block, required: false)
|
||||
|
||||
def avatar_fallback(assigns) do
|
||||
~H"""
|
||||
<span
|
||||
class={cn(["absolute flex h-full w-full items-center justify-center rounded-full", @class])}
|
||||
{@rest}
|
||||
>
|
||||
<%= render_slot(@inner_block) %>
|
||||
</span>
|
||||
"""
|
||||
end
|
||||
|
||||
# TODO
|
||||
defp cn(x), do: x
|
||||
end
|
@ -2,6 +2,8 @@ defmodule AlgoraWeb.ChatLive do
|
||||
use AlgoraWeb, :live_view
|
||||
require Logger
|
||||
|
||||
import AlgoraWeb.Components.Avatar
|
||||
|
||||
alias Algora.{Accounts, Library, Chat}
|
||||
alias AlgoraWeb.{LayoutComponent, RTMPDestinationIconComponent}
|
||||
|
||||
@ -67,20 +69,33 @@ defmodule AlgoraWeb.ChatLive do
|
||||
id="chat-messages"
|
||||
phx-hook="Chat"
|
||||
phx-update="stream"
|
||||
class="text-sm break-words flex-1 scrollbar-thin overflow-y-auto inset-0 h-[400px] py-4"
|
||||
class="text-sm break-words flex-1 scrollbar-thin overflow-y-auto inset-0 h-[400px] py-4 space-y-2.5"
|
||||
>
|
||||
<div :for={{id, message} <- @streams.messages} id={id} class="px-4">
|
||||
<RTMPDestinationIconComponent.icon
|
||||
:if={message.platform != "algora"}
|
||||
class="inline-flex w-5 h-5 shrink-0 mr-0.5"
|
||||
icon={String.to_atom(message.platform)}
|
||||
/>
|
||||
<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
|
||||
:for={{id, message} <- @streams.messages}
|
||||
id={id}
|
||||
class="px-4 flex items-start gap-2"
|
||||
>
|
||||
<div class="relative h-6 w-6 shrink-0">
|
||||
<.user_avatar
|
||||
src={message.sender_avatar_url}
|
||||
alt={message.sender_handle}
|
||||
class="rounded-full h-6 w-6 [&_.fallback]:bg-gray-700 [&_.fallback]:text-xs"
|
||||
/>
|
||||
<RTMPDestinationIconComponent.icon
|
||||
:if={message.platform != "algora"}
|
||||
class="absolute -right-1 -bottom-1 flex w-4 h-4 shrink-0 bg-[#110f2c]"
|
||||
icon={String.to_atom(message.platform)}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<span class={"font-semibold #{if(system_message?(message), do: "text-indigo-400", else: "text-emerald-400")}"}>
|
||||
<%= message.sender_name %>
|
||||
</span>
|
||||
<span class="font-medium text-gray-100">
|
||||
<%= message.body %>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,6 +2,7 @@ defmodule AlgoraWeb.VideoLive do
|
||||
use AlgoraWeb, :live_view
|
||||
require Logger
|
||||
import Ecto.Query, warn: false
|
||||
import AlgoraWeb.Components.Avatar
|
||||
|
||||
alias Algora.{Accounts, Library, Storage, Chat, Repo}
|
||||
alias Algora.Events.Event
|
||||
@ -421,7 +422,7 @@ defmodule AlgoraWeb.VideoLive do
|
||||
phx-hook="Chat"
|
||||
phx-update="stream"
|
||||
class={[
|
||||
"text-sm break-words flex-1 scrollbar-thin overflow-y-auto",
|
||||
"text-sm break-words flex-1 scrollbar-thin overflow-y-auto space-y-2.5",
|
||||
if(@channel.solving_challenge,
|
||||
do: "h-[calc(100svh-56.25vw-415px)] sm:h-[calc(100vh-19.5rem)]",
|
||||
else: "h-[calc(100svh-56.25vw-375px)] sm:h-[calc(100vh-12rem)]"
|
||||
@ -431,19 +432,28 @@ defmodule AlgoraWeb.VideoLive do
|
||||
<div
|
||||
:for={{id, message} <- @streams.messages}
|
||||
id={id}
|
||||
class="group hover:bg-white/5 relative px-4"
|
||||
class="group hover:bg-white/5 relative px-4 flex items-start gap-2"
|
||||
>
|
||||
<RTMPDestinationIconComponent.icon
|
||||
:if={message.platform != "algora"}
|
||||
class="inline-flex w-5 h-5 shrink-0 mr-0.5"
|
||||
icon={String.to_atom(message.platform)}
|
||||
/>
|
||||
<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 class="relative h-6 w-6 shrink-0">
|
||||
<.user_avatar
|
||||
src={message.sender_avatar_url}
|
||||
alt={message.sender_handle}
|
||||
class="rounded-full h-full w-full [&_.fallback]:bg-gray-700 [&_.fallback]:text-xs"
|
||||
/>
|
||||
<RTMPDestinationIconComponent.icon
|
||||
:if={message.platform != "algora"}
|
||||
class="absolute -right-1 -bottom-1 flex w-4 h-4 shrink-0 bg-[#110f2c]"
|
||||
icon={String.to_atom(message.platform)}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<span class={"font-semibold #{if(system_message?(message), do: "text-indigo-400", else: "text-emerald-400")}"}>
|
||||
<%= message.sender_name %>
|
||||
</span>
|
||||
<span class="font-medium text-gray-100">
|
||||
<%= message.body %>
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
:if={@current_user && Chat.can_delete?(@current_user, message)}
|
||||
phx-click="delete"
|
||||
|
Loading…
Reference in New Issue
Block a user