Skip to content
Draft
36 changes: 21 additions & 15 deletions lib/atomic_web/components/activity.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule AtomicWeb.Components.Activity do
"""
use AtomicWeb, :component

import AtomicWeb.Components.Avatar
import AtomicWeb.Components.{Avatar, Popover}

alias Atomic.Activities.Activity

Expand All @@ -13,22 +13,28 @@ defmodule AtomicWeb.Components.Activity do
def activity(assigns) do
~H"""
<div>
<div class="flex space-x-3">
<div class="flex">
<div class="my-auto flex-shrink-0">
<.avatar name={@activity.organization.name} color={:light_gray} class="!h-10 !w-10" size={:xs} type={:organization} src={Uploaders.Logo.url({@activity.organization.logo, @activity.organization}, :original)} />
<.popover type={:organization} organization={@activity.organization} position={:bottom}>
<:wrapper>
<.avatar name={@activity.organization.name} color={:light_gray} class="!h-10 !w-10" size={:xs} type={:organization} src={Uploaders.Logo.url({@activity.organization.logo, @activity.organization}, :original)} />
</:wrapper>
</.popover>
</div>
<div class="min-w-0 flex-1">
<object>
<.link navigate={Routes.organization_show_path(AtomicWeb.Endpoint, :show, @activity.organization.id)}>
<span class="text-sm font-medium text-gray-900 hover:underline focus:outline-none">
<%= @activity.organization.name %>
</span>
</.link>
</object>
<p class="text-sm text-gray-500">
<span class="sr-only">Published on</span>
<time><%= relative_datetime(@activity.inserted_at) %></time>
</p>
<div class="ml-3">
<div class="min-w-0 flex-1">
<object>
<.link navigate={Routes.organization_show_path(AtomicWeb.Endpoint, :show, @activity.organization.id)}>
<span class="text-sm font-medium text-gray-900 hover:underline focus:outline-none">
<%= @activity.organization.name %>
</span>
</.link>
</object>
<p class="text-sm text-gray-500">
<span class="sr-only">Published on</span>
<time><%= relative_datetime(@activity.inserted_at) %></time>
</p>
</div>
</div>
</div>
<h2 class="mt-3 text-base font-semibold text-gray-900"><%= @activity.title %></h2>
Expand Down
36 changes: 21 additions & 15 deletions lib/atomic_web/components/announcement.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,35 @@ defmodule AtomicWeb.Components.Announcement do
"""
use AtomicWeb, :component

import AtomicWeb.Components.Avatar
import AtomicWeb.Components.{Avatar, Popover}

attr :announcement, :map, required: true, doc: "The announcement to render."

def announcement(assigns) do
~H"""
<div>
<div class="flex space-x-3">
<div class="flex">
<div class="my-auto flex-shrink-0">
<.avatar name={@announcement.organization.name} color={:light_gray} class="!h-10 !w-10" size={:xs} type={:organization} src={Uploaders.Logo.url({@announcement.organization.logo, @announcement.organization}, :original)} />
<.popover type={:organization} organization={@announcement.organization} position={:bottom}>
<:wrapper>
<.avatar name={@announcement.organization.name} color={:light_gray} class="!h-10 !w-10" size={:xs} type={:organization} src={Uploaders.Logo.url({@announcement.organization.logo, @announcement.organization}, :original)} />
</:wrapper>
</.popover>
</div>
<div class="min-w-0 flex-1">
<object>
<.link navigate={Routes.organization_show_path(AtomicWeb.Endpoint, :show, @announcement.organization.id)} class="hover:underline focus:outline-none">
<p class="text-sm font-medium text-gray-900">
<%= @announcement.organization.name %>
</p>
</.link>
</object>
<p class="text-sm text-gray-500">
<span class="sr-only">Published on</span>
<time><%= relative_datetime(@announcement.inserted_at) %></time>
</p>
<div class="ml-3">
<div class="min-w-0 flex-1">
<object>
<.link navigate={Routes.organization_show_path(AtomicWeb.Endpoint, :show, @announcement.organization.id)} class="hover:underline focus:outline-none">
<p class="text-sm font-medium text-gray-900">
<%= @announcement.organization.name %>
</p>
</.link>
</object>
<p class="text-sm text-gray-500">
<span class="sr-only">Published on</span>
<time><%= relative_datetime(@announcement.inserted_at) %></time>
</p>
</div>
</div>
</div>
<h2 class="mt-3 text-base font-semibold text-gray-900"><%= @announcement.title %></h2>
Expand Down
111 changes: 111 additions & 0 deletions lib/atomic_web/components/popover.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
defmodule AtomicWeb.Components.Popover do
@moduledoc """
Renders a popover.
"""

use AtomicWeb, :component

import AtomicWeb.Components.Avatar

attr :type, :atom,
values: [:user, :organization, :button],
default: :user,
doc: "The type of entity associated with the avatar."

attr :position, :atom,
values: [:top, :right, :bottom, :left],
required: true,
doc: "The position of the popover."

attr :organization, :map, default: %{}, doc: "The organization to render."
attr :user, :map, default: %{}, doc: "The user to render."
attr :button, :map, default: %{}, doc: "The button to render."

slot :wrapper,
required: true,
doc: "Slot to be rendered as a wrapper of the popover. For example, a avatar."

