Starting with the line,
<%= if !!@initials && render_slot(@svg) do %>
In the module directly below:
I’m curious why I wasn’t able to make a relaxed operator work, like
{render_slot(@svg) || !!@operator && SOME_CODE }
I tried making the default svg a functional component, plain text, nested sigil_H (not even sure if that would work in any case?).
defmodule ContentAgentWeb.TailwindUi.Components.AvatarComponent do
use ContentAgentWeb, :html
import Phoenix.LiveView.JS
attr :src, :string, default: nil, doc: "the image source for the avatar"
attr :square, :boolean, default: false, doc: "whether the avatar is square or circular"
attr :initials, :string, default: nil, doc: "the initials to display if no image is provided"
attr :alt, :string, default: "", doc: "the alt text for the avatar"
attr :class, :string, default: "", doc: "additional classes for the avatar"
attr :rest, :global, doc: "the attributes for the avatar"
slot :svg, required: false, doc: "the slot for the svg element" do
attr :initials, :string, doc: "Initials to display"
attr :alt, :string, doc: "Alt text for the SVG"
end
def avatar(assigns) do
~H"""
<span
{@rest}
class={[
@class,
"inline-grid shrink-0 align-middle [--avatar-radius:20%] [--ring-opacity:20%] *:col-start-1 *:row-start-1",
"outline outline-1 -outline-offset-1 outline-black/[--ring-opacity] dark:outline-white/[--ring-opacity]",
(@square && "rounded-[--avatar-radius] *:rounded-[--avatar-radius]") ||
"rounded-full *:rounded-full"
]}
>
<%= if !!@initials && render_slot(@svg) do %>
{render_slot(@svg)}
<% else %>
<%= if !!@initials do %>
<svg
:if={!!@initials}
class="size-full select-none fill-current p-[5%] text-[48px] font-medium uppercase"
viewBox="0 0 100 100"
aria-hidden={@alt != ""}
>
<title :if={@alt != ""}>{@alt}</title>
<text
x="50%"
y="50%"
alignment-baseline="middle"
dominant-baseline="middle"
text-anchor="middle"
dy=".125em"
>
{@initials}
</text>
</svg>
<% end %>
<img :if={@src} class="size-full" src={@src} alt={@alt} />
<% end %>
</span>
"""
end
end
Just curious about the underlying reason why that is the case when I was able to get stuff like this to work:
attr :color, :atom, default: :dark_zinc
attr :base_class, :list, default: @base_classes
attr :button_style, :atom, default: :primary, values: [:primary, :secondary, :soft]
attr :button_text, :string
attr :class, :list, default: []
attr :disabled, :boolean, default: false
attr :type, :string, default: "button"
attr :rest, :global
slot :icon
slot :inner_block
def button(assigns) do
color_classes = color_classes(%{color: assigns.color})
button_style = button_style(%{button_style: assigns.button_style})
assigns =
assign(
assigns,
:computed_classes,
[button_style | [color_classes | [assigns.class | [assigns.base_class]]]]
)
assigns =
(assigns.icon &&
assign(
assigns,
:icon,
"<div data-slot=\"icon\"> <%= render_slot(@icon) %> </div>"
)) || assigns
~H"""
<button type={@type} class={@computed_classes} disabled={@disabled} {@rest}>
<span
class="absolute left-1/2 top-1/2 size-[max(100%,2.75rem)] -translate-x-1/2 -translate-y-1/2 [@media(pointer:fine)]:hidden"
aria-hidden="true"
/>
{@icon}
{render_slot(@inner_block) || @button_text} <<<<<-----------------------
</button>
"""
end
attr :src, :string, default: nil, doc: "the image source for the avatar"
attr :square, :boolean, default: false, doc: "whether the avatar is square or circular"
attr :initials, :string, default: nil, doc: "the initials to display if no image is provided"
attr :alt, :string, default: "", doc: "the alt text for the avatar"
attr :class, :string, default: "", doc: "additional classes for the avatar button"
attr :rest, :global, doc: "the attributes for the avatar button"
def avatar_button(assigns) do
assigns =
assign(assigns, :classes, [
{(assigns.square && "rounded-[20%]") || "rounded-full"}, <<<<<-----------------------
"relative inline-grid focus:outline-none data-[focus]:outline data-[focus]:outline-2 data-[focus]:outline-offset-2 data-[focus]:outline-blue-500"
| [assigns.class]
])
~H"""
<button
class={Enum.join(@classes, " ")}
phx-hover={JS.add_class("data-hover")}
phx-mouse-leave={JS.remove_class("data-hover")}
phx-focus={JS.add_class("data-focus")}
phx-blur={JS.remove_class("data-focus")}
phx-click={
JS.add_class("data-active", to: "button")
|> JS.remove_class("data-active", to: "button", delay: 200)
}
{@rest}
>
<span
class="absolute left-1/2 top-1/2 size-[max(100%,2.75rem)] -translate-x-1/2 -translate-y-1/2 [@media(pointer:fine)]:hidden"
aria-hidden="true"
/>
<AvatarComponent.avatar src={@src} square={@square} initials={@initials} alt={@alt}>
</AvatarComponent.avatar>
</button>
"""
end
Also, always looking to improve so if there are ways to improve what I’m trying to do here, always open to feedback if you have time to share feedback