Files

155 lines
4.9 KiB
Elixir
Raw Permalink Normal View History

2026-07-04 18:05:14 +09:00
defmodule Rsh26poolWeb.Layouts do
@moduledoc """
This module holds layouts and related functionality
used by your application.
"""
use Rsh26poolWeb, :html
# Embed all files in layouts/* within this module.
# The default root.html.heex file contains the HTML
# skeleton of your application, namely HTML headers
# and other static content.
embed_templates "layouts/*"
@doc """
Renders your app layout.
This function is typically invoked from every template,
and it often contains your application menu, sidebar,
or similar.
## Examples
<Layouts.app flash={@flash}>
<h1>Content</h1>
</Layouts.app>
"""
attr :flash, :map, required: true, doc: "the map of flash messages"
2026-07-04 19:27:17 +09:00
attr :current_participant, :map,
2026-07-04 18:05:14 +09:00
default: nil,
2026-07-04 19:27:17 +09:00
doc: "the currently logged-in participant, if any"
2026-07-04 18:05:14 +09:00
slot :inner_block, required: true
def app(assigns) do
~H"""
2026-07-04 19:27:17 +09:00
<header class="navbar bg-base-100 border-b border-base-200 px-4 sm:px-6 lg:px-8">
2026-07-04 18:05:14 +09:00
<div class="flex-1">
2026-07-04 19:27:17 +09:00
<.link navigate={~p"/"} class="flex items-center gap-2 text-lg font-bold">
<.icon name="hero-check-badge" class="size-7 text-primary" />
<span>みんなで投票</span>
</.link>
2026-07-04 18:05:14 +09:00
</div>
2026-07-04 19:27:17 +09:00
<div class="flex-none flex items-center gap-3">
<.theme_toggle />
<div :if={@current_participant} class="flex items-center gap-2">
<span class="hidden sm:inline text-sm text-base-content/70">
{@current_participant.name} さん
</span>
<.form for={%{}} action={~p"/logout"} method="delete">
<button class="btn btn-sm btn-ghost gap-1" type="submit">
<.icon name="hero-arrow-right-on-rectangle" class="size-4" />
<span class="hidden sm:inline">ログアウト</span>
</button>
</.form>
</div>
2026-07-04 18:05:14 +09:00
</div>
</header>
2026-07-04 19:27:17 +09:00
<main class="px-4 py-10 sm:px-6 lg:px-8">
<div class="mx-auto max-w-3xl space-y-6">
2026-07-04 18:05:14 +09:00
{render_slot(@inner_block)}
</div>
</main>
<.flash_group flash={@flash} />
"""
end
@doc """
Shows the flash group with standard titles and content.
## Examples
<.flash_group flash={@flash} />
"""
attr :flash, :map, required: true, doc: "the map of flash messages"
attr :id, :string, default: "flash-group", doc: "the optional id of flash container"
def flash_group(assigns) do
~H"""
<div id={@id} aria-live="polite">
<.flash kind={:info} flash={@flash} />
<.flash kind={:error} flash={@flash} />
<.flash
id="client-error"
kind={:error}
2026-07-04 19:27:17 +09:00
title="インターネットに接続できません"
2026-07-04 18:05:14 +09:00
phx-disconnected={
show(".phx-client-error #client-error")
|> JS.remove_attribute("hidden", to: ".phx-client-error #client-error")
}
phx-connected={hide("#client-error") |> JS.set_attribute({"hidden", ""})}
hidden
>
2026-07-04 19:27:17 +09:00
再接続を試みています <.icon name="hero-arrow-path" class="ml-1 size-3 motion-safe:animate-spin" />
2026-07-04 18:05:14 +09:00
</.flash>
<.flash
id="server-error"
kind={:error}
2026-07-04 19:27:17 +09:00
title="問題が発生しました"
2026-07-04 18:05:14 +09:00
phx-disconnected={
show(".phx-server-error #server-error")
|> JS.remove_attribute("hidden", to: ".phx-server-error #server-error")
}
phx-connected={hide("#server-error") |> JS.set_attribute({"hidden", ""})}
hidden
>
2026-07-04 19:27:17 +09:00
再接続を試みています <.icon name="hero-arrow-path" class="ml-1 size-3 motion-safe:animate-spin" />
2026-07-04 18:05:14 +09:00
</.flash>
</div>
"""
end
@doc """
Provides dark vs light theme toggle based on themes defined in app.css.
See <head> in root.html.heex which applies the theme before page load.
"""
def theme_toggle(assigns) do
~H"""
<div class="card relative flex flex-row items-center border-2 border-base-300 bg-base-300 rounded-full">
<div class="absolute w-1/3 h-full rounded-full border-1 border-base-200 bg-base-100 brightness-200 left-0 [[data-theme=light]_&]:left-1/3 [[data-theme=dark]_&]:left-2/3 [[data-theme-source=system]_&]:!left-0 transition-[left]" />
<button
class="flex p-2 cursor-pointer w-1/3"
phx-click={JS.dispatch("phx:set-theme")}
data-phx-theme="system"
>
<.icon name="hero-computer-desktop-micro" class="size-4 opacity-75 hover:opacity-100" />
</button>
<button
class="flex p-2 cursor-pointer w-1/3"
phx-click={JS.dispatch("phx:set-theme")}
data-phx-theme="light"
>
<.icon name="hero-sun-micro" class="size-4 opacity-75 hover:opacity-100" />
</button>
<button
class="flex p-2 cursor-pointer w-1/3"
phx-click={JS.dispatch("phx:set-theme")}
data-phx-theme="dark"
>
<.icon name="hero-moon-micro" class="size-4 opacity-75 hover:opacity-100" />
</button>
</div>
"""
end
end