feat(elixir): proper dark/light mode support
This commit is contained in:
@@ -102,4 +102,39 @@
|
||||
/* Make LiveView wrapper divs transparent for layout */
|
||||
[data-phx-session], [data-phx-teleported-src] { display: contents }
|
||||
|
||||
/* Modal enhancements for better theme support */
|
||||
.modal-backdrop {
|
||||
background-color: var(--color-base-content);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: var(--color-base-100);
|
||||
border-color: var(--color-base-300);
|
||||
color: var(--color-base-content);
|
||||
}
|
||||
|
||||
/* Ensure input field styling works properly in modals */
|
||||
.modal-content input,
|
||||
.modal-content textarea,
|
||||
.modal-content select {
|
||||
background-color: var(--color-base-100);
|
||||
border-color: var(--color-base-300);
|
||||
color: var(--color-base-content);
|
||||
}
|
||||
|
||||
.modal-content input::placeholder,
|
||||
.modal-content textarea::placeholder {
|
||||
color: var(--color-base-content);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* Focus states for inputs in modals */
|
||||
.modal-content input:focus,
|
||||
.modal-content textarea:focus,
|
||||
.modal-content select:focus {
|
||||
border-color: var(--color-primary);
|
||||
outline-color: var(--color-primary);
|
||||
}
|
||||
|
||||
/* This file is for your main application CSS */
|
||||
|
||||
@@ -188,14 +188,14 @@ defmodule ComponentsElixirWeb.CoreComponents do
|
||||
<div class="fieldset mb-2">
|
||||
<label>
|
||||
<input type="hidden" name={@name} value="false" disabled={@rest[:disabled]} />
|
||||
<span class="label">
|
||||
<span class="label text-base-content">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={@id}
|
||||
name={@name}
|
||||
value="true"
|
||||
checked={@checked}
|
||||
class={@class || "checkbox checkbox-sm"}
|
||||
class={@class || "checkbox checkbox-sm border-base-300 checked:bg-primary checked:border-primary"}
|
||||
{@rest}
|
||||
/>{@label}
|
||||
</span>
|
||||
@@ -209,11 +209,11 @@ defmodule ComponentsElixirWeb.CoreComponents do
|
||||
~H"""
|
||||
<div class="fieldset mb-2">
|
||||
<label>
|
||||
<span :if={@label} class="label mb-1">{@label}</span>
|
||||
<span :if={@label} class="label mb-1 text-base-content">{@label}</span>
|
||||
<select
|
||||
id={@id}
|
||||
name={@name}
|
||||
class={[@class || "w-full select", @errors != [] && (@error_class || "select-error")]}
|
||||
class={[@class || "w-full select bg-base-100 border-base-300 text-base-content", @errors != [] && (@error_class || "select-error border-error")]}
|
||||
multiple={@multiple}
|
||||
{@rest}
|
||||
>
|
||||
@@ -230,13 +230,13 @@ defmodule ComponentsElixirWeb.CoreComponents do
|
||||
~H"""
|
||||
<div class="fieldset mb-2">
|
||||
<label>
|
||||
<span :if={@label} class="label mb-1">{@label}</span>
|
||||
<span :if={@label} class="label mb-1 text-base-content">{@label}</span>
|
||||
<textarea
|
||||
id={@id}
|
||||
name={@name}
|
||||
class={[
|
||||
@class || "w-full textarea",
|
||||
@errors != [] && (@error_class || "textarea-error")
|
||||
@class || "w-full textarea bg-base-100 border-base-300 text-base-content placeholder:text-base-content/50",
|
||||
@errors != [] && (@error_class || "textarea-error border-error")
|
||||
]}
|
||||
{@rest}
|
||||
>{Phoenix.HTML.Form.normalize_value("textarea", @value)}</textarea>
|
||||
@@ -251,15 +251,15 @@ defmodule ComponentsElixirWeb.CoreComponents do
|
||||
~H"""
|
||||
<div class="fieldset mb-2">
|
||||
<label>
|
||||
<span :if={@label} class="label mb-1">{@label}</span>
|
||||
<span :if={@label} class="label mb-1 text-base-content">{@label}</span>
|
||||
<input
|
||||
type={@type}
|
||||
name={@name}
|
||||
id={@id}
|
||||
value={Phoenix.HTML.Form.normalize_value(@type, @value)}
|
||||
class={[
|
||||
@class || "w-full input",
|
||||
@errors != [] && (@error_class || "input-error")
|
||||
@class || "w-full input bg-base-100 border-base-300 text-base-content placeholder:text-base-content/50",
|
||||
@errors != [] && (@error_class || "input-error border-error")
|
||||
]}
|
||||
{@rest}
|
||||
/>
|
||||
|
||||
@@ -172,7 +172,7 @@ defmodule ComponentsElixirWeb.CategoriesLive 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
|
||||
@@ -195,17 +195,17 @@ defmodule ComponentsElixirWeb.CategoriesLive do
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center">
|
||||
<.icon name="hero-folder" class={"#{@icon_size} #{if @depth == 0, do: "text-indigo-500", else: "text-gray-400"} mr-3"} />
|
||||
<.icon name="hero-folder" class={"#{@icon_size} #{if @depth == 0, do: "text-primary", else: "text-base-content/60"} mr-3"} />
|
||||
<div>
|
||||
<%= if @title_tag == "h3" do %>
|
||||
<h3 class={"#{@text_size} font-medium #{if @depth == 0, do: "text-gray-900", else: "text-gray-700"}"}>{@category.name}</h3>
|
||||
<h3 class={"#{@text_size} font-medium #{if @depth == 0, do: "text-base-content", else: "text-base-content/80"}"}>{@category.name}</h3>
|
||||
<% else %>
|
||||
<h4 class={"#{@text_size} font-medium #{if @depth == 0, do: "text-gray-900", else: "text-gray-700"}"}>{@category.name}</h4>
|
||||
<h4 class={"#{@text_size} font-medium #{if @depth == 0, do: "text-base-content", else: "text-base-content/80"}"}>{@category.name}</h4>
|
||||
<% end %>
|
||||
<%= if @category.description do %>
|
||||
<p class="text-sm text-gray-500 mt-1">{@category.description}</p>
|
||||
<p class="text-sm text-base-content/60 mt-1">{@category.description}</p>
|
||||
<% end %>
|
||||
<p class="text-xs text-gray-400 mt-1">
|
||||
<p class="text-xs text-base-content/50 mt-1">
|
||||
{count_components_in_category(@category.id)} components
|
||||
</p>
|
||||
</div>
|
||||
@@ -240,19 +240,19 @@ defmodule ComponentsElixirWeb.CategoriesLive 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">
|
||||
Category Management
|
||||
</h1>
|
||||
</div>
|
||||
@@ -265,7 +265,7 @@ defmodule ComponentsElixirWeb.CategoriesLive 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>
|
||||
@@ -276,14 +276,14 @@ defmodule ComponentsElixirWeb.CategoriesLive do
|
||||
|
||||
<!-- Add Category 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 Category</h3>
|
||||
<h3 class="text-lg font-medium text-base-content">Add New Category</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>
|
||||
@@ -291,12 +291,12 @@ defmodule ComponentsElixirWeb.CategoriesLive do
|
||||
|
||||
<.form for={@form} phx-submit="save_category" 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 Category</label>
|
||||
<label class="block text-sm font-medium text-base-content">Parent Category</label>
|
||||
<.input
|
||||
field={@form[:parent_id]}
|
||||
type="select"
|
||||
@@ -305,7 +305,7 @@ defmodule ComponentsElixirWeb.CategoriesLive 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>
|
||||
|
||||
@@ -313,13 +313,13 @@ defmodule ComponentsElixirWeb.CategoriesLive 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 Category
|
||||
</button>
|
||||
@@ -332,14 +332,14 @@ defmodule ComponentsElixirWeb.CategoriesLive do
|
||||
|
||||
<!-- Edit Category 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 Category</h3>
|
||||
<h3 class="text-lg font-medium text-base-content">Edit Category</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>
|
||||
@@ -347,12 +347,12 @@ defmodule ComponentsElixirWeb.CategoriesLive 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 Category</label>
|
||||
<label class="block text-sm font-medium text-base-content">Parent Category</label>
|
||||
<.input
|
||||
field={@form[:parent_id]}
|
||||
type="select"
|
||||
@@ -361,7 +361,7 @@ defmodule ComponentsElixirWeb.CategoriesLive 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>
|
||||
|
||||
@@ -369,13 +369,13 @@ defmodule ComponentsElixirWeb.CategoriesLive 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 Category
|
||||
</button>
|
||||
@@ -388,17 +388,17 @@ defmodule ComponentsElixirWeb.CategoriesLive do
|
||||
|
||||
<!-- Categories 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">Category Hierarchy</h2>
|
||||
<p class="text-sm text-gray-500 mt-1">Manage your component categories and subcategories</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">Category Hierarchy</h2>
|
||||
<p class="text-sm text-base-content/60 mt-1">Manage your component categories and subcategories</p>
|
||||
</div>
|
||||
|
||||
<%= if Enum.empty?(@categories) do %>
|
||||
<div class="text-center py-12">
|
||||
<.icon name="hero-folder-open" class="mx-auto h-12 w-12 text-gray-400" />
|
||||
<h3 class="mt-2 text-sm font-medium text-gray-900">No categories</h3>
|
||||
<p class="mt-1 text-sm text-gray-500">
|
||||
<.icon name="hero-folder-open" class="mx-auto h-12 w-12 text-base-content/50" />
|
||||
<h3 class="mt-2 text-sm font-medium text-base-content">No categories</h3>
|
||||
<p class="mt-1 text-sm text-base-content/60">
|
||||
Get started by creating your first category.
|
||||
</p>
|
||||
<div class="mt-6">
|
||||
@@ -412,7 +412,7 @@ defmodule ComponentsElixirWeb.CategoriesLive do
|
||||
</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="divide-y divide-gray-200">
|
||||
<div class="divide-y divide-base-300">
|
||||
<!-- Recursive Category Tree -->
|
||||
<%= for category <- root_categories(@categories) do %>
|
||||
<div class="px-6 py-4">
|
||||
|
||||
@@ -319,16 +319,16 @@ defmodule ComponentsElixirWeb.ComponentsLive 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">
|
||||
<h1 class="text-3xl font-bold text-gray-900">
|
||||
<h1 class="text-3xl font-bold text-base-content">
|
||||
Components Inventory
|
||||
</h1>
|
||||
<div class="ml-8 text-sm text-gray-500">
|
||||
<div class="ml-8 text-sm text-base-content/60">
|
||||
{@stats.total_components} components • {@stats.total_stock} items in stock
|
||||
</div>
|
||||
</div>
|
||||
@@ -341,20 +341,20 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
</button>
|
||||
<.link
|
||||
navigate={~p"/categories"}
|
||||
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-folder" class="w-4 h-4 mr-2" /> Categories
|
||||
</.link>
|
||||
<.link
|
||||
navigate={~p"/storage_locations"}
|
||||
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-archive-box" class="w-4 h-4 mr-2" /> Storage
|
||||
</.link>
|
||||
<.link
|
||||
href="/logout"
|
||||
method="post"
|
||||
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-arrow-right-on-rectangle" class="w-4 h-4 mr-2" /> Logout
|
||||
</.link>
|
||||
@@ -373,7 +373,7 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
name="search"
|
||||
value={@search}
|
||||
placeholder="Search components..."
|
||||
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||
class="block w-full px-3 py-2 border border-base-300 rounded-md shadow-sm bg-base-100 text-base-content focus:outline-none focus:ring-primary focus:border-primary sm:text-sm"
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
@@ -381,7 +381,7 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
<form phx-change="category_filter">
|
||||
<select
|
||||
name="category_id"
|
||||
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||
class="block w-full px-3 py-2 border border-base-300 rounded-md shadow-sm bg-base-100 text-base-content focus:outline-none focus:ring-primary focus:border-primary sm:text-sm"
|
||||
>
|
||||
<option value="" selected={is_nil(@selected_category)}>All Categories</option>
|
||||
<%= for category <- @categories do %>
|
||||
@@ -400,7 +400,7 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
<form phx-change="sort_change">
|
||||
<select
|
||||
name="sort_criteria"
|
||||
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||
class="block w-full px-3 py-2 border border-base-300 rounded-md shadow-sm bg-base-100 text-base-content focus:outline-none focus:ring-primary focus:border-primary sm:text-sm"
|
||||
>
|
||||
<option value="all_not_id" selected={@sort_criteria == "all_not_id"}>
|
||||
All (without IDs)
|
||||
@@ -422,14 +422,14 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
|
||||
<!-- Add Component 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 Component</h3>
|
||||
<h3 class="text-lg font-medium text-base-content">Add New Component</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>
|
||||
@@ -437,12 +437,12 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
|
||||
<.form for={@form} phx-submit="save_component" phx-change="validate" multipart={true} 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">Category</label>
|
||||
<label class="block text-sm font-medium text-base-content">Category</label>
|
||||
<.input
|
||||
field={@form[:category_id]}
|
||||
type="select"
|
||||
@@ -452,17 +452,17 @@ defmodule ComponentsElixirWeb.ComponentsLive 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 class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Keywords</label>
|
||||
<label class="block text-sm font-medium text-base-content">Keywords</label>
|
||||
<.input field={@form[:keywords]} type="text" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Storage Location</label>
|
||||
<label class="block text-sm font-medium text-base-content">Storage Location</label>
|
||||
<.input
|
||||
field={@form[:storage_location_id]}
|
||||
type="select"
|
||||
@@ -473,26 +473,26 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Count</label>
|
||||
<label class="block text-sm font-medium text-base-content">Count</label>
|
||||
<.input field={@form[:count]} type="number" min="0" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Datasheet URL</label>
|
||||
<label class="block text-sm font-medium text-base-content">Datasheet URL</label>
|
||||
<.input field={@form[:datasheet_url]} type="url" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Component Image</label>
|
||||
<label class="block text-sm font-medium text-base-content">Component Image</label>
|
||||
<div class="mt-1">
|
||||
<.live_file_input upload={@uploads.image} class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100" />
|
||||
<.live_file_input upload={@uploads.image} class="block w-full text-sm text-base-content file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-primary/10 file:text-primary hover:file:bg-primary/20" />
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-gray-500">
|
||||
<p class="mt-1 text-xs text-base-content/60">
|
||||
JPG, PNG, GIF up to 5MB
|
||||
</p>
|
||||
|
||||
<%= for err <- upload_errors(@uploads.image) do %>
|
||||
<p class="text-red-600 text-sm mt-1"><%= Phoenix.Naming.humanize(err) %></p>
|
||||
<p class="text-error text-sm mt-1"><%= Phoenix.Naming.humanize(err) %></p>
|
||||
<% end %>
|
||||
|
||||
<%= for entry <- @uploads.image.entries do %>
|
||||
@@ -502,17 +502,17 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
<.live_img_preview entry={entry} class="h-10 w-10 rounded-lg object-cover" />
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium text-gray-900"><%= entry.client_name %></p>
|
||||
<p class="text-sm text-gray-500"><%= entry.progress %>%</p>
|
||||
<p class="text-sm font-medium text-base-content"><%= entry.client_name %></p>
|
||||
<p class="text-sm text-base-content/60"><%= entry.progress %>%</p>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" phx-click="cancel-upload" phx-value-ref={entry.ref} aria-label="cancel" class="text-red-600 hover:text-red-900">
|
||||
<button type="button" phx-click="cancel-upload" phx-value-ref={entry.ref} aria-label="cancel" class="text-error hover:text-error/80">
|
||||
<.icon name="hero-x-mark" class="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= for err <- upload_errors(@uploads.image) do %>
|
||||
<p class="mt-1 text-sm text-red-600"><%= upload_error_to_string(err) %></p>
|
||||
<p class="mt-1 text-sm text-error"><%= upload_error_to_string(err) %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@@ -520,13 +520,13 @@ defmodule ComponentsElixirWeb.ComponentsLive 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 Component
|
||||
</button>
|
||||
@@ -539,14 +539,14 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
|
||||
<!-- Edit Component 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 Component</h3>
|
||||
<h3 class="text-lg font-medium text-base-content">Edit Component</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>
|
||||
@@ -554,12 +554,12 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
|
||||
<.form for={@form} phx-submit="save_edit" phx-change="validate" multipart={true} 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">Category</label>
|
||||
<label class="block text-sm font-medium text-base-content">Category</label>
|
||||
<.input
|
||||
field={@form[:category_id]}
|
||||
type="select"
|
||||
@@ -569,17 +569,17 @@ defmodule ComponentsElixirWeb.ComponentsLive 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 class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Keywords</label>
|
||||
<label class="block text-sm font-medium text-base-content">Keywords</label>
|
||||
<.input field={@form[:keywords]} type="text" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Storage Location</label>
|
||||
<label class="block text-sm font-medium text-base-content">Storage Location</label>
|
||||
<.input
|
||||
field={@form[:storage_location_id]}
|
||||
type="select"
|
||||
@@ -590,32 +590,32 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Count</label>
|
||||
<label class="block text-sm font-medium text-base-content">Count</label>
|
||||
<.input field={@form[:count]} type="number" min="0" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Datasheet URL</label>
|
||||
<label class="block text-sm font-medium text-base-content">Datasheet URL</label>
|
||||
<.input field={@form[:datasheet_url]} type="url" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Component Image</label>
|
||||
<label class="block text-sm font-medium text-base-content">Component Image</label>
|
||||
<%= if @editing_component && @editing_component.image_filename do %>
|
||||
<div class="mt-1 mb-2">
|
||||
<p class="text-sm text-gray-600">Current image:</p>
|
||||
<p class="text-sm text-base-content/70">Current image:</p>
|
||||
<img src={"/user_generated/uploads/images/#{@editing_component.image_filename}"} alt="Current component" class="h-20 w-20 object-cover rounded-lg" />
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="mt-1">
|
||||
<.live_file_input upload={@uploads.image} class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100" />
|
||||
<.live_file_input upload={@uploads.image} class="block w-full text-sm text-base-content file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-primary/10 file:text-primary hover:file:bg-primary/20" />
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-gray-500">
|
||||
<p class="mt-1 text-xs text-base-content/60">
|
||||
JPG, PNG, GIF up to 5MB (leave empty to keep current image)
|
||||
</p>
|
||||
|
||||
<%= for err <- upload_errors(@uploads.image) do %>
|
||||
<p class="text-red-600 text-sm mt-1"><%= Phoenix.Naming.humanize(err) %></p>
|
||||
<p class="text-error text-sm mt-1"><%= Phoenix.Naming.humanize(err) %></p>
|
||||
<% end %>
|
||||
|
||||
<%= for entry <- @uploads.image.entries do %>
|
||||
@@ -625,17 +625,17 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
<.live_img_preview entry={entry} class="h-10 w-10 rounded-lg object-cover" />
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium text-gray-900"><%= entry.client_name %></p>
|
||||
<p class="text-sm text-gray-500"><%= entry.progress %>%</p>
|
||||
<p class="text-sm font-medium text-base-content"><%= entry.client_name %></p>
|
||||
<p class="text-sm text-base-content/60"><%= entry.progress %>%</p>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" phx-click="cancel-upload" phx-value-ref={entry.ref} aria-label="cancel" class="text-red-600 hover:text-red-900">
|
||||
<button type="button" phx-click="cancel-upload" phx-value-ref={entry.ref} aria-label="cancel" class="text-error hover:text-error/80">
|
||||
<.icon name="hero-x-mark" class="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= for err <- upload_errors(@uploads.image) do %>
|
||||
<p class="mt-1 text-sm text-red-600"><%= upload_error_to_string(err) %></p>
|
||||
<p class="mt-1 text-sm text-error"><%= upload_error_to_string(err) %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@@ -643,13 +643,13 @@ defmodule ComponentsElixirWeb.ComponentsLive 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 Component
|
||||
</button>
|
||||
@@ -662,10 +662,10 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
|
||||
<!-- Components List -->
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pb-6">
|
||||
<div class="bg-white shadow overflow-hidden sm:rounded-md">
|
||||
<ul class="divide-y divide-gray-200" id="components-list" phx-update="replace">
|
||||
<div class="bg-base-100 shadow overflow-hidden sm:rounded-md">
|
||||
<ul class="divide-y divide-base-300" id="components-list" phx-update="replace">
|
||||
<%= for component <- @components do %>
|
||||
<li id={"component-#{component.id}"} class="px-6 py-4 hover:bg-gray-50">
|
||||
<li id={"component-#{component.id}"} class="px-6 py-4 hover:bg-base-200">
|
||||
<div class="flex items-center justify-between">
|
||||
<!-- Component Image -->
|
||||
<div class="flex-shrink-0 mr-4">
|
||||
@@ -674,8 +674,8 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
<img src={"/user_generated/uploads/images/#{component.image_filename}"} alt={component.name} class="h-12 w-12 rounded-lg object-cover cursor-pointer" />
|
||||
</button>
|
||||
<% else %>
|
||||
<div class="h-12 w-12 rounded-lg bg-gray-200 flex items-center justify-center">
|
||||
<.icon name="hero-cube-transparent" class="h-6 w-6 text-gray-400" />
|
||||
<div class="h-12 w-12 rounded-lg bg-base-200 flex items-center justify-center">
|
||||
<.icon name="hero-cube-transparent" class="h-6 w-6 text-base-content/50" />
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -684,12 +684,12 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
<!-- Top row: Name and Category -->
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="flex items-center min-w-0 flex-1">
|
||||
<p class="text-sm font-medium text-indigo-600 truncate">
|
||||
<p class="text-sm font-medium text-primary truncate">
|
||||
<%= if component.datasheet_url do %>
|
||||
<a
|
||||
href={component.datasheet_url}
|
||||
target="_blank"
|
||||
class="hover:text-indigo-500"
|
||||
class="hover:text-primary/80"
|
||||
>
|
||||
{component.name}
|
||||
</a>
|
||||
@@ -698,7 +698,7 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
<% end %>
|
||||
</p>
|
||||
<%= if component.datasheet_url do %>
|
||||
<span class="ml-2 text-blue-500" title="Datasheet available">📄</span>
|
||||
<span class="ml-2 text-primary" title="Datasheet available">📄</span>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="ml-4 flex-shrink-0">
|
||||
@@ -711,29 +711,29 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
<!-- Middle row: Description -->
|
||||
<%= if component.description do %>
|
||||
<div class="mt-1">
|
||||
<p class="text-sm text-gray-500 line-clamp-2">
|
||||
<p class="text-sm text-base-content/70 line-clamp-2">
|
||||
{component.description}
|
||||
</p>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<!-- Bottom row: Metadata -->
|
||||
<div class="mt-2 grid grid-cols-1 sm:grid-cols-3 gap-x-4 gap-y-1 text-sm text-gray-500">
|
||||
<div class="mt-2 grid grid-cols-1 sm:grid-cols-3 gap-x-4 gap-y-1 text-sm text-base-content/60">
|
||||
<%= if component.storage_location do %>
|
||||
<div class="flex items-center min-w-0">
|
||||
<.icon name="hero-map-pin" class="w-4 h-4 mr-1 text-gray-400 flex-shrink-0" />
|
||||
<.icon name="hero-map-pin" class="w-4 h-4 mr-1 text-base-content/50 flex-shrink-0" />
|
||||
<span class="font-medium">Location:</span>
|
||||
<span class="ml-1 truncate">{storage_location_display_name(component.storage_location)}</span>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="flex items-center">
|
||||
<.icon name="hero-cube" class="w-4 h-4 mr-1 text-gray-400" />
|
||||
<.icon name="hero-cube" class="w-4 h-4 mr-1 text-base-content/50" />
|
||||
<span class="font-medium">Count:</span>
|
||||
<span class="ml-1">{component.count}</span>
|
||||
</div>
|
||||
<%= if @sort_criteria == "all" or @sort_criteria == "id" do %>
|
||||
<div class="flex items-center">
|
||||
<.icon name="hero-hashtag" class="w-4 h-4 mr-1 text-gray-400" />
|
||||
<.icon name="hero-hashtag" class="w-4 h-4 mr-1 text-base-content/50" />
|
||||
<span class="font-medium">ID:</span>
|
||||
<span class="ml-1">{component.id}</span>
|
||||
</div>
|
||||
@@ -743,7 +743,7 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
<!-- Keywords row -->
|
||||
<%= if component.keywords do %>
|
||||
<div class="mt-2">
|
||||
<p class="text-xs text-gray-400">
|
||||
<p class="text-xs text-base-content/50">
|
||||
<span class="font-medium">Keywords:</span> {component.keywords}
|
||||
</p>
|
||||
</div>
|
||||
@@ -789,7 +789,7 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
<div class="bg-white px-4 py-3 flex items-center justify-center border-t border-gray-200">
|
||||
<button
|
||||
phx-click="load_more"
|
||||
class="relative 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"
|
||||
class="relative 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"
|
||||
>
|
||||
Load More
|
||||
</button>
|
||||
@@ -798,9 +798,9 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
|
||||
<%= if Enum.empty?(@components) do %>
|
||||
<div class="text-center py-12">
|
||||
<.icon name="hero-cube-transparent" class="mx-auto h-12 w-12 text-gray-400" />
|
||||
<h3 class="mt-2 text-sm font-medium text-gray-900">No components found</h3>
|
||||
<p class="mt-1 text-sm text-gray-500">
|
||||
<.icon name="hero-cube-transparent" class="mx-auto h-12 w-12 text-base-content/50" />
|
||||
<h3 class="mt-2 text-sm font-medium text-base-content">No components found</h3>
|
||||
<p class="mt-1 text-sm text-base-content/60">
|
||||
<%= if @search != "" do %>
|
||||
Try adjusting your search terms.
|
||||
<% else %>
|
||||
@@ -820,13 +820,13 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
<div class="absolute inset-0 bg-black bg-opacity-75"></div>
|
||||
|
||||
<!-- Modal content -->
|
||||
<div class="relative bg-white rounded-lg shadow-xl max-w-4xl w-full max-h-full overflow-auto" phx-click="prevent_close">
|
||||
<div class="relative bg-base-100 rounded-lg shadow-xl max-w-4xl w-full max-h-full overflow-auto" phx-click="prevent_close">
|
||||
<!-- Header -->
|
||||
<div class="flex justify-between items-center p-4 border-b bg-white rounded-t-lg">
|
||||
<h3 class="text-lg font-semibold text-gray-900">Component Image</h3>
|
||||
<div class="flex justify-between items-center p-4 border-b border-base-300 bg-base-100 rounded-t-lg">
|
||||
<h3 class="text-lg font-semibold text-base-content">Component Image</h3>
|
||||
<button
|
||||
type="button"
|
||||
class="text-gray-400 hover:text-gray-600 text-3xl font-bold leading-none p-1"
|
||||
class="text-base-content/50 hover:text-base-content text-3xl font-bold leading-none p-1"
|
||||
phx-click="close_image_modal"
|
||||
title="Close"
|
||||
>
|
||||
@@ -835,7 +835,7 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="p-6 bg-white rounded-b-lg">
|
||||
<div class="p-6 bg-base-100 rounded-b-lg">
|
||||
<div class="text-center">
|
||||
<%= if @modal_image_url do %>
|
||||
<img
|
||||
@@ -845,7 +845,7 @@ defmodule ComponentsElixirWeb.ComponentsLive do
|
||||
style="object-fit: contain;"
|
||||
/>
|
||||
<% else %>
|
||||
<p class="text-gray-500 py-8">No image available</p>
|
||||
<p class="text-base-content/60 py-8">No image available</p>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -38,13 +38,13 @@ defmodule ComponentsElixirWeb.LoginLive do
|
||||
@impl true
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<div class="min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div class="min-h-screen flex items-center justify-center bg-base-200 py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div class="max-w-md w-full space-y-8">
|
||||
<div>
|
||||
<h2 class="mt-6 text-center text-3xl font-extrabold text-gray-900">
|
||||
<h2 class="mt-6 text-center text-3xl font-extrabold text-base-content">
|
||||
Components Inventory
|
||||
</h2>
|
||||
<p class="mt-2 text-center text-sm text-gray-600">
|
||||
<p class="mt-2 text-center text-sm text-base-content/70">
|
||||
Please enter your password to continue
|
||||
</p>
|
||||
</div>
|
||||
@@ -57,7 +57,7 @@ defmodule ComponentsElixirWeb.LoginLive do
|
||||
name="password"
|
||||
type="password"
|
||||
required
|
||||
class="appearance-none rounded-md relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm"
|
||||
class="appearance-none rounded-md relative block w-full px-3 py-2 border border-base-300 placeholder-base-content/50 text-base-content bg-base-100 focus:outline-none focus:ring-primary focus:border-primary focus:z-10 sm:text-sm"
|
||||
placeholder="Password"
|
||||
autocomplete="current-password"
|
||||
value={@form[:password].value}
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user