1
0
mirror of https://github.com/algora-io/tv.git synced 2025-10-30 23:07:56 +02:00

revamp homepage (#44)

This commit is contained in:
Zafer Cesur
2024-05-31 12:29:56 +03:00
committed by GitHub
parent 1cf1f37b35
commit 1cb6c1eb33
8 changed files with 229 additions and 6 deletions

View File

@@ -581,6 +581,20 @@ defmodule Algora.Library do
|> Enum.reverse()
end
def list_videos_by_show_ids(ids) do
from(v in Video,
join: u in User,
on: v.user_id == u.id,
select_merge: %{
channel_handle: u.handle,
channel_name: u.name,
channel_avatar_url: u.avatar_url
},
where: v.show_id in ^ids
)
|> Repo.all()
end
def list_shorts(limit \\ 100) do
from(v in Video,
join: u in User,

View File

@@ -3,9 +3,28 @@ defmodule Algora.Shows do
alias Algora.Repo
alias Algora.Shows.Show
alias Algora.Accounts.User
def list_shows do
Repo.all(Show)
def list_shows() do
from(s in Show)
|> Repo.all()
end
def list_featured_shows(limit \\ 100) do
from(s in Show,
join: u in User,
on: s.user_id == u.id,
limit: ^limit,
where: not is_nil(s.ordering),
select_merge: %{
channel_handle: u.handle,
channel_name: coalesce(u.name, u.handle),
channel_avatar_url: u.avatar_url,
channel_twitter_url: u.twitter_url
},
order_by: [{:desc, s.ordering}, {:desc, s.id}]
)
|> Repo.all()
end
def get_show!(id), do: Repo.get!(Show, id)
@@ -31,4 +50,8 @@ defmodule Algora.Shows do
def change_show(%Show{} = show, attrs \\ %{}) do
Show.changeset(show, attrs)
end
def list_videos do
Repo.all(Show)
end
end

View File

@@ -12,6 +12,11 @@ defmodule Algora.Shows.Show do
field :image_url, :string
field :og_image_url, :string
field :url, :string
field :ordering, :integer
field :channel_handle, :string, virtual: true
field :channel_name, :string, virtual: true
field :channel_avatar_url, :string, virtual: true
field :channel_twitter_url, :string, virtual: true
belongs_to :user, User

View File

@@ -0,0 +1,170 @@
defmodule AlgoraWeb.HomepageLive do
use AlgoraWeb, :live_view
alias Algora.{Library, Shows}
def render(assigns) do
~H"""
<div class="mx-auto pt-2 pb-6 px-4 sm:px-6 space-y-6">
<.header class="pt-8">
<h1 class="text-4xl font-semibold">Livestreaming for developers</h1>
<p class="text-xl font-medium text-gray-200 italic">You'll never ship alone!</p>
</.header>
<div>
<ul role="list" class="grid grid-cols-1 gap-12 sm:grid-cols-2">
<li :for={show <- @shows} class="col-span-1">
<div class="h-full flex flex-col rounded-2xl overflow-hidden bg-[#15112b] ring-1 ring-white/20 text-center shadow-lg relative group">
<img
class="object-cover absolute inset-0 shrink-0 h-[12rem] w-full bg-gray-950"
src={show.image_url}
alt=""
/>
<div class="absolute h-[12rem] w-full inset-0 bg-gradient-to-b from-transparent to-[#15112b]" />
<.link navigate={~p"/shows/#{show.slug}"} class="absolute h-[10rem] w-full inset-0 z-10">
</.link>
<div class="relative text-left h-full">
<div class="flex flex-1 flex-col h-full">
<div class="px-4 mt-[8rem] flex-col sm:flex-row flex sm:items-center gap-4">
<.link :if={show.channel_handle != "algora"} navigate={~p"/shows/#{show.slug}"}>
<img
class="h-[8rem] w-[8rem] rounded-full ring-4 ring-white shrink-0"
src={show.channel_avatar_url}
alt=""
/>
</.link>
<div :if={show.channel_handle == "algora"} class="h-[8rem] w-0 -ml-4"></div>
<div>
<.link navigate={~p"/shows/#{show.slug}"}>
<h3 class="mt-auto text-3xl font-semibold text-white [text-shadow:#000_10px_5px_10px] line-clamp-2 hover:underline">
<%= show.title %>
</h3>
</.link>
<div :if={show.channel_handle != "algora"} class="flex items-center gap-2">
<.link navigate={~p"/#{show.channel_handle}"}>
<div class="text-base text-gray-300 font-semibold line-clamp-1 hover:underline">
<%= show.channel_name %>
</div>
</.link>
<.link
:if={show.channel_twitter_url}
target="_blank"
rel="noopener noreferrer"
href={show.channel_twitter_url}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="text-white"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M4 4l11.733 16h4.267l-11.733 -16z" /><path d="M4 20l6.768 -6.768m2.46 -2.46l6.772 -6.772" />
</svg>
</.link>
</div>
<div :if={show.channel_handle == "algora"} class="h-[24px]"></div>
</div>
<.link
:if={show.scheduled_for}
navigate={~p"/shows/#{show.slug}"}
class="shrink-0 sm:hidden xl:flex bg-gray-900 px-3 py-2 rounded-lg ring-1 ring-green-300 mr-auto sm:mr-0 sm:ml-auto flex items-center space-x-2"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="h-6 w-6 text-green-300 shrink-0"
>
<path d="M8 2v4"></path>
<path d="M16 2v4"></path>
<rect width="18" height="18" x="3" y="4" rx="2"></rect>
<path d="M3 10h18"></path>
</svg>
<div class="shrink-0">
<div class="text-sm font-semibold">
<%= show.scheduled_for
|> Timex.to_datetime("Etc/UTC")
|> Timex.Timezone.convert("America/New_York")
|> Timex.format!("{WDfull}, {Mshort} {D}") %>
</div>
<div class="text-sm">
<%= show.scheduled_for
|> Timex.to_datetime("Etc/UTC")
|> Timex.Timezone.convert("America/New_York")
|> Timex.format!("{h12}:{m} {am}, Eastern Time") %>
</div>
</div>
</.link>
</div>
<div
:if={length(Enum.filter(@show_eps, fn v -> v.show_id == show.id end)) > 0}
class="mt-auto pt-[2rem] -mb-2"
>
<div class="flex justify-between items-center gap-2 px-2">
<h3 class="text-sm uppercase text-gray-300 font-semibold">Past episodes</h3>
</div>
<div class="p-2 flex gap-4 overflow-x-scroll scrollbar-thin transition-all">
<div
:for={video <- Enum.filter(@show_eps, fn v -> v.show_id == show.id end)}
class="max-w-[12rem] sm:max-w-[16rem] shrink-0 w-full"
>
<.link class="truncate" href={~p"/#{video.channel_handle}/#{video.id}"}>
<.video_thumbnail video={video} class="rounded-xl" />
</.link>
</div>
</div>
</div>
</div>
</div>
</div>
</li>
</ul>
</div>
<div class="pt-12">
<h2 class="text-white text-3xl font-semibold">
Most recent livestreams
</h2>
<div>
<div class="pt-4 gap-8 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3">
<.video_entry :for={video <- @videos} video={video} />
</div>
</div>
</div>
</div>
"""
end
def mount(_params, _session, socket) do
shows = Shows.list_featured_shows()
show_eps = shows |> Enum.map(fn s -> s.id end) |> Library.list_videos_by_show_ids()
videos = Library.list_videos(150)
{:ok,
socket
|> assign(:show_eps, show_eps)
|> assign(:videos, videos)
|> assign(:shows, shows)}
end
def handle_params(params, _url, socket) do
{:noreply, socket |> apply_action(socket.assigns.live_action, params)}
end
defp apply_action(socket, :show, _params) do
socket |> assign(:page_title, nil)
end
end

View File

@@ -154,7 +154,7 @@ defmodule AlgoraWeb.ShowLive.FormComponent do
{:noreply,
socket
|> put_flash(:info, "Show created successfully")
|> push_patch(to: ~p"/shows/#{show.slug}")}
|> push_navigate(to: ~p"/shows/#{show.slug}")}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign_form(socket, changeset)}

