feat(elixir): proper dark/light mode support

This commit is contained in:
Schuwi
2025-09-14 22:50:44 +02:00
parent 280caad641
commit ae861f32a1
6 changed files with 237 additions and 202 deletions

View File

@@ -298,7 +298,7 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
margin_left = if assigns.depth == 0, do: 0, else: 32 + assigns.depth * 16
# Determine border style based on depth
border_class = if assigns.depth > 0, do: "border-l-2 border-gray-200 pl-6", else: ""
border_class = if assigns.depth > 0, do: "border-l-2 border-base-300 pl-6", else: ""
# Icon size and button size based on depth
{icon_size, button_size, text_size, title_tag} = case assigns.depth do
@@ -328,22 +328,22 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
<div class={[@border_class, @depth > 0 && "mt-4"]} style={"margin-left: #{@margin_left}px"}>
<div class="flex items-center justify-between">
<div class="flex items-center flex-1 space-x-4">
<.icon name={@icon_name} class={"#{@icon_size} #{if @depth == 0, do: "text-blue-500", else: "text-gray-400"}"} />
<.icon name={@icon_name} class={"#{@icon_size} #{if @depth == 0, do: "text-primary", else: "text-base-content/60"}"} />
<div class="flex-1">
<%= if @title_tag == "h3" do %>
<h3 class={"#{@text_size} font-medium #{if @depth == 0, do: "text-gray-900", else: "text-gray-700"}"}>{@location.name}</h3>
<h3 class={"#{@text_size} font-medium #{if @depth == 0, do: "text-base-content", else: "text-base-content/80"}"}>{@location.name}</h3>
<% else %>
<h4 class={"#{@text_size} font-medium #{if @depth == 0, do: "text-gray-900", else: "text-gray-700"}"}>{@location.name}</h4>
<h4 class={"#{@text_size} font-medium #{if @depth == 0, do: "text-base-content", else: "text-base-content/80"}"}>{@location.name}</h4>
<% end %>
<%= if @location.description do %>
<p class="text-sm text-gray-500 mt-1">{@location.description}</p>
<p class="text-sm text-base-content/60 mt-1">{@location.description}</p>
<% end %>
<div class="flex items-center space-x-2 mt-1">
<p class="text-xs text-gray-400">
<p class="text-xs text-base-content/50">
{count_components_in_location(@location.id)} components
</p>
<%= if @location.apriltag_id do %>
<span class="text-xs bg-gray-100 text-gray-600 px-2 py-1 rounded">
<span class="text-xs bg-base-200 text-base-content/80 px-2 py-1 rounded">
AprilTag: {@location.apriltag_id}
</span>
<% end %>
@@ -356,19 +356,19 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
<img
src={get_apriltag_url(@location)}
alt={"AprilTag for #{@location.name}"}
class="w-16 h-auto border border-gray-200 rounded bg-white"
class="w-16 h-auto border border-base-300 rounded bg-base-100"
onerror="this.style.display='none'"
/>
</div>
<% else %>
<div class="w-16 h-16 border border-gray-200 rounded bg-gray-50 flex items-center justify-center flex-shrink-0">
<.icon name="hero-qr-code" class="w-8 h-8 text-gray-400" />
<div class="w-16 h-16 border border-base-300 rounded bg-base-200 flex items-center justify-center flex-shrink-0">
<.icon name="hero-qr-code" class="w-8 h-8 text-base-content/50" />
</div>
<% end %>
<button
phx-click="download_apriltag"
phx-value-id={@location.id}
class="inline-flex items-center px-3 py-1.5 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 flex-shrink-0"
class="inline-flex items-center px-3 py-1.5 border border-base-300 rounded-md shadow-sm text-sm font-medium text-base-content bg-base-100 hover:bg-base-200 flex-shrink-0"
title="Download AprilTag"
>
<.icon name="hero-arrow-down-tray" class="w-4 h-4 mr-1.5" />
@@ -410,19 +410,19 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
@impl true
def render(assigns) do
~H"""
<div class="min-h-screen bg-gray-50">
<div class="min-h-screen bg-base-200">
<!-- Header -->
<div class="bg-white shadow">
<div class="bg-base-100 shadow">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between items-center py-6">
<div class="flex items-center space-x-4">
<.link
navigate={~p"/"}
class="text-gray-500 hover:text-gray-700"
class="text-base-content/60 hover:text-base-content"
>
<.icon name="hero-arrow-left" class="w-5 h-5" />
</.link>
<h1 class="text-3xl font-bold text-gray-900">
<h1 class="text-3xl font-bold text-base-content">
Storage Location Management
</h1>
</div>
@@ -441,7 +441,7 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
</button>
<.link
navigate={~p"/"}
class="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
class="inline-flex items-center px-4 py-2 border border-base-300 text-sm font-medium rounded-md text-base-content bg-base-100 hover:bg-base-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary"
>
<.icon name="hero-cube-transparent" class="w-4 h-4 mr-2" /> Components
</.link>
@@ -452,14 +452,14 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
<!-- Add Location Modal -->
<%= if @show_add_form do %>
<div class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
<div class="relative top-20 mx-auto p-5 border w-11/12 md:w-1/2 shadow-lg rounded-md bg-white">
<div class="fixed inset-0 bg-base-content/50 overflow-y-auto h-full w-full z-50">
<div class="relative top-20 mx-auto p-5 border border-base-300 w-11/12 md:w-1/2 shadow-lg rounded-md bg-base-100">
<div class="mt-3">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-medium text-gray-900">Add New Storage Location</h3>
<h3 class="text-lg font-medium text-base-content">Add New Storage Location</h3>
<button
phx-click="hide_add_form"
class="text-gray-400 hover:text-gray-600"
class="text-base-content/60 hover:text-base-content"
>
<.icon name="hero-x-mark" class="w-6 h-6" />
</button>
@@ -467,12 +467,12 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
<.form for={@form} phx-submit="save_location" class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700">Name</label>
<label class="block text-sm font-medium text-base-content">Name</label>
<.input field={@form[:name]} type="text" required />
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Parent Location</label>
<label class="block text-sm font-medium text-base-content">Parent Location</label>
<.input
field={@form[:parent_id]}
type="select"
@@ -481,12 +481,12 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Description</label>
<label class="block text-sm font-medium text-base-content">Description</label>
<.input field={@form[:description]} type="textarea" />
</div>
<div>
<label class="block text-sm font-medium text-gray-700">AprilTag ID (Optional)</label>
<label class="block text-sm font-medium text-base-content">AprilTag ID (Optional)</label>
<div class="space-y-2">
<div class="flex items-center space-x-2">
<input
@@ -495,12 +495,12 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
value="none"
id="apriltag_none"
checked={@apriltag_mode == "none"}
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
class="h-4 w-4 text-primary focus:ring-primary border-base-300"
phx-click="set_apriltag_mode"
phx-value-mode="none"
/>
<label for="apriltag_none" class="text-sm text-gray-700">
No AprilTag assignment
<label for="apriltag_none" class="text-sm text-base-content">
No AprilTag
</label>
</div>
<div class="flex items-center space-x-2">
@@ -510,11 +510,11 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
value="auto"
id="apriltag_auto"
checked={@apriltag_mode == "auto"}
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
class="h-4 w-4 text-primary focus:ring-primary border-base-300"
phx-click="set_apriltag_mode"
phx-value-mode="auto"
/>
<label for="apriltag_auto" class="text-sm text-gray-700">
<label for="apriltag_auto" class="text-sm text-base-content">
Auto-assign next available ID
</label>
</div>
@@ -525,11 +525,11 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
value="manual"
id="apriltag_manual"
checked={@apriltag_mode == "manual"}
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
class="h-4 w-4 text-primary focus:ring-primary border-base-300"
phx-click="set_apriltag_mode"
phx-value-mode="manual"
/>
<label for="apriltag_manual" class="text-sm text-gray-700">
<label for="apriltag_manual" class="text-sm text-base-content">
Choose specific ID
</label>
</div>
@@ -543,7 +543,7 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
placeholder="Enter ID (0-586)"
class="w-32"
/>
<div class="text-xs text-gray-500">
<div class="text-xs text-base-content/60">
Available IDs: <%= length(@available_apriltag_ids) %> of 587
<%= if length(@available_apriltag_ids) < 20 do %>
<br/>Next available: <%= @available_apriltag_ids |> Enum.take(10) |> Enum.join(", ") %>
@@ -559,13 +559,13 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
<button
type="button"
phx-click="hide_add_form"
class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50"
class="px-4 py-2 border border-base-300 rounded-md text-sm font-medium text-base-content hover:bg-base-200"
>
Cancel
</button>
<button
type="submit"
class="px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700"
class="px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-primary-content bg-primary hover:bg-primary/90"
>
Save Location
</button>
@@ -578,14 +578,14 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
<!-- Edit Location Modal -->
<%= if @show_edit_form do %>
<div class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
<div class="relative top-20 mx-auto p-5 border w-11/12 md:w-1/2 shadow-lg rounded-md bg-white">
<div class="fixed inset-0 bg-base-content/50 overflow-y-auto h-full w-full z-50">
<div class="relative top-20 mx-auto p-5 border border-base-300 w-11/12 md:w-1/2 shadow-lg rounded-md bg-base-100">
<div class="mt-3">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-medium text-gray-900">Edit Storage Location</h3>
<h3 class="text-lg font-medium text-base-content">Edit Storage Location</h3>
<button
phx-click="hide_edit_form"
class="text-gray-400 hover:text-gray-600"
class="text-base-content/60 hover:text-base-content"
>
<.icon name="hero-x-mark" class="w-6 h-6" />
</button>
@@ -593,12 +593,12 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
<.form for={@form} phx-submit="save_edit" class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700">Name</label>
<label class="block text-sm font-medium text-base-content">Name</label>
<.input field={@form[:name]} type="text" required />
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Parent Location</label>
<label class="block text-sm font-medium text-base-content">Parent Location</label>
<.input
field={@form[:parent_id]}
type="select"
@@ -607,12 +607,12 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Description</label>
<label class="block text-sm font-medium text-base-content">Description</label>
<.input field={@form[:description]} type="textarea" />
</div>
<div>
<label class="block text-sm font-medium text-gray-700">AprilTag ID</label>
<label class="block text-sm font-medium text-base-content">AprilTag ID</label>
<div class="space-y-2">
<div class="flex items-center space-x-2">
<input
@@ -621,11 +621,11 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
value="keep"
id="edit_apriltag_keep"
checked={@edit_apriltag_mode == "keep"}
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
class="h-4 w-4 text-primary focus:ring-primary border-base-300"
phx-click="set_edit_apriltag_mode"
phx-value-mode="keep"
/>
<label for="edit_apriltag_keep" class="text-sm text-gray-700">
<label for="edit_apriltag_keep" class="text-sm text-base-content">
Keep current assignment
</label>
</div>
@@ -636,11 +636,11 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
value="change"
id="edit_apriltag_change"
checked={@edit_apriltag_mode == "change"}
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
class="h-4 w-4 text-primary focus:ring-primary border-base-300"
phx-click="set_edit_apriltag_mode"
phx-value-mode="change"
/>
<label for="edit_apriltag_change" class="text-sm text-gray-700">
<label for="edit_apriltag_change" class="text-sm text-base-content">
Change to different ID
</label>
</div>
@@ -651,11 +651,11 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
value="remove"
id="edit_apriltag_remove"
checked={@edit_apriltag_mode == "remove"}
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
class="h-4 w-4 text-primary focus:ring-primary border-base-300"
phx-click="set_edit_apriltag_mode"
phx-value-mode="remove"
/>
<label for="edit_apriltag_remove" class="text-sm text-gray-700">
<label for="edit_apriltag_remove" class="text-sm text-base-content">
Remove AprilTag assignment
</label>
</div>
@@ -669,12 +669,12 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
placeholder="Enter new ID (0-586)"
class="w-32"
/>
<div class="text-xs text-gray-500">
<div class="text-xs text-base-content/60">
Available IDs: <%= length(@available_apriltag_ids) %> of 587
</div>
</div>
<% end %>
<p class="text-xs text-gray-500 mt-1">
<p class="text-xs text-base-content/60 mt-1">
Current: <%= if @editing_location.apriltag_id, do: "ID #{@editing_location.apriltag_id}", else: "None" %>
</p>
</div>
@@ -684,13 +684,13 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
<button
type="button"
phx-click="hide_edit_form"
class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50"
class="px-4 py-2 border border-base-300 rounded-md text-sm font-medium text-base-content hover:bg-base-200"
>
Cancel
</button>
<button
type="submit"
class="px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700"
class="px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-primary-content bg-primary hover:bg-primary/90"
>
Update Location
</button>
@@ -703,39 +703,39 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
<!-- AprilTag Scanner Modal -->
<%= if @apriltag_scanner_open do %>
<div class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
<div class="relative top-10 mx-auto p-5 border w-11/12 md:w-1/2 shadow-lg rounded-md bg-white">
<div class="fixed inset-0 bg-base-content/30 bg-opacity-50 overflow-y-auto h-full w-full z-50">
<div class="relative top-10 mx-auto p-5 border border-base-300 w-11/12 md:w-1/2 shadow-lg rounded-md bg-base-100">
<div class="mt-3">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-medium text-gray-900">AprilTag Scanner</h3>
<h3 class="text-lg font-medium text-base-content">AprilTag Scanner</h3>
<button
phx-click="close_apriltag_scanner"
class="text-gray-400 hover:text-gray-600"
class="text-base-content/50 hover:text-base-content"
>
<.icon name="hero-x-mark" class="w-6 h-6" />
</button>
</div>
<!-- AprilTag Scanner Interface -->
<div class="border-2 border-dashed border-gray-300 rounded-lg p-6 text-center">
<.icon name="hero-qr-code" class="mx-auto h-12 w-12 text-gray-400" />
<p class="mt-2 text-sm text-gray-600">Camera AprilTag scanner would go here</p>
<p class="text-xs text-gray-500 mt-1">In a real implementation, this would use JavaScript AprilTag detection</p>
<div class="border-2 border-dashed border-base-300 rounded-lg p-6 text-center">
<.icon name="hero-qr-code" class="mx-auto h-12 w-12 text-base-content/50" />
<p class="mt-2 text-sm text-base-content/70">Camera AprilTag scanner would go here</p>
<p class="text-xs text-base-content/60 mt-1">In a real implementation, this would use JavaScript AprilTag detection</p>
<!-- Test buttons for demo -->
<div class="mt-4 space-y-2">
<p class="text-sm font-medium text-gray-700">Test with sample AprilTag IDs:</p>
<p class="text-sm font-medium text-base-content/80">Test with sample AprilTag IDs:</p>
<button
phx-click="apriltag_scanned"
phx-value-apriltag_id="0"
class="block w-full px-3 py-2 text-sm bg-gray-100 hover:bg-gray-200 rounded"
class="block w-full px-3 py-2 text-sm bg-base-200 hover:bg-base-300 rounded"
>
Scan AprilTag ID 0
</button>
<button
phx-click="apriltag_scanned"
phx-value-apriltag_id="1"
class="block w-full px-3 py-2 text-sm bg-gray-100 hover:bg-gray-200 rounded"
class="block w-full px-3 py-2 text-sm bg-base-200 hover:bg-base-300 rounded"
>
Scan AprilTag ID 1
</button>
@@ -760,10 +760,10 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
</button>
</div>
<div class="space-y-2">
<div :for={scan <- @scanned_tags} class="flex items-center justify-between bg-white p-2 rounded border">
<div :for={scan <- @scanned_tags} class="flex items-center justify-between bg-base-100 p-2 rounded border border-base-300">
<div>
<span class="font-medium text-gray-900">{location_display_name(scan.location)}</span>
<span class="text-sm text-gray-600 ml-2">(AprilTag ID {scan.apriltag_id})</span>
<span class="font-medium text-base-content">{location_display_name(scan.location)}</span>
<span class="text-sm text-base-content/70 ml-2">(AprilTag ID {scan.apriltag_id})</span>
</div>
<span class="text-xs text-green-600 bg-green-100 px-2 py-1 rounded">
Level {scan.location.level}
@@ -776,17 +776,17 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
<!-- Storage Locations List -->
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<div class="bg-white shadow overflow-hidden sm:rounded-md">
<div class="px-6 py-4 border-b border-gray-200">
<h2 class="text-lg font-medium text-gray-900">Storage Location Hierarchy</h2>
<p class="text-sm text-gray-500 mt-1">Manage your physical storage locations and AprilTags</p>
<div class="bg-base-100 shadow overflow-hidden sm:rounded-md">
<div class="px-6 py-4 border-b border-base-300">
<h2 class="text-lg font-medium text-base-content">Storage Location Hierarchy</h2>
<p class="text-sm text-base-content/60 mt-1">Manage your physical storage locations and AprilTags</p>
</div>
<%= if Enum.empty?(@storage_locations) do %>
<div class="text-center py-12">
<.icon name="hero-building-office" class="mx-auto h-12 w-12 text-gray-400" />
<h3 class="mt-2 text-sm font-medium text-gray-900">No storage locations</h3>
<p class="mt-1 text-sm text-gray-500">
<.icon name="hero-building-office" class="mx-auto h-12 w-12 text-base-content/50" />
<h3 class="mt-2 text-sm font-medium text-base-content">No storage locations</h3>
<p class="mt-1 text-sm text-base-content/60">
Get started by creating your first storage location.
</p>
<div class="mt-6">
@@ -800,7 +800,7 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
</div>
</div>
<% else %>
<div class="divide-y divide-gray-200">
<div class="divide-y divide-base-300">
<!-- Recursive Storage Location Tree -->
<%= for location <- root_storage_locations(@storage_locations) do %>
<div class="px-6 py-4">