move branding settings from Theme tab to Site tab
Some checks failed
deploy / deploy (push) Failing after 10m13s
Some checks failed
deploy / deploy (push) Failing after 10m13s
- Add branding_editor component to site_editor.ex with: - Shop name input - Show shop name / Show logo toggles - Logo upload (size slider, SVG recolor, color picker) - Header background toggle and upload (zoom, position sliders) - Add site_ prefixed event handlers in page_editor_hook.ex: - site_update_branding, site_toggle_branding, site_update_color - site_remove_logo and site_remove_header (delegate to theme handlers) - Remove branding sections from theme_editor.ex: - Deleted shop_name_input, branding_section, logo/header upload sections - Theme tab now shows only: preset grid, accent colours, customise accordion Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -24,10 +24,18 @@ defmodule BerrypodWeb.ShopComponents.SiteEditor do
|
||||
Expects:
|
||||
- site_state: SiteEditorState struct with all site tab state
|
||||
- site_nav_pages: list of pages for the nav picker
|
||||
- Branding-related props passed from theme state
|
||||
"""
|
||||
attr :site_state, :any, required: true
|
||||
attr :site_nav_pages, :list, default: []
|
||||
attr :event_prefix, :string, default: "site_"
|
||||
attr :site_name, :string, default: ""
|
||||
attr :theme_settings, :map, default: nil
|
||||
attr :logo_image, :map, default: nil
|
||||
attr :header_image, :map, default: nil
|
||||
attr :icon_image, :map, default: nil
|
||||
attr :contrast_warning, :atom, default: :ok
|
||||
attr :uploads, :map, default: nil
|
||||
|
||||
def site_editor(%{site_state: nil} = assigns) do
|
||||
~H"""
|
||||
@@ -60,7 +68,16 @@ defmodule BerrypodWeb.ShopComponents.SiteEditor do
|
||||
~H"""
|
||||
<div class="editor-site-content">
|
||||
<.site_section title="Branding" icon="hero-sparkles" open={true}>
|
||||
<.branding_placeholder />
|
||||
<.branding_editor
|
||||
site_name={@site_name}
|
||||
theme_settings={@theme_settings}
|
||||
logo_image={@logo_image}
|
||||
header_image={@header_image}
|
||||
icon_image={@icon_image}
|
||||
contrast_warning={@contrast_warning}
|
||||
uploads={@uploads}
|
||||
event_prefix={@event_prefix}
|
||||
/>
|
||||
</.site_section>
|
||||
|
||||
<.site_section title="Announcement bar" icon="hero-megaphone">
|
||||
@@ -128,19 +145,356 @@ defmodule BerrypodWeb.ShopComponents.SiteEditor do
|
||||
"""
|
||||
end
|
||||
|
||||
# ── Branding Section (placeholder) ─────────────────────────────────
|
||||
# ── Branding Editor ─────────────────────────────────────────────────
|
||||
|
||||
defp branding_placeholder(assigns) do
|
||||
attr :site_name, :string, default: ""
|
||||
attr :theme_settings, :map, default: nil
|
||||
attr :logo_image, :map, default: nil
|
||||
attr :header_image, :map, default: nil
|
||||
attr :icon_image, :map, default: nil
|
||||
attr :contrast_warning, :atom, default: :ok
|
||||
attr :uploads, :map, default: nil
|
||||
attr :event_prefix, :string, default: "site_"
|
||||
|
||||
defp branding_editor(%{theme_settings: nil} = assigns) do
|
||||
~H"""
|
||||
<div class="site-editor-placeholder">
|
||||
<p class="admin-text-secondary">
|
||||
Branding settings (shop name, logo, favicon) will be moved here from the Theme tab.
|
||||
</p>
|
||||
<p class="admin-help-text">Coming soon in the next phase.</p>
|
||||
<p class="admin-text-secondary">Loading branding settings...</p>
|
||||
"""
|
||||
end
|
||||
|
||||
defp branding_editor(assigns) do
|
||||
~H"""
|
||||
<div class="site-editor-form">
|
||||
<%!-- Shop name --%>
|
||||
<div class="theme-section">
|
||||
<label class="theme-section-label">Shop name</label>
|
||||
<form phx-change={@event_prefix <> "update_branding"} phx-value-field="site_name">
|
||||
<input
|
||||
type="text"
|
||||
name="site_name"
|
||||
value={@site_name}
|
||||
placeholder="Your shop name"
|
||||
class="admin-input"
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<%!-- Display toggles --%>
|
||||
<div class="admin-stack admin-stack-sm theme-field">
|
||||
<label class="admin-check-label">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={@theme_settings.show_site_name}
|
||||
phx-click={@event_prefix <> "toggle_branding"}
|
||||
phx-value-field="show_site_name"
|
||||
class="admin-checkbox admin-checkbox-sm"
|
||||
/>
|
||||
<span class="theme-check-text">Show shop name</span>
|
||||
</label>
|
||||
|
||||
<label class="admin-check-label">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={@theme_settings.show_logo}
|
||||
phx-click={@event_prefix <> "toggle_branding"}
|
||||
phx-value-field="show_logo"
|
||||
class="admin-checkbox admin-checkbox-sm"
|
||||
/>
|
||||
<span class="theme-check-text">Show logo</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<%!-- Logo upload section --%>
|
||||
<%= if @theme_settings.show_logo && @uploads do %>
|
||||
<.logo_upload_section
|
||||
uploads={@uploads}
|
||||
logo_image={@logo_image}
|
||||
theme_settings={@theme_settings}
|
||||
site_name={@site_name}
|
||||
event_prefix={@event_prefix}
|
||||
/>
|
||||
<% end %>
|
||||
|
||||
<%!-- Header background toggle --%>
|
||||
<label class="admin-check-label theme-field">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={@theme_settings.header_background_enabled}
|
||||
phx-click={@event_prefix <> "update_branding"}
|
||||
phx-value-field="header_background_enabled"
|
||||
phx-value-setting_value={
|
||||
if @theme_settings.header_background_enabled, do: "false", else: "true"
|
||||
}
|
||||
class="admin-checkbox admin-checkbox-sm"
|
||||
/>
|
||||
<span class="theme-check-text">Header background image</span>
|
||||
</label>
|
||||
|
||||
<%!-- Header upload section --%>
|
||||
<%= if @theme_settings.header_background_enabled && @uploads do %>
|
||||
<.header_upload_section
|
||||
uploads={@uploads}
|
||||
header_image={@header_image}
|
||||
theme_settings={@theme_settings}
|
||||
contrast_warning={@contrast_warning}
|
||||
event_prefix={@event_prefix}
|
||||
/>
|
||||
<% end %>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
# Logo upload sub-section
|
||||
attr :uploads, :map, required: true
|
||||
attr :logo_image, :map, default: nil
|
||||
attr :theme_settings, :map, required: true
|
||||
attr :site_name, :string, default: ""
|
||||
attr :event_prefix, :string, default: "site_"
|
||||
|
||||
defp logo_upload_section(assigns) do
|
||||
~H"""
|
||||
<div class="theme-subsection">
|
||||
<span class="theme-slider-label theme-block-label">Upload logo (SVG or PNG)</span>
|
||||
<div class="admin-row admin-row-lg">
|
||||
<form phx-change="noop" phx-submit="noop" class="admin-fill">
|
||||
<label class="theme-upload-label theme-upload-label-compact">
|
||||
<span>Choose file...</span>
|
||||
<.live_file_input upload={@uploads.theme_logo_upload} class="hidden" />
|
||||
</label>
|
||||
</form>
|
||||
<%= if @logo_image do %>
|
||||
<div class="theme-thumb theme-thumb-logo theme-thumb-compact">
|
||||
<img src={"/image_cache/#{@logo_image.id}.webp"} alt={@site_name} />
|
||||
<button
|
||||
type="button"
|
||||
phx-click={@event_prefix <> "remove_logo"}
|
||||
class="theme-remove-btn"
|
||||
title="Remove logo"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<%= for entry <- @uploads.theme_logo_upload.entries do %>
|
||||
<.upload_progress entry={entry} upload_name="theme_logo_upload" />
|
||||
<%= for err <- upload_errors(@uploads.theme_logo_upload, entry) do %>
|
||||
<p class="theme-error-text">{error_to_string(err)}</p>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%= for err <- upload_errors(@uploads.theme_logo_upload) do %>
|
||||
<p class="theme-error-text">{error_to_string(err)}</p>
|
||||
<% end %>
|
||||
|
||||
<%= if @logo_image do %>
|
||||
<form
|
||||
phx-change={@event_prefix <> "update_branding"}
|
||||
phx-value-field="logo_size"
|
||||
class="theme-subfield"
|
||||
>
|
||||
<div class="theme-slider-header">
|
||||
<span class="theme-slider-label">Logo size</span>
|
||||
<span class="theme-slider-value">{@theme_settings.logo_size}px</span>
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
min="24"
|
||||
max="120"
|
||||
value={@theme_settings.logo_size}
|
||||
name="logo_size"
|
||||
class="admin-range"
|
||||
/>
|
||||
</form>
|
||||
|
||||
<%= if @logo_image.is_svg do %>
|
||||
<div class="theme-subfield">
|
||||
<label class="admin-check-label">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={@theme_settings.logo_recolor}
|
||||
phx-click={@event_prefix <> "update_branding"}
|
||||
phx-value-field="logo_recolor"
|
||||
phx-value-setting_value={if @theme_settings.logo_recolor, do: "false", else: "true"}
|
||||
class="admin-checkbox admin-checkbox-sm"
|
||||
/>
|
||||
<span class="theme-check-text">Recolour logo</span>
|
||||
</label>
|
||||
|
||||
<%= if @theme_settings.logo_recolor do %>
|
||||
<form
|
||||
id="logo-color-form-site"
|
||||
phx-change={@event_prefix <> "update_color"}
|
||||
phx-value-field="logo_color"
|
||||
phx-hook="ColorSync"
|
||||
class="theme-color-row theme-subfield-sm"
|
||||
>
|
||||
<input
|
||||
type="color"
|
||||
name="value"
|
||||
value={@theme_settings.logo_color}
|
||||
class="theme-color-swatch theme-color-swatch-sm"
|
||||
/>
|
||||
<span class="theme-color-value">{@theme_settings.logo_color}</span>
|
||||
</form>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
# Header upload sub-section
|
||||
attr :uploads, :map, required: true
|
||||
attr :header_image, :map, default: nil
|
||||
attr :theme_settings, :map, required: true
|
||||
attr :contrast_warning, :atom, default: :ok
|
||||
attr :event_prefix, :string, default: "site_"
|
||||
|
||||
defp header_upload_section(assigns) do
|
||||
~H"""
|
||||
<div class="theme-subsection">
|
||||
<span class="theme-slider-label theme-block-label">Upload header image</span>
|
||||
<form phx-change="noop" phx-submit="noop">
|
||||
<label class="theme-upload-label theme-upload-label-compact">
|
||||
<span>Choose file...</span>
|
||||
<.live_file_input upload={@uploads.theme_header_upload} class="hidden" />
|
||||
</label>
|
||||
</form>
|
||||
|
||||
<%= if @header_image do %>
|
||||
<div class="theme-thumb theme-thumb-cover theme-thumb-header theme-thumb-compact">
|
||||
<img src={"/image_cache/#{@header_image.id}.webp"} alt="" />
|
||||
<button
|
||||
type="button"
|
||||
phx-click={@event_prefix <> "remove_header"}
|
||||
class="theme-remove-btn"
|
||||
title="Remove header background"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<%= if @contrast_warning != :ok do %>
|
||||
<div class="theme-contrast-warning theme-contrast-warning-compact">
|
||||
<strong>
|
||||
<%= if @contrast_warning == :poor do %>
|
||||
Text may be hard to read
|
||||
<% else %>
|
||||
Text contrast could be better
|
||||
<% end %>
|
||||
</strong>
|
||||
<p>
|
||||
Try switching to a
|
||||
<%= if @theme_settings.mood == "dark" do %>
|
||||
lighter mood
|
||||
<% else %>
|
||||
dark mood
|
||||
<% end %>
|
||||
or choosing a different image.
|
||||
</p>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="admin-stack admin-stack-md theme-subfield">
|
||||
<form phx-change={@event_prefix <> "update_branding"} phx-value-field="header_zoom">
|
||||
<div class="theme-slider-header">
|
||||
<span class="theme-slider-label">Zoom</span>
|
||||
<span class="theme-slider-value">{@theme_settings.header_zoom}%</span>
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
min="100"
|
||||
max="200"
|
||||
value={@theme_settings.header_zoom}
|
||||
name="header_zoom"
|
||||
class="admin-range"
|
||||
/>
|
||||
</form>
|
||||
<%= if @theme_settings.header_zoom > 100 do %>
|
||||
<form
|
||||
phx-change={@event_prefix <> "update_branding"}
|
||||
phx-value-field="header_position_x"
|
||||
>
|
||||
<div class="theme-slider-header">
|
||||
<span class="theme-slider-label">Horizontal position</span>
|
||||
<span class="theme-slider-value">{@theme_settings.header_position_x}%</span>
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="100"
|
||||
value={@theme_settings.header_position_x}
|
||||
name="header_position_x"
|
||||
class="admin-range"
|
||||
/>
|
||||
</form>
|
||||
<form
|
||||
phx-change={@event_prefix <> "update_branding"}
|
||||
phx-value-field="header_position_y"
|
||||
>
|
||||
<div class="theme-slider-header">
|
||||
<span class="theme-slider-label">Vertical position</span>
|
||||
<span class="theme-slider-value">{@theme_settings.header_position_y}%</span>
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="100"
|
||||
value={@theme_settings.header_position_y}
|
||||
name="header_position_y"
|
||||
class="admin-range"
|
||||
/>
|
||||
</form>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= for entry <- @uploads.theme_header_upload.entries do %>
|
||||
<.upload_progress entry={entry} upload_name="theme_header_upload" />
|
||||
<%= for err <- upload_errors(@uploads.theme_header_upload, entry) do %>
|
||||
<p class="theme-error-text">{error_to_string(err)}</p>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%= for err <- upload_errors(@uploads.theme_header_upload) do %>
|
||||
<p class="theme-error-text">{error_to_string(err)}</p>
|
||||
<% end %>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
# Shared upload progress component
|
||||
attr :entry, :map, required: true
|
||||
attr :upload_name, :string, required: true
|
||||
|
||||
defp upload_progress(assigns) do
|
||||
~H"""
|
||||
<div class="theme-progress">
|
||||
<div class="theme-progress-bar">
|
||||
<div class="theme-progress-fill" style={"width: #{@entry.progress}%"}></div>
|
||||
</div>
|
||||
<span class="admin-text-secondary">{@entry.progress}%</span>
|
||||
<button
|
||||
type="button"
|
||||
phx-click="theme_cancel_upload"
|
||||
phx-value-ref={@entry.ref}
|
||||
phx-value-upload={@upload_name}
|
||||
class="theme-upload-cancel"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
defp error_to_string(:too_large), do: "File is too large"
|
||||
defp error_to_string(:too_many_files), do: "Too many files"
|
||||
defp error_to_string(:not_accepted), do: "File type not accepted"
|
||||
defp error_to_string(err), do: inspect(err)
|
||||
|
||||
# ── Announcement Bar Editor ─────────────────────────────────────────
|
||||
|
||||
attr :settings, :map, required: true
|
||||
|
||||
@@ -18,29 +18,6 @@ defmodule BerrypodWeb.ShopComponents.ThemeEditor do
|
||||
# ── Quick Settings ─────────────────────────────────────────────────
|
||||
# These are the core settings shown in both compact and full modes.
|
||||
|
||||
@doc """
|
||||
Renders the shop name input field.
|
||||
"""
|
||||
attr :site_name, :string, required: true
|
||||
attr :event_prefix, :string, default: ""
|
||||
|
||||
def shop_name_input(assigns) do
|
||||
~H"""
|
||||
<div class="theme-section">
|
||||
<label class="theme-section-label">Shop name</label>
|
||||
<form phx-change={@event_prefix <> "update_setting"} phx-value-field="site_name">
|
||||
<input
|
||||
type="text"
|
||||
name="site_name"
|
||||
value={@site_name}
|
||||
placeholder="Your shop name"
|
||||
class="admin-input"
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders the preset grid for quick theme switching.
|
||||
"""
|
||||
@@ -211,19 +188,6 @@ defmodule BerrypodWeb.ShopComponents.ThemeEditor do
|
||||
~H"""
|
||||
<div class="editor-theme-content">
|
||||
<%= if @theme_settings do %>
|
||||
<.shop_name_input site_name={@site_name} event_prefix={@event_prefix} />
|
||||
|
||||
<.branding_section
|
||||
theme_settings={@theme_settings}
|
||||
uploads={@uploads}
|
||||
logo_image={@logo_image}
|
||||
header_image={@header_image}
|
||||
icon_image={@icon_image}
|
||||
contrast_warning={@contrast_warning}
|
||||
site_name={@site_name}
|
||||
event_prefix={@event_prefix}
|
||||
/>
|
||||
|
||||
<.preset_grid presets={@presets} active_preset={@active_preset} event_prefix={@event_prefix} />
|
||||
|
||||
<.color_picker
|
||||
@@ -257,334 +221,6 @@ defmodule BerrypodWeb.ShopComponents.ThemeEditor do
|
||||
"""
|
||||
end
|
||||
|
||||
# ── Branding Section (Logo, Header, Icon) ───────────────────────────
|
||||
|
||||
attr :theme_settings, :map, required: true
|
||||
attr :uploads, :map, default: nil
|
||||
attr :logo_image, :map, default: nil
|
||||
attr :header_image, :map, default: nil
|
||||
attr :icon_image, :map, default: nil
|
||||
attr :contrast_warning, :atom, default: :ok
|
||||
attr :site_name, :string, default: ""
|
||||
attr :event_prefix, :string, default: "theme_"
|
||||
|
||||
defp branding_section(assigns) do
|
||||
~H"""
|
||||
<div class="theme-section theme-section-compact">
|
||||
<label class="theme-section-label">Logo & branding</label>
|
||||
|
||||
<div class="admin-stack admin-stack-sm theme-field">
|
||||
<label class="admin-check-label">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={@theme_settings.show_site_name}
|
||||
phx-click={@event_prefix <> "toggle_setting"}
|
||||
phx-value-field="show_site_name"
|
||||
class="admin-checkbox admin-checkbox-sm"
|
||||
/>
|
||||
<span class="theme-check-text">Show shop name</span>
|
||||
</label>
|
||||
|
||||
<label class="admin-check-label">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={@theme_settings.show_logo}
|
||||
phx-click={@event_prefix <> "toggle_setting"}
|
||||
phx-value-field="show_logo"
|
||||
class="admin-checkbox admin-checkbox-sm"
|
||||
/>
|
||||
<span class="theme-check-text">Show logo</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<%= if @theme_settings.show_logo && @uploads do %>
|
||||
<.logo_upload_section
|
||||
uploads={@uploads}
|
||||
logo_image={@logo_image}
|
||||
theme_settings={@theme_settings}
|
||||
site_name={@site_name}
|
||||
event_prefix={@event_prefix}
|
||||
/>
|
||||
<% end %>
|
||||
|
||||
<label class="admin-check-label theme-field">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={@theme_settings.header_background_enabled}
|
||||
phx-click={@event_prefix <> "update_setting"}
|
||||
phx-value-field="header_background_enabled"
|
||||
phx-value-setting_value={
|
||||
if @theme_settings.header_background_enabled, do: "false", else: "true"
|
||||
}
|
||||
class="admin-checkbox admin-checkbox-sm"
|
||||
/>
|
||||
<span class="theme-check-text">Header background image</span>
|
||||
</label>
|
||||
|
||||
<%= if @theme_settings.header_background_enabled && @uploads do %>
|
||||
<.header_upload_section
|
||||
uploads={@uploads}
|
||||
header_image={@header_image}
|
||||
theme_settings={@theme_settings}
|
||||
contrast_warning={@contrast_warning}
|
||||
event_prefix={@event_prefix}
|
||||
/>
|
||||
<% end %>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
# Logo upload sub-section
|
||||
attr :uploads, :map, required: true
|
||||
attr :logo_image, :map, default: nil
|
||||
attr :theme_settings, :map, required: true
|
||||
attr :site_name, :string, default: ""
|
||||
attr :event_prefix, :string, default: "theme_"
|
||||
|
||||
defp logo_upload_section(assigns) do
|
||||
~H"""
|
||||
<div class="theme-subsection">
|
||||
<span class="theme-slider-label theme-block-label">Upload logo (SVG or PNG)</span>
|
||||
<div class="admin-row admin-row-lg">
|
||||
<form phx-change="noop" phx-submit="noop" class="admin-fill">
|
||||
<label class="theme-upload-label theme-upload-label-compact">
|
||||
<span>Choose file...</span>
|
||||
<.live_file_input upload={@uploads.theme_logo_upload} class="hidden" />
|
||||
</label>
|
||||
</form>
|
||||
<%= if @logo_image do %>
|
||||
<div class="theme-thumb theme-thumb-logo theme-thumb-compact">
|
||||
<img src={"/image_cache/#{@logo_image.id}.webp"} alt={@site_name} />
|
||||
<button
|
||||
type="button"
|
||||
phx-click={@event_prefix <> "remove_logo"}
|
||||
class="theme-remove-btn"
|
||||
title="Remove logo"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<%= for entry <- @uploads.theme_logo_upload.entries do %>
|
||||
<.upload_progress entry={entry} upload_name="theme_logo_upload" />
|
||||
<%= for err <- upload_errors(@uploads.theme_logo_upload, entry) do %>
|
||||
<p class="theme-error-text">{error_to_string(err)}</p>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%= for err <- upload_errors(@uploads.theme_logo_upload) do %>
|
||||
<p class="theme-error-text">{error_to_string(err)}</p>
|
||||
<% end %>
|
||||
|
||||
<%= if @logo_image do %>
|
||||
<form
|
||||
phx-change={@event_prefix <> "update_setting"}
|
||||
phx-value-field="logo_size"
|
||||
class="theme-subfield"
|
||||
>
|
||||
<div class="theme-slider-header">
|
||||
<span class="theme-slider-label">Logo size</span>
|
||||
<span class="theme-slider-value">{@theme_settings.logo_size}px</span>
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
min="24"
|
||||
max="120"
|
||||
value={@theme_settings.logo_size}
|
||||
name="logo_size"
|
||||
class="admin-range"
|
||||
/>
|
||||
</form>
|
||||
|
||||
<%= if @logo_image.is_svg do %>
|
||||
<div class="theme-subfield">
|
||||
<label class="admin-check-label">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={@theme_settings.logo_recolor}
|
||||
phx-click={@event_prefix <> "update_setting"}
|
||||
phx-value-field="logo_recolor"
|
||||
phx-value-setting_value={if @theme_settings.logo_recolor, do: "false", else: "true"}
|
||||
class="admin-checkbox admin-checkbox-sm"
|
||||
/>
|
||||
<span class="theme-check-text">Recolour logo</span>
|
||||
</label>
|
||||
|
||||
<%= if @theme_settings.logo_recolor do %>
|
||||
<form
|
||||
id="logo-color-form-compact"
|
||||
phx-change={@event_prefix <> "update_color"}
|
||||
phx-value-field="logo_color"
|
||||
phx-hook="ColorSync"
|
||||
class="theme-color-row theme-subfield-sm"
|
||||
>
|
||||
<input
|
||||
type="color"
|
||||
name="value"
|
||||
value={@theme_settings.logo_color}
|
||||
class="theme-color-swatch theme-color-swatch-sm"
|
||||
/>
|
||||
<span class="theme-color-value">{@theme_settings.logo_color}</span>
|
||||
</form>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
# Header upload sub-section
|
||||
attr :uploads, :map, required: true
|
||||
attr :header_image, :map, default: nil
|
||||
attr :theme_settings, :map, required: true
|
||||
attr :contrast_warning, :atom, default: :ok
|
||||
attr :event_prefix, :string, default: "theme_"
|
||||
|
||||
defp header_upload_section(assigns) do
|
||||
~H"""
|
||||
<div class="theme-subsection">
|
||||
<span class="theme-slider-label theme-block-label">Upload header image</span>
|
||||
<form phx-change="noop" phx-submit="noop">
|
||||
<label class="theme-upload-label theme-upload-label-compact">
|
||||
<span>Choose file...</span>
|
||||
<.live_file_input upload={@uploads.theme_header_upload} class="hidden" />
|
||||
</label>
|
||||
</form>
|
||||
|
||||
<%= if @header_image do %>
|
||||
<div class="theme-thumb theme-thumb-cover theme-thumb-header theme-thumb-compact">
|
||||
<img src={"/image_cache/#{@header_image.id}.webp"} alt="" />
|
||||
<button
|
||||
type="button"
|
||||
phx-click={@event_prefix <> "remove_header"}
|
||||
class="theme-remove-btn"
|
||||
title="Remove header background"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<%= if @contrast_warning != :ok do %>
|
||||
<div class="theme-contrast-warning theme-contrast-warning-compact">
|
||||
<strong>
|
||||
<%= if @contrast_warning == :poor do %>
|
||||
Text may be hard to read
|
||||
<% else %>
|
||||
Text contrast could be better
|
||||
<% end %>
|
||||
</strong>
|
||||
<p>
|
||||
Try switching to a
|
||||
<%= if @theme_settings.mood == "dark" do %>
|
||||
lighter mood
|
||||
<% else %>
|
||||
dark mood
|
||||
<% end %>
|
||||
or choosing a different image.
|
||||
</p>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="admin-stack admin-stack-md theme-subfield">
|
||||
<form phx-change={@event_prefix <> "update_setting"} phx-value-field="header_zoom">
|
||||
<div class="theme-slider-header">
|
||||
<span class="theme-slider-label">Zoom</span>
|
||||
<span class="theme-slider-value">{@theme_settings.header_zoom}%</span>
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
min="100"
|
||||
max="200"
|
||||
value={@theme_settings.header_zoom}
|
||||
name="header_zoom"
|
||||
class="admin-range"
|
||||
/>
|
||||
</form>
|
||||
<%= if @theme_settings.header_zoom > 100 do %>
|
||||
<form
|
||||
phx-change={@event_prefix <> "update_setting"}
|
||||
phx-value-field="header_position_x"
|
||||
>
|
||||
<div class="theme-slider-header">
|
||||
<span class="theme-slider-label">Horizontal position</span>
|
||||
<span class="theme-slider-value">{@theme_settings.header_position_x}%</span>
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="100"
|
||||
value={@theme_settings.header_position_x}
|
||||
name="header_position_x"
|
||||
class="admin-range"
|
||||
/>
|
||||
</form>
|
||||
<form
|
||||
phx-change={@event_prefix <> "update_setting"}
|
||||
phx-value-field="header_position_y"
|
||||
>
|
||||
<div class="theme-slider-header">
|
||||
<span class="theme-slider-label">Vertical position</span>
|
||||
<span class="theme-slider-value">{@theme_settings.header_position_y}%</span>
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="100"
|
||||
value={@theme_settings.header_position_y}
|
||||
name="header_position_y"
|
||||
class="admin-range"
|
||||
/>
|
||||
</form>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= for entry <- @uploads.theme_header_upload.entries do %>
|
||||
<.upload_progress entry={entry} upload_name="theme_header_upload" />
|
||||
<%= for err <- upload_errors(@uploads.theme_header_upload, entry) do %>
|
||||
<p class="theme-error-text">{error_to_string(err)}</p>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%= for err <- upload_errors(@uploads.theme_header_upload) do %>
|
||||
<p class="theme-error-text">{error_to_string(err)}</p>
|
||||
<% end %>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
# Shared upload progress component
|
||||
attr :entry, :map, required: true
|
||||
attr :upload_name, :string, required: true
|
||||
|
||||
defp upload_progress(assigns) do
|
||||
~H"""
|
||||
<div class="theme-progress">
|
||||
<div class="theme-progress-bar">
|
||||
<div class="theme-progress-fill" style={"width: #{@entry.progress}%"}></div>
|
||||
</div>
|
||||
<span class="admin-text-secondary">{@entry.progress}%</span>
|
||||
<button
|
||||
type="button"
|
||||
phx-click="theme_cancel_upload"
|
||||
phx-value-ref={@entry.ref}
|
||||
phx-value-upload={@upload_name}
|
||||
class="theme-upload-cancel"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
defp error_to_string(:too_large), do: "File is too large"
|
||||
defp error_to_string(:too_many_files), do: "Too many files"
|
||||
defp error_to_string(:not_accepted), do: "File type not accepted"
|
||||
defp error_to_string(err), do: inspect(err)
|
||||
|
||||
# ── Full Customise Accordion ───────────────────────────────────────
|
||||
# Advanced settings groups for admin theme page.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user