View File

@@ -99,7 +99,9 @@ defmodule AlgoraWeb.ShowLive.Show do
<span :if={@attendees_count > @max_attendee_names_count} class="font-medium">
and
<span :if={@attendees_count == @max_attendee_names_count + 1}>
<%= @attendees |> Enum.at(@max_attendee_names_count) %>
<%= @attendees
|> Enum.map(fn attendee -> attendee.user_display_name end)
|> Enum.at(@max_attendee_names_count) %>
</span>
<span :if={@attendees_count != @max_attendee_names_count + 1}>
<%= @attendees_count - @max_attendee_names_count %> others
@@ -274,7 +276,7 @@ defmodule AlgoraWeb.ShowLive.Show do
channel = Accounts.get_user(show.user_id) |> Library.get_channel!()
videos = Library.list_channel_videos(channel, 50)
videos = Library.list_videos_by_show_ids([show.id])
{:ok,
socket

View File

@@ -105,7 +105,7 @@ defmodule AlgoraWeb.Router do
end
live_session :default, on_mount: [{AlgoraWeb.UserAuth, :current_user}, AlgoraWeb.Nav] do
live "/", HomeLive, :show
live "/", HomepageLive, :show
live "/auth/login", SignInLive, :index
live "/cossgpt", COSSGPTLive, :index
live "/og/cossgpt", COSSGPTOGLive, :index

View File

@@ -0,0 +1,9 @@
defmodule Algora.Repo.Local.Migrations.AddOrderingToShow do
use Ecto.Migration
def change do
alter table("shows") do
add :ordering, :integer
end
end
end