def popover(assigns) do
~H"""
<div class="group relative h-min">
<%= render_slot(@wrapper) %>
<div class={[
"hidden z-50 group-hover:block transition delay-700 duration-300 ease-in-out",
triangle_class(position: @position)
]}>
<div class={[
"absolute z-50 w-64 bg-slate-50 border border-gray-200 rounded-lg shadow-md",
popover_position(position: @position)
]}>
<%= render_popover(assigns, type: @type) %>
</div>
</div>
</div>
"""
end

def triangle_class(position: :bottom) do
"before:border-l-[10px] before:border-b-[10px] before:border-r-[10px] before:absolute before:mx-3 before:mb-8 before:border-r-transparent before:border-b-gray-200 before:border-l-transparent"
end

def triangle_class(position: :top) do
"before:bottom-full before:border-l-[10px] before:border-t-[10px] before:border-r-[10px] before:absolute before:mx-3 before:mt-8 before:border-r-transparent before:border-b-gray-200 before:border-l-transparent"
end

def triangle_class(position: :left) do
"before:right-full before:bottom-0 before:border-t-[10px] before:border-l-[10px] before:border-b-[10px] before:absolute before:mt-9 before:border-t-transparent before:border-l-gray-200 before:border-b-transparent"
end

def triangle_class(position: :right) do
"before:left-full before:bottom-0 before:border-t-[10px] before:border-r-[10px] before:border-b-[10px] before:absolute before:mt-9 before:border-t-transparent before:border-r-gray-200 before:border-b-transparent"
end

def popover_position(position: :bottom) do
"mt-2"
end

def popover_position(position: :top) do
"bottom-full mb-2"
end

def popover_position(position: :right) do
"left-full mx-2 top-0"
end

def popover_position(position: :left) do
"right-full mx-2 top-0"
end

def render_popover(assigns, type: :organization) do
~H"""
<div class="relative p-3">
<div class="mb-2 mb-4 flex items-center justify-between">
<.avatar name={@organization.name} color={:light_gray} class="!h-10 !w-10" size={:xs} type={:organization} src={Uploaders.Logo.url({@organization.logo, @organization}, :original)} />
</div>
<p class="text-base font-semibold leading-none text-gray-900">
<.link navigate={Routes.organization_show_path(AtomicWeb.Endpoint, :show, @organization.id)}>
<%= @organization.name %>
</.link>
</p>
<p class="text-sm text-gray-500 dark:text-gray-400">
<%= @organization.description %>
</p>
</div>
"""
end

def render_popover(assigns, type: :button) do
~H"""
<div class="relative p-3">
<div class="mb-2 mb-4 items-center justify-between">
<p class="text-base font-semibold leading-none text-gray-900">
<%= @button.name %>
</p>
<p class="mt-4 text-sm text-gray-500 dark:text-gray-400">
<%= @button.description %>
</p>
</div>
</div>
"""
end
end
2 changes: 1 addition & 1 deletion lib/atomic_web/templates/layout/live.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<div class="flex relative flex-col min-h-screen">
<div class="flex flex-col mx-auto w-full lg:flex-row xl:px-8 max-w-[1380px]">
<!-- Navbar -->
<div class="relative flex-shrink-0 lg:w-72 lg:flex lg:max-w-[400px]">
<div class="relative flex-shrink-0 z-0 lg:w-72 lg:flex lg:max-w-[400px]">
<%= render("_live_navbar.html", assigns) %>
</div>
<!-- Central content -->
Expand Down
108 changes: 108 additions & 0 deletions storybook/components/popover.story.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
defmodule AtomicWeb.Storybook.Components.Popover do
use PhoenixStorybook.Story, :component

alias AtomicWeb.Components.Popover

def function, do: &Popover.popover/1

def variations do
[
%Variation{
id: :default,
attributes: %{
type: :button,
position: :bottom,
button: %{
name: "Button",
description: "This is a button."
}
},
slots: [
"""
<:wrapper>
<button class="bg-blue-500 text-white px-4 py-2 rounded-md">Button</button>
</:wrapper>
"""
]
},
%VariationGroup{
id: :Positon,
description: "Position",
variations: [
%Variation{
id: :bottom,
attributes: %{
type: :button,
position: :bottom,
button: %{
name: "Button",
description: "The popover is positioned at the bottom."
}
},
slots: [
"""
<:wrapper>
<button class="bg-blue-500 text-white px-4 py-2 rounded-md">Button Bottom</button>
</:wrapper>
"""
]
},
%Variation{
id: :top,
attributes: %{
type: :button,
position: :top,
button: %{
name: "Button",
description: "The popover is positioned at the top."
}
},
slots: [
"""
<:wrapper>
<button class="bg-blue-500 text-white px-4 py-2 rounded-md">Button Top</button>
</:wrapper>
"""
]
},
%Variation{
id: :right,
attributes: %{
type: :button,
position: :right,
button: %{
name: "Button",
description: "The popover is positioned at the right."
}
},
slots: [
"""
<:wrapper>
<button class="bg-blue-500 text-white px-4 py-2 rounded-md">Button Right</button>
</:wrapper>
"""
]
},
%Variation{
id: :left,
attributes: %{
type: :button,
position: :left,
button: %{
name: "Button",
description: "The popover is positioned at the left."
}
},
slots: [
"""
<:wrapper>
<button class="bg-blue-500 text-white px-4 py-2 rounded-md">Button Left</button>
</:wrapper>
"""
]
}
]
}
]
end
end