chore: apply mix format to codebase
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
d97918d66a
commit
336b2bb81d
@ -194,7 +194,9 @@ defmodule Mix.Tasks.GenerateMockups do
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
if failed > 0 do
|
if failed > 0 do
|
||||||
Mix.shell().error("Some products failed to generate. Check the output above for details.")
|
Mix.shell().error(
|
||||||
|
"Some products failed to generate. Check the output above for details."
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -31,7 +31,8 @@ defmodule SimpleshopTheme.Images.Optimizer do
|
|||||||
{width, _height, _} <- Image.shape(image),
|
{width, _height, _} <- Image.shape(image),
|
||||||
{:ok, resized} <- maybe_resize(image, width),
|
{:ok, resized} <- maybe_resize(image, width),
|
||||||
{final_width, final_height, _} <- Image.shape(resized),
|
{final_width, final_height, _} <- Image.shape(resized),
|
||||||
{:ok, webp_data} <- Image.write(resized, :memory, suffix: ".webp", quality: @storage_quality) do
|
{:ok, webp_data} <-
|
||||||
|
Image.write(resized, :memory, suffix: ".webp", quality: @storage_quality) do
|
||||||
{:ok, webp_data, final_width, final_height}
|
{:ok, webp_data, final_width, final_height}
|
||||||
end
|
end
|
||||||
rescue
|
rescue
|
||||||
@ -191,9 +192,20 @@ defmodule SimpleshopTheme.Images.Optimizer do
|
|||||||
widths = applicable_widths(source_width)
|
widths = applicable_widths(source_width)
|
||||||
|
|
||||||
tasks = [
|
tasks = [
|
||||||
Task.async(fn -> generate_variant_to_dir(vips_image, output_basename, output_dir, "thumb", :jpg, @thumb_size) end)
|
Task.async(fn ->
|
||||||
|
generate_variant_to_dir(
|
||||||
|
vips_image,
|
||||||
|
output_basename,
|
||||||
|
output_dir,
|
||||||
|
"thumb",
|
||||||
|
:jpg,
|
||||||
|
@thumb_size
|
||||||
|
)
|
||||||
|
end)
|
||||||
| for w <- widths, fmt <- @pregenerated_formats do
|
| for w <- widths, fmt <- @pregenerated_formats do
|
||||||
Task.async(fn -> generate_variant_to_dir(vips_image, output_basename, output_dir, w, fmt, w) end)
|
Task.async(fn ->
|
||||||
|
generate_variant_to_dir(vips_image, output_basename, output_dir, w, fmt, w)
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -59,7 +59,9 @@ defmodule SimpleshopTheme.Images.VariantCache do
|
|||||||
if to_process == [] do
|
if to_process == [] do
|
||||||
Logger.info("[VariantCache] All database image variants up to date")
|
Logger.info("[VariantCache] All database image variants up to date")
|
||||||
else
|
else
|
||||||
Logger.info("[VariantCache] Enqueueing #{length(to_process)} database images for processing")
|
Logger.info(
|
||||||
|
"[VariantCache] Enqueueing #{length(to_process)} database images for processing"
|
||||||
|
)
|
||||||
|
|
||||||
Enum.each(to_process, fn image ->
|
Enum.each(to_process, fn image ->
|
||||||
image
|
image
|
||||||
|
|||||||
@ -119,7 +119,12 @@ defmodule SimpleshopTheme.Media do
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
def get_logo do
|
def get_logo do
|
||||||
Repo.one(from i in ImageSchema, where: i.image_type == "logo", order_by: [desc: i.inserted_at], limit: 1)
|
Repo.one(
|
||||||
|
from i in ImageSchema,
|
||||||
|
where: i.image_type == "logo",
|
||||||
|
order_by: [desc: i.inserted_at],
|
||||||
|
limit: 1
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
@ -132,7 +137,12 @@ defmodule SimpleshopTheme.Media do
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
def get_header do
|
def get_header do
|
||||||
Repo.one(from i in ImageSchema, where: i.image_type == "header", order_by: [desc: i.inserted_at], limit: 1)
|
Repo.one(
|
||||||
|
from i in ImageSchema,
|
||||||
|
where: i.image_type == "header",
|
||||||
|
order_by: [desc: i.inserted_at],
|
||||||
|
limit: 1
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
|||||||
@ -46,7 +46,8 @@ defmodule SimpleshopTheme.Media.Image do
|
|||||||
defp detect_svg(changeset) do
|
defp detect_svg(changeset) do
|
||||||
content_type = get_change(changeset, :content_type)
|
content_type = get_change(changeset, :content_type)
|
||||||
|
|
||||||
if content_type == "image/svg+xml" or String.ends_with?(get_change(changeset, :filename) || "", ".svg") do
|
if content_type == "image/svg+xml" or
|
||||||
|
String.ends_with?(get_change(changeset, :filename) || "", ".svg") do
|
||||||
changeset
|
changeset
|
||||||
|> put_change(:is_svg, true)
|
|> put_change(:is_svg, true)
|
||||||
|> maybe_store_svg_content()
|
|> maybe_store_svg_content()
|
||||||
|
|||||||
@ -23,7 +23,8 @@ defmodule SimpleshopTheme.Media.SVGRecolorer do
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
@spec recolor(String.t(), String.t()) :: String.t()
|
@spec recolor(String.t(), String.t()) :: String.t()
|
||||||
def recolor(svg_content, target_color) when is_binary(svg_content) and is_binary(target_color) do
|
def recolor(svg_content, target_color)
|
||||||
|
when is_binary(svg_content) and is_binary(target_color) do
|
||||||
svg_content
|
svg_content
|
||||||
|> recolor_fill_attributes(target_color)
|
|> recolor_fill_attributes(target_color)
|
||||||
|> recolor_stroke_attributes(target_color)
|
|> recolor_stroke_attributes(target_color)
|
||||||
|
|||||||
@ -163,9 +163,17 @@ defmodule SimpleshopTheme.Mockups.Generator do
|
|||||||
hoodie: %{blueprint_id: nil, print_provider_id: nil, search_term: "Pullover Hoodie"},
|
hoodie: %{blueprint_id: nil, print_provider_id: nil, search_term: "Pullover Hoodie"},
|
||||||
tote: %{blueprint_id: nil, print_provider_id: nil, search_term: "Cotton Tote Bag"},
|
tote: %{blueprint_id: nil, print_provider_id: nil, search_term: "Cotton Tote Bag"},
|
||||||
mug: %{blueprint_id: nil, print_provider_id: nil, search_term: "Mug 11oz"},
|
mug: %{blueprint_id: nil, print_provider_id: nil, search_term: "Mug 11oz"},
|
||||||
cushion: %{blueprint_id: nil, print_provider_id: nil, search_term: "Spun Polyester Square Pillow"},
|
cushion: %{
|
||||||
|
blueprint_id: nil,
|
||||||
|
print_provider_id: nil,
|
||||||
|
search_term: "Spun Polyester Square Pillow"
|
||||||
|
},
|
||||||
blanket: %{blueprint_id: nil, print_provider_id: nil, search_term: "Sherpa Fleece Blanket"},
|
blanket: %{blueprint_id: nil, print_provider_id: nil, search_term: "Sherpa Fleece Blanket"},
|
||||||
notebook: %{blueprint_id: nil, print_provider_id: nil, search_term: "Hardcover Journal Matte"},
|
notebook: %{
|
||||||
|
blueprint_id: nil,
|
||||||
|
print_provider_id: nil,
|
||||||
|
search_term: "Hardcover Journal Matte"
|
||||||
|
},
|
||||||
phone_case: %{blueprint_id: nil, print_provider_id: nil, search_term: "Tough Phone Cases"},
|
phone_case: %{blueprint_id: nil, print_provider_id: nil, search_term: "Tough Phone Cases"},
|
||||||
laptop_sleeve: %{blueprint_id: nil, print_provider_id: nil, search_term: "Laptop Sleeve"}
|
laptop_sleeve: %{blueprint_id: nil, print_provider_id: nil, search_term: "Laptop Sleeve"}
|
||||||
}
|
}
|
||||||
@ -253,12 +261,12 @@ defmodule SimpleshopTheme.Mockups.Generator do
|
|||||||
"""
|
"""
|
||||||
def calculate_cover_scale(artwork_width, artwork_height, placeholder_width, placeholder_height)
|
def calculate_cover_scale(artwork_width, artwork_height, placeholder_width, placeholder_height)
|
||||||
when is_number(artwork_width) and is_number(artwork_height) and
|
when is_number(artwork_width) and is_number(artwork_height) and
|
||||||
is_number(placeholder_width) and is_number(placeholder_height) and
|
is_number(placeholder_width) and is_number(placeholder_height) and
|
||||||
artwork_width > 0 and artwork_height > 0 and
|
artwork_width > 0 and artwork_height > 0 and
|
||||||
placeholder_width > 0 and placeholder_height > 0 do
|
placeholder_width > 0 and placeholder_height > 0 do
|
||||||
# For cover: use the larger scale to ensure full coverage
|
# For cover: use the larger scale to ensure full coverage
|
||||||
width_scale = 1.0
|
width_scale = 1.0
|
||||||
height_scale = (placeholder_height * artwork_width) / (artwork_height * placeholder_width)
|
height_scale = placeholder_height * artwork_width / (artwork_height * placeholder_width)
|
||||||
max(width_scale, height_scale)
|
max(width_scale, height_scale)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -267,21 +275,36 @@ defmodule SimpleshopTheme.Mockups.Generator do
|
|||||||
@doc """
|
@doc """
|
||||||
Create a product with the uploaded artwork.
|
Create a product with the uploaded artwork.
|
||||||
"""
|
"""
|
||||||
def create_product(shop_id, product_def, image_id, image_width, image_height, blueprint_id, print_provider_id, variants) do
|
def create_product(
|
||||||
|
shop_id,
|
||||||
|
product_def,
|
||||||
|
image_id,
|
||||||
|
image_width,
|
||||||
|
image_height,
|
||||||
|
blueprint_id,
|
||||||
|
print_provider_id,
|
||||||
|
variants
|
||||||
|
) do
|
||||||
# Get the first variant for simplicity (typically a standard size/color)
|
# Get the first variant for simplicity (typically a standard size/color)
|
||||||
variant = hd(variants)
|
variant = hd(variants)
|
||||||
variant_id = variant["id"]
|
variant_id = variant["id"]
|
||||||
|
|
||||||
# Get placeholder info
|
# Get placeholder info
|
||||||
placeholders = variant["placeholders"] || []
|
placeholders = variant["placeholders"] || []
|
||||||
front_placeholder = Enum.find(placeholders, fn p -> p["position"] == "front" end) || hd(placeholders)
|
|
||||||
|
front_placeholder =
|
||||||
|
Enum.find(placeholders, fn p -> p["position"] == "front" end) || hd(placeholders)
|
||||||
|
|
||||||
# Extract placeholder dimensions and calculate cover scale
|
# Extract placeholder dimensions and calculate cover scale
|
||||||
placeholder_width = front_placeholder["width"]
|
placeholder_width = front_placeholder["width"]
|
||||||
placeholder_height = front_placeholder["height"]
|
placeholder_height = front_placeholder["height"]
|
||||||
scale = calculate_cover_scale(image_width, image_height, placeholder_width, placeholder_height)
|
|
||||||
|
|
||||||
IO.puts(" Scale calculation: artwork #{image_width}x#{image_height}, placeholder #{placeholder_width}x#{placeholder_height} -> scale #{Float.round(scale, 3)}")
|
scale =
|
||||||
|
calculate_cover_scale(image_width, image_height, placeholder_width, placeholder_height)
|
||||||
|
|
||||||
|
IO.puts(
|
||||||
|
" Scale calculation: artwork #{image_width}x#{image_height}, placeholder #{placeholder_width}x#{placeholder_height} -> scale #{Float.round(scale, 3)}"
|
||||||
|
)
|
||||||
|
|
||||||
product_data = %{
|
product_data = %{
|
||||||
title: product_def.name,
|
title: product_def.name,
|
||||||
@ -439,7 +462,17 @@ defmodule SimpleshopTheme.Mockups.Generator do
|
|||||||
image_height = upload["height"],
|
image_height = upload["height"],
|
||||||
_ = IO.puts(" Artwork uploaded (ID: #{image_id}, #{image_width}x#{image_height})"),
|
_ = IO.puts(" Artwork uploaded (ID: #{image_id}, #{image_width}x#{image_height})"),
|
||||||
_ = IO.puts(" Creating product..."),
|
_ = IO.puts(" Creating product..."),
|
||||||
{:ok, product} <- create_product(shop_id, product_def, image_id, image_width, image_height, blueprint_id, provider_id, variants),
|
{:ok, product} <-
|
||||||
|
create_product(
|
||||||
|
shop_id,
|
||||||
|
product_def,
|
||||||
|
image_id,
|
||||||
|
image_width,
|
||||||
|
image_height,
|
||||||
|
blueprint_id,
|
||||||
|
provider_id,
|
||||||
|
variants
|
||||||
|
),
|
||||||
product_id = product["id"],
|
product_id = product["id"],
|
||||||
mockup_urls = extract_mockup_urls(product),
|
mockup_urls = extract_mockup_urls(product),
|
||||||
_ = IO.puts(" Product created (ID: #{product_id})"),
|
_ = IO.puts(" Product created (ID: #{product_id})"),
|
||||||
|
|||||||
@ -287,14 +287,17 @@ defmodule SimpleshopTheme.Products do
|
|||||||
|
|
||||||
if MapSet.size(removed_ids) > 0 do
|
if MapSet.size(removed_ids) > 0 do
|
||||||
from(v in ProductVariant,
|
from(v in ProductVariant,
|
||||||
where: v.product_id == ^product_id and v.provider_variant_id in ^MapSet.to_list(removed_ids)
|
where:
|
||||||
|
v.product_id == ^product_id and v.provider_variant_id in ^MapSet.to_list(removed_ids)
|
||||||
)
|
)
|
||||||
|> Repo.delete_all()
|
|> Repo.delete_all()
|
||||||
end
|
end
|
||||||
|
|
||||||
# Upsert incoming variants
|
# Upsert incoming variants
|
||||||
Enum.map(variants, fn variant_data ->
|
Enum.map(variants, fn variant_data ->
|
||||||
provider_variant_id = variant_data[:provider_variant_id] || variant_data["provider_variant_id"]
|
provider_variant_id =
|
||||||
|
variant_data[:provider_variant_id] || variant_data["provider_variant_id"]
|
||||||
|
|
||||||
attrs = Map.put(variant_data, :product_id, product_id)
|
attrs = Map.put(variant_data, :product_id, product_id)
|
||||||
|
|
||||||
case get_variant_by_provider(product_id, provider_variant_id) do
|
case get_variant_by_provider(product_id, provider_variant_id) do
|
||||||
|
|||||||
@ -88,7 +88,8 @@ defmodule SimpleshopTheme.Products.ProductVariant do
|
|||||||
Formats the options as a human-readable title.
|
Formats the options as a human-readable title.
|
||||||
E.g., %{"Size" => "Large", "Color" => "Blue"} -> "Large / Blue"
|
E.g., %{"Size" => "Large", "Color" => "Blue"} -> "Large / Blue"
|
||||||
"""
|
"""
|
||||||
def options_title(%__MODULE__{options: options}) when is_map(options) and map_size(options) > 0 do
|
def options_title(%__MODULE__{options: options})
|
||||||
|
when is_map(options) and map_size(options) > 0 do
|
||||||
options
|
options
|
||||||
|> Map.values()
|
|> Map.values()
|
||||||
|> Enum.join(" / ")
|
|> Enum.join(" / ")
|
||||||
|
|||||||
@ -93,7 +93,10 @@ defmodule SimpleshopTheme.Settings.ThemeSettings do
|
|||||||
])
|
])
|
||||||
|> validate_required([:mood, :typography, :shape, :density])
|
|> validate_required([:mood, :typography, :shape, :density])
|
||||||
|> validate_inclusion(:mood, ~w(neutral warm cool dark))
|
|> validate_inclusion(:mood, ~w(neutral warm cool dark))
|
||||||
|> validate_inclusion(:typography, ~w(clean editorial modern classic friendly minimal impulse))
|
|> validate_inclusion(
|
||||||
|
:typography,
|
||||||
|
~w(clean editorial modern classic friendly minimal impulse)
|
||||||
|
)
|
||||||
|> validate_inclusion(:shape, ~w(sharp soft round pill))
|
|> validate_inclusion(:shape, ~w(sharp soft round pill))
|
||||||
|> validate_inclusion(:density, ~w(spacious balanced compact))
|
|> validate_inclusion(:density, ~w(spacious balanced compact))
|
||||||
|> validate_inclusion(:grid_columns, ~w(2 3 4))
|
|> validate_inclusion(:grid_columns, ~w(2 3 4))
|
||||||
@ -101,8 +104,14 @@ defmodule SimpleshopTheme.Settings.ThemeSettings do
|
|||||||
|> validate_inclusion(:logo_mode, ~w(text-only logo-text logo-only))
|
|> validate_inclusion(:logo_mode, ~w(text-only logo-text logo-only))
|
||||||
|> validate_number(:logo_size, greater_than_or_equal_to: 24, less_than_or_equal_to: 120)
|
|> validate_number(:logo_size, greater_than_or_equal_to: 24, less_than_or_equal_to: 120)
|
||||||
|> validate_number(:header_zoom, greater_than_or_equal_to: 100, less_than_or_equal_to: 200)
|
|> validate_number(:header_zoom, greater_than_or_equal_to: 100, less_than_or_equal_to: 200)
|
||||||
|> validate_number(:header_position_x, greater_than_or_equal_to: 0, less_than_or_equal_to: 100)
|
|> validate_number(:header_position_x,
|
||||||
|> validate_number(:header_position_y, greater_than_or_equal_to: 0, less_than_or_equal_to: 100)
|
greater_than_or_equal_to: 0,
|
||||||
|
less_than_or_equal_to: 100
|
||||||
|
)
|
||||||
|
|> validate_number(:header_position_y,
|
||||||
|
greater_than_or_equal_to: 0,
|
||||||
|
less_than_or_equal_to: 100
|
||||||
|
)
|
||||||
|> validate_inclusion(:layout_width, ~w(contained wide full))
|
|> validate_inclusion(:layout_width, ~w(contained wide full))
|
||||||
|> validate_inclusion(:card_shadow, ~w(none sm md lg))
|
|> validate_inclusion(:card_shadow, ~w(none sm md lg))
|
||||||
|> validate_inclusion(:font_size, ~w(small medium large))
|
|> validate_inclusion(:font_size, ~w(small medium large))
|
||||||
|
|||||||
@ -234,5 +234,4 @@ defmodule SimpleshopTheme.Theme.Fonts do
|
|||||||
""
|
""
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -67,7 +67,8 @@ defmodule SimpleshopTheme.Theme.PreviewData do
|
|||||||
%{
|
%{
|
||||||
rating: 5,
|
rating: 5,
|
||||||
title: "Absolutely beautiful",
|
title: "Absolutely beautiful",
|
||||||
body: "The quality exceeded my expectations. The colours are vibrant and the paper feels premium. It's now pride of place in my living room.",
|
body:
|
||||||
|
"The quality exceeded my expectations. The colours are vibrant and the paper feels premium. It's now pride of place in my living room.",
|
||||||
author: "Sarah M.",
|
author: "Sarah M.",
|
||||||
date: "2 weeks ago",
|
date: "2 weeks ago",
|
||||||
verified: true
|
verified: true
|
||||||
@ -75,7 +76,8 @@ defmodule SimpleshopTheme.Theme.PreviewData do
|
|||||||
%{
|
%{
|
||||||
rating: 4,
|
rating: 4,
|
||||||
title: "Great gift",
|
title: "Great gift",
|
||||||
body: "Bought this as a gift and it arrived beautifully packaged. Fast shipping too. Would definitely order again.",
|
body:
|
||||||
|
"Bought this as a gift and it arrived beautifully packaged. Fast shipping too. Would definitely order again.",
|
||||||
author: "James T.",
|
author: "James T.",
|
||||||
date: "1 month ago",
|
date: "1 month ago",
|
||||||
verified: true
|
verified: true
|
||||||
@ -90,13 +92,33 @@ defmodule SimpleshopTheme.Theme.PreviewData do
|
|||||||
"""
|
"""
|
||||||
def about_content do
|
def about_content do
|
||||||
[
|
[
|
||||||
%{type: :lead, text: "I'm Emma, a nature photographer based in the UK. What started as weekend walks with my camera has grown into something I never expected – a little shop where I can share my favourite captures with others."},
|
%{
|
||||||
%{type: :paragraph, text: "Every design in this shop comes from my own photography. Whether it's early morning mist over the hills, autumn leaves in the local woods, or the quiet beauty of wildflower meadows, I'm drawn to the peaceful moments that nature offers."},
|
type: :lead,
|
||||||
%{type: :paragraph, text: "I work with quality print partners to bring these images to life on products you can actually use and enjoy – from art prints for your walls to mugs for your morning tea."},
|
text:
|
||||||
|
"I'm Emma, a nature photographer based in the UK. What started as weekend walks with my camera has grown into something I never expected – a little shop where I can share my favourite captures with others."
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
type: :paragraph,
|
||||||
|
text:
|
||||||
|
"Every design in this shop comes from my own photography. Whether it's early morning mist over the hills, autumn leaves in the local woods, or the quiet beauty of wildflower meadows, I'm drawn to the peaceful moments that nature offers."
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
type: :paragraph,
|
||||||
|
text:
|
||||||
|
"I work with quality print partners to bring these images to life on products you can actually use and enjoy – from art prints for your walls to mugs for your morning tea."
|
||||||
|
},
|
||||||
%{type: :heading, text: "Quality you can trust"},
|
%{type: :heading, text: "Quality you can trust"},
|
||||||
%{type: :paragraph, text: "I've carefully chosen print partners who share my commitment to quality. Every product is made to order using premium materials and printing techniques that ensure vibrant colours and lasting quality."},
|
%{
|
||||||
|
type: :paragraph,
|
||||||
|
text:
|
||||||
|
"I've carefully chosen print partners who share my commitment to quality. Every product is made to order using premium materials and printing techniques that ensure vibrant colours and lasting quality."
|
||||||
|
},
|
||||||
%{type: :heading, text: "Printed sustainably"},
|
%{type: :heading, text: "Printed sustainably"},
|
||||||
%{type: :paragraph, text: "Because each item is printed on demand, there's no waste from unsold stock. My print partners use eco-friendly inks where possible, and products are shipped directly to you to minimise unnecessary handling."},
|
%{
|
||||||
|
type: :paragraph,
|
||||||
|
text:
|
||||||
|
"Because each item is printed on demand, there's no waste from unsold stock. My print partners use eco-friendly inks where possible, and products are shipped directly to you to minimise unnecessary handling."
|
||||||
|
},
|
||||||
%{type: :closing, text: "Thank you for visiting. It means a lot that you're here."}
|
%{type: :closing, text: "Thank you for visiting. It means a lot that you're here."}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
@ -427,42 +449,48 @@ defmodule SimpleshopTheme.Theme.PreviewData do
|
|||||||
%{
|
%{
|
||||||
id: "1",
|
id: "1",
|
||||||
author: "Sarah M.",
|
author: "Sarah M.",
|
||||||
content: "The print quality is absolutely stunning - colours are exactly as shown online. My living room looks so much better now!",
|
content:
|
||||||
|
"The print quality is absolutely stunning - colours are exactly as shown online. My living room looks so much better now!",
|
||||||
rating: 5,
|
rating: 5,
|
||||||
date: "2025-01-15"
|
date: "2025-01-15"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
id: "2",
|
id: "2",
|
||||||
author: "James L.",
|
author: "James L.",
|
||||||
content: "Bought the forest hoodie as a gift. The packaging was lovely and the quality exceeded expectations. Will order again!",
|
content:
|
||||||
|
"Bought the forest hoodie as a gift. The packaging was lovely and the quality exceeded expectations. Will order again!",
|
||||||
rating: 5,
|
rating: 5,
|
||||||
date: "2025-01-10"
|
date: "2025-01-10"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
id: "3",
|
id: "3",
|
||||||
author: "Emily R.",
|
author: "Emily R.",
|
||||||
content: "My new favourite mug! I love sipping my morning tea while looking at that beautiful fern design.",
|
content:
|
||||||
|
"My new favourite mug! I love sipping my morning tea while looking at that beautiful fern design.",
|
||||||
rating: 5,
|
rating: 5,
|
||||||
date: "2025-01-05"
|
date: "2025-01-05"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
id: "4",
|
id: "4",
|
||||||
author: "Michael T.",
|
author: "Michael T.",
|
||||||
content: "The tote bag is so sturdy - I use it for everything now. Great print quality that hasn't faded at all.",
|
content:
|
||||||
|
"The tote bag is so sturdy - I use it for everything now. Great print quality that hasn't faded at all.",
|
||||||
rating: 5,
|
rating: 5,
|
||||||
date: "2024-12-28"
|
date: "2024-12-28"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
id: "5",
|
id: "5",
|
||||||
author: "Lisa K.",
|
author: "Lisa K.",
|
||||||
content: "The night sky blanket is gorgeous and so cosy. Perfect for film nights on the sofa. Highly recommend!",
|
content:
|
||||||
|
"The night sky blanket is gorgeous and so cosy. Perfect for film nights on the sofa. Highly recommend!",
|
||||||
rating: 5,
|
rating: 5,
|
||||||
date: "2024-12-20"
|
date: "2024-12-20"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
id: "6",
|
id: "6",
|
||||||
author: "David P.",
|
author: "David P.",
|
||||||
content: "Ordered several prints for my new flat. They arrived well packaged and look amazing on the wall.",
|
content:
|
||||||
|
"Ordered several prints for my new flat. They arrived well packaged and look amazing on the wall.",
|
||||||
rating: 5,
|
rating: 5,
|
||||||
date: "2024-12-15"
|
date: "2024-12-15"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,8 @@ defmodule SimpleshopThemeWeb do
|
|||||||
those modules here.
|
those modules here.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def static_paths, do: ~w(assets css fonts images image_cache mockups favicon.ico robots.txt demo.html)
|
def static_paths,
|
||||||
|
do: ~w(assets css fonts images image_cache mockups favicon.ico robots.txt demo.html)
|
||||||
|
|
||||||
def router do
|
def router do
|
||||||
quote do
|
quote do
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
<%= @inner_content %>
|
{@inner_content}
|
||||||
|
|||||||
@ -4,8 +4,14 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="csrf-token" content={get_csrf_token()} />
|
<meta name="csrf-token" content={get_csrf_token()} />
|
||||||
<meta name="description" content={assigns[:page_description] || @theme_settings.site_description || "Welcome to #{@theme_settings.site_name}"} />
|
<meta
|
||||||
<.live_title><%= assigns[:page_title] || @theme_settings.site_name %></.live_title>
|
name="description"
|
||||||
|
content={
|
||||||
|
assigns[:page_description] || @theme_settings.site_description ||
|
||||||
|
"Welcome to #{@theme_settings.site_name}"
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<.live_title>{assigns[:page_title] || @theme_settings.site_name}</.live_title>
|
||||||
<!-- Preload critical fonts for the current typography preset -->
|
<!-- Preload critical fonts for the current typography preset -->
|
||||||
<%= for preload <- SimpleshopTheme.Theme.Fonts.preload_links(
|
<%= for preload <- SimpleshopTheme.Theme.Fonts.preload_links(
|
||||||
@theme_settings.typography,
|
@theme_settings.typography,
|
||||||
@ -17,7 +23,9 @@
|
|||||||
<script defer phx-track-static src={~p"/assets/js/app.js"}>
|
<script defer phx-track-static src={~p"/assets/js/app.js"}>
|
||||||
</script>
|
</script>
|
||||||
<!-- Generated theme CSS with @font-face declarations -->
|
<!-- Generated theme CSS with @font-face declarations -->
|
||||||
<style id="theme-css"><%= Phoenix.HTML.raw(@generated_css) %></style>
|
<style id="theme-css">
|
||||||
|
<%= Phoenix.HTML.raw(@generated_css) %>
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="h-full">
|
<body class="h-full">
|
||||||
<div
|
<div
|
||||||
|
|||||||
@ -1,11 +1,21 @@
|
|||||||
<div class="shop-container min-h-screen pb-20 md:pb-0" style="background-color: var(--t-surface-base); font-family: var(--t-font-body); color: var(--t-text-primary);">
|
<div
|
||||||
|
class="shop-container min-h-screen pb-20 md:pb-0"
|
||||||
|
style="background-color: var(--t-surface-base); font-family: var(--t-font-body); color: var(--t-text-primary);"
|
||||||
|
>
|
||||||
<.skip_link />
|
<.skip_link />
|
||||||
|
|
||||||
<%= if @theme_settings.announcement_bar do %>
|
<%= if @theme_settings.announcement_bar do %>
|
||||||
<.announcement_bar theme_settings={@theme_settings} />
|
<.announcement_bar theme_settings={@theme_settings} />
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<.shop_header theme_settings={@theme_settings} logo_image={@logo_image} header_image={@header_image} active_page="about" mode={@mode} cart_count={@cart_count} />
|
<.shop_header
|
||||||
|
theme_settings={@theme_settings}
|
||||||
|
logo_image={@logo_image}
|
||||||
|
header_image={@header_image}
|
||||||
|
active_page="about"
|
||||||
|
mode={@mode}
|
||||||
|
cart_count={@cart_count}
|
||||||
|
/>
|
||||||
|
|
||||||
<main id="main-content" class="content-page" style="background-color: var(--t-surface-base);">
|
<main id="main-content" class="content-page" style="background-color: var(--t-surface-base);">
|
||||||
<.hero_section
|
<.hero_section
|
||||||
|
|||||||
@ -1,11 +1,21 @@
|
|||||||
<div class="shop-container min-h-screen pb-20 md:pb-0" style="background-color: var(--t-surface-base); font-family: var(--t-font-body); color: var(--t-text-primary);">
|
<div
|
||||||
|
class="shop-container min-h-screen pb-20 md:pb-0"
|
||||||
|
style="background-color: var(--t-surface-base); font-family: var(--t-font-body); color: var(--t-text-primary);"
|
||||||
|
>
|
||||||
<.skip_link />
|
<.skip_link />
|
||||||
|
|
||||||
<%= if @theme_settings.announcement_bar do %>
|
<%= if @theme_settings.announcement_bar do %>
|
||||||
<.announcement_bar theme_settings={@theme_settings} />
|
<.announcement_bar theme_settings={@theme_settings} />
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<.shop_header theme_settings={@theme_settings} logo_image={@logo_image} header_image={@header_image} active_page="cart" mode={@mode} cart_count={@cart_count} />
|
<.shop_header
|
||||||
|
theme_settings={@theme_settings}
|
||||||
|
logo_image={@logo_image}
|
||||||
|
header_image={@header_image}
|
||||||
|
active_page="cart"
|
||||||
|
mode={@mode}
|
||||||
|
cart_count={@cart_count}
|
||||||
|
/>
|
||||||
|
|
||||||
<main id="main-content" class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
<main id="main-content" class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||||
<.page_title text="Your basket" />
|
<.page_title text="Your basket" />
|
||||||
|
|||||||
@ -1,11 +1,21 @@
|
|||||||
<div class="shop-container min-h-screen pb-20 md:pb-0" style="background-color: var(--t-surface-base); font-family: var(--t-font-body); color: var(--t-text-primary);">
|
<div
|
||||||
|
class="shop-container min-h-screen pb-20 md:pb-0"
|
||||||
|
style="background-color: var(--t-surface-base); font-family: var(--t-font-body); color: var(--t-text-primary);"
|
||||||
|
>
|
||||||
<.skip_link />
|
<.skip_link />
|
||||||
|
|
||||||
<%= if @theme_settings.announcement_bar do %>
|
<%= if @theme_settings.announcement_bar do %>
|
||||||
<.announcement_bar theme_settings={@theme_settings} />
|
<.announcement_bar theme_settings={@theme_settings} />
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<.shop_header theme_settings={@theme_settings} logo_image={@logo_image} header_image={@header_image} active_page="collection" mode={@mode} cart_count={@cart_count} />
|
<.shop_header
|
||||||
|
theme_settings={@theme_settings}
|
||||||
|
logo_image={@logo_image}
|
||||||
|
header_image={@header_image}
|
||||||
|
active_page="collection"
|
||||||
|
mode={@mode}
|
||||||
|
cart_count={@cart_count}
|
||||||
|
/>
|
||||||
|
|
||||||
<main id="main-content">
|
<main id="main-content">
|
||||||
<.collection_header title="All Products" product_count={length(@preview_data.products)} />
|
<.collection_header title="All Products" product_count={length(@preview_data.products)} />
|
||||||
|
|||||||
@ -1,11 +1,21 @@
|
|||||||
<div class="shop-container min-h-screen pb-20 md:pb-0" style="background-color: var(--t-surface-base); font-family: var(--t-font-body); color: var(--t-text-primary);">
|
<div
|
||||||
|
class="shop-container min-h-screen pb-20 md:pb-0"
|
||||||
|
style="background-color: var(--t-surface-base); font-family: var(--t-font-body); color: var(--t-text-primary);"
|
||||||
|
>
|
||||||
<.skip_link />
|
<.skip_link />
|
||||||
|
|
||||||
<%= if @theme_settings.announcement_bar do %>
|
<%= if @theme_settings.announcement_bar do %>
|
||||||
<.announcement_bar theme_settings={@theme_settings} />
|
<.announcement_bar theme_settings={@theme_settings} />
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<.shop_header theme_settings={@theme_settings} logo_image={@logo_image} header_image={@header_image} active_page="contact" mode={@mode} cart_count={@cart_count} />
|
<.shop_header
|
||||||
|
theme_settings={@theme_settings}
|
||||||
|
logo_image={@logo_image}
|
||||||
|
header_image={@header_image}
|
||||||
|
active_page="contact"
|
||||||
|
mode={@mode}
|
||||||
|
cart_count={@cart_count}
|
||||||
|
/>
|
||||||
|
|
||||||
<main id="main-content" class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-16">
|
<main id="main-content" class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-16">
|
||||||
<.hero_section
|
<.hero_section
|
||||||
@ -20,11 +30,14 @@
|
|||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-6">
|
||||||
<.order_tracking_card />
|
<.order_tracking_card />
|
||||||
|
|
||||||
<.info_card title="Handy to know" items={[
|
<.info_card
|
||||||
%{label: "Printing", value: "2-5 business days"},
|
title="Handy to know"
|
||||||
%{label: "Delivery", value: "3-7 business days after printing"},
|
items={[
|
||||||
%{label: "Returns", value: "Happy to help with faulty or damaged items"}
|
%{label: "Printing", value: "2-5 business days"},
|
||||||
]} />
|
%{label: "Delivery", value: "3-7 business days after printing"},
|
||||||
|
%{label: "Returns", value: "Happy to help with faulty or damaged items"}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
<.newsletter_card />
|
<.newsletter_card />
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,27 @@
|
|||||||
<div class="shop-container min-h-screen" style="background-color: var(--t-surface-base); font-family: var(--t-font-body); color: var(--t-text-primary);">
|
<div
|
||||||
|
class="shop-container min-h-screen"
|
||||||
|
style="background-color: var(--t-surface-base); font-family: var(--t-font-body); color: var(--t-text-primary);"
|
||||||
|
>
|
||||||
<.skip_link />
|
<.skip_link />
|
||||||
|
|
||||||
<%= if @theme_settings.announcement_bar do %>
|
<%= if @theme_settings.announcement_bar do %>
|
||||||
<.announcement_bar theme_settings={@theme_settings} />
|
<.announcement_bar theme_settings={@theme_settings} />
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<.shop_header theme_settings={@theme_settings} logo_image={@logo_image} header_image={@header_image} active_page="error" mode={@mode} cart_count={@cart_count} />
|
<.shop_header
|
||||||
|
theme_settings={@theme_settings}
|
||||||
|
logo_image={@logo_image}
|
||||||
|
header_image={@header_image}
|
||||||
|
active_page="error"
|
||||||
|
mode={@mode}
|
||||||
|
cart_count={@cart_count}
|
||||||
|
/>
|
||||||
|
|
||||||
<main id="main-content" class="flex items-center justify-center" style="min-height: calc(100vh - 4rem);">
|
<main
|
||||||
|
id="main-content"
|
||||||
|
class="flex items-center justify-center"
|
||||||
|
style="min-height: calc(100vh - 4rem);"
|
||||||
|
>
|
||||||
<div class="max-w-2xl mx-auto px-4 sm:px-6 lg:px-8 py-16">
|
<div class="max-w-2xl mx-auto px-4 sm:px-6 lg:px-8 py-16">
|
||||||
<.hero_section
|
<.hero_section
|
||||||
variant={:error}
|
variant={:error}
|
||||||
|
|||||||
@ -1,11 +1,21 @@
|
|||||||
<div class="shop-container min-h-screen pb-20 md:pb-0" style="background-color: var(--t-surface-base); font-family: var(--t-font-body); color: var(--t-text-primary);">
|
<div
|
||||||
|
class="shop-container min-h-screen pb-20 md:pb-0"
|
||||||
|
style="background-color: var(--t-surface-base); font-family: var(--t-font-body); color: var(--t-text-primary);"
|
||||||
|
>
|
||||||
<.skip_link />
|
<.skip_link />
|
||||||
|
|
||||||
<%= if @theme_settings.announcement_bar do %>
|
<%= if @theme_settings.announcement_bar do %>
|
||||||
<.announcement_bar theme_settings={@theme_settings} />
|
<.announcement_bar theme_settings={@theme_settings} />
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<.shop_header theme_settings={@theme_settings} logo_image={@logo_image} header_image={@header_image} active_page="home" mode={@mode} cart_count={@cart_count} />
|
<.shop_header
|
||||||
|
theme_settings={@theme_settings}
|
||||||
|
logo_image={@logo_image}
|
||||||
|
header_image={@header_image}
|
||||||
|
active_page="home"
|
||||||
|
mode={@mode}
|
||||||
|
cart_count={@cart_count}
|
||||||
|
/>
|
||||||
|
|
||||||
<main id="main-content">
|
<main id="main-content">
|
||||||
<.hero_section
|
<.hero_section
|
||||||
|
|||||||
@ -1,18 +1,36 @@
|
|||||||
<div class="shop-container min-h-screen pb-20 md:pb-0" style="background-color: var(--t-surface-base); font-family: var(--t-font-body); color: var(--t-text-primary);">
|
<div
|
||||||
|
class="shop-container min-h-screen pb-20 md:pb-0"
|
||||||
|
style="background-color: var(--t-surface-base); font-family: var(--t-font-body); color: var(--t-text-primary);"
|
||||||
|
>
|
||||||
<.skip_link />
|
<.skip_link />
|
||||||
|
|
||||||
<%= if @theme_settings.announcement_bar do %>
|
<%= if @theme_settings.announcement_bar do %>
|
||||||
<.announcement_bar theme_settings={@theme_settings} />
|
<.announcement_bar theme_settings={@theme_settings} />
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<.shop_header theme_settings={@theme_settings} logo_image={@logo_image} header_image={@header_image} active_page="pdp" mode={@mode} cart_count={@cart_count} />
|
<.shop_header
|
||||||
|
theme_settings={@theme_settings}
|
||||||
|
logo_image={@logo_image}
|
||||||
|
header_image={@header_image}
|
||||||
|
active_page="pdp"
|
||||||
|
mode={@mode}
|
||||||
|
cart_count={@cart_count}
|
||||||
|
/>
|
||||||
|
|
||||||
<main id="main-content" class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
<main id="main-content" class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||||
<.breadcrumb items={[
|
<.breadcrumb
|
||||||
%{label: "Home", page: "home", href: "/"},
|
items={[
|
||||||
%{label: @product.category, page: "collection", href: "/collections/#{@product.category |> String.downcase() |> String.replace(" ", "-")}"},
|
%{label: "Home", page: "home", href: "/"},
|
||||||
%{label: @product.name, current: true}
|
%{
|
||||||
]} mode={@mode} />
|
label: @product.category,
|
||||||
|
page: "collection",
|
||||||
|
href:
|
||||||
|
"/collections/#{@product.category |> String.downcase() |> String.replace(" ", "-")}"
|
||||||
|
},
|
||||||
|
%{label: @product.name, current: true}
|
||||||
|
]}
|
||||||
|
mode={@mode}
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-12 mb-16">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-12 mb-16">
|
||||||
<.product_gallery images={@gallery_images} product_name={@product.name} />
|
<.product_gallery images={@gallery_images} product_name={@product.name} />
|
||||||
@ -27,7 +45,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<.reviews_section :if={@theme_settings.pdp_reviews} reviews={SimpleshopTheme.Theme.PreviewData.reviews()} average_rating={5} total_count={24} />
|
<.reviews_section
|
||||||
|
:if={@theme_settings.pdp_reviews}
|
||||||
|
reviews={SimpleshopTheme.Theme.PreviewData.reviews()}
|
||||||
|
average_rating={5}
|
||||||
|
total_count={24}
|
||||||
|
/>
|
||||||
|
|
||||||
<.related_products_section
|
<.related_products_section
|
||||||
:if={@theme_settings.pdp_related_products}
|
:if={@theme_settings.pdp_related_products}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -12,13 +12,21 @@ defmodule SimpleshopThemeWeb.ErrorHTML do
|
|||||||
alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator, PreviewData}
|
alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator, PreviewData}
|
||||||
|
|
||||||
def render("404.html", assigns) do
|
def render("404.html", assigns) do
|
||||||
render_error_page(assigns, "404", "Page Not Found",
|
render_error_page(
|
||||||
"Sorry, we couldn't find the page you're looking for. Perhaps you've mistyped the URL or the page has been moved.")
|
assigns,
|
||||||
|
"404",
|
||||||
|
"Page Not Found",
|
||||||
|
"Sorry, we couldn't find the page you're looking for. Perhaps you've mistyped the URL or the page has been moved."
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def render("500.html", assigns) do
|
def render("500.html", assigns) do
|
||||||
render_error_page(assigns, "500", "Server Error",
|
render_error_page(
|
||||||
"Something went wrong on our end. Please try again later or contact support if the problem persists.")
|
assigns,
|
||||||
|
"500",
|
||||||
|
"Server Error",
|
||||||
|
"Something went wrong on our end. Please try again later or contact support if the problem persists."
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def render(template, _assigns) do
|
def render(template, _assigns) do
|
||||||
@ -57,23 +65,25 @@ defmodule SimpleshopThemeWeb.ErrorHTML do
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title><%= @error_code %> - <%= @error_title %></title>
|
<title>{@error_code} - {@error_title}</title>
|
||||||
<link phx-track-static rel="stylesheet" href={~p"/assets/app.css"} />
|
<link phx-track-static rel="stylesheet" href={~p"/assets/app.css"} />
|
||||||
<style id="theme-css">
|
<style id="theme-css">
|
||||||
<%= Phoenix.HTML.raw(@generated_css) %>
|
<%= Phoenix.HTML.raw(@generated_css) %>
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="h-full">
|
<body class="h-full">
|
||||||
<div class="shop-root themed h-full"
|
<div
|
||||||
data-mood={@theme_settings.mood}
|
class="shop-root themed h-full"
|
||||||
data-typography={@theme_settings.typography}
|
data-mood={@theme_settings.mood}
|
||||||
data-shape={@theme_settings.shape}
|
data-typography={@theme_settings.typography}
|
||||||
data-density={@theme_settings.density}
|
data-shape={@theme_settings.shape}
|
||||||
data-grid={@theme_settings.grid_columns}
|
data-density={@theme_settings.density}
|
||||||
data-header={@theme_settings.header_layout}
|
data-grid={@theme_settings.grid_columns}
|
||||||
data-sticky={to_string(@theme_settings.sticky_header)}
|
data-header={@theme_settings.header_layout}
|
||||||
data-layout={@theme_settings.layout_width}
|
data-sticky={to_string(@theme_settings.sticky_header)}
|
||||||
data-shadow={@theme_settings.card_shadow}>
|
data-layout={@theme_settings.layout_width}
|
||||||
|
data-shadow={@theme_settings.card_shadow}
|
||||||
|
>
|
||||||
<SimpleshopThemeWeb.PageTemplates.error
|
<SimpleshopThemeWeb.PageTemplates.error
|
||||||
theme_settings={@theme_settings}
|
theme_settings={@theme_settings}
|
||||||
logo_image={@logo_image}
|
logo_image={@logo_image}
|
||||||
@ -96,14 +106,18 @@ defmodule SimpleshopThemeWeb.ErrorHTML do
|
|||||||
defp load_theme_data do
|
defp load_theme_data do
|
||||||
try do
|
try do
|
||||||
theme_settings = Settings.get_theme_settings()
|
theme_settings = Settings.get_theme_settings()
|
||||||
|
|
||||||
generated_css =
|
generated_css =
|
||||||
case CSSCache.get() do
|
case CSSCache.get() do
|
||||||
{:ok, css} -> css
|
{:ok, css} ->
|
||||||
|
css
|
||||||
|
|
||||||
:miss ->
|
:miss ->
|
||||||
css = CSSGenerator.generate(theme_settings)
|
css = CSSGenerator.generate(theme_settings)
|
||||||
CSSCache.put(css)
|
CSSCache.put(css)
|
||||||
css
|
css
|
||||||
end
|
end
|
||||||
|
|
||||||
{theme_settings, generated_css}
|
{theme_settings, generated_css}
|
||||||
rescue
|
rescue
|
||||||
_ -> {%ThemeSettings{}, ""}
|
_ -> {%ThemeSettings{}, ""}
|
||||||
|
|||||||
@ -11,7 +11,9 @@ defmodule SimpleshopThemeWeb.ShopLive.About do
|
|||||||
|
|
||||||
generated_css =
|
generated_css =
|
||||||
case CSSCache.get() do
|
case CSSCache.get() do
|
||||||
{:ok, css} -> css
|
{:ok, css} ->
|
||||||
|
css
|
||||||
|
|
||||||
:miss ->
|
:miss ->
|
||||||
css = CSSGenerator.generate(theme_settings)
|
css = CSSGenerator.generate(theme_settings)
|
||||||
CSSCache.put(css)
|
CSSCache.put(css)
|
||||||
|
|||||||
@ -11,7 +11,9 @@ defmodule SimpleshopThemeWeb.ShopLive.Cart do
|
|||||||
|
|
||||||
generated_css =
|
generated_css =
|
||||||
case CSSCache.get() do
|
case CSSCache.get() do
|
||||||
{:ok, css} -> css
|
{:ok, css} ->
|
||||||
|
css
|
||||||
|
|
||||||
:miss ->
|
:miss ->
|
||||||
css = CSSGenerator.generate(theme_settings)
|
css = CSSGenerator.generate(theme_settings)
|
||||||
CSSCache.put(css)
|
CSSCache.put(css)
|
||||||
@ -24,9 +26,11 @@ defmodule SimpleshopThemeWeb.ShopLive.Cart do
|
|||||||
# For now, use preview data for cart items
|
# For now, use preview data for cart items
|
||||||
# In a real implementation, this would come from session/database
|
# In a real implementation, this would come from session/database
|
||||||
cart_page_items = PreviewData.cart_items()
|
cart_page_items = PreviewData.cart_items()
|
||||||
cart_page_subtotal = Enum.reduce(cart_page_items, 0, fn item, acc ->
|
|
||||||
acc + item.product.price * item.quantity
|
cart_page_subtotal =
|
||||||
end)
|
Enum.reduce(cart_page_items, 0, fn item, acc ->
|
||||||
|
acc + item.product.price * item.quantity
|
||||||
|
end)
|
||||||
|
|
||||||
socket =
|
socket =
|
||||||
socket
|
socket
|
||||||
|
|||||||
@ -20,7 +20,9 @@ defmodule SimpleshopThemeWeb.ShopLive.Collection do
|
|||||||
|
|
||||||
generated_css =
|
generated_css =
|
||||||
case CSSCache.get() do
|
case CSSCache.get() do
|
||||||
{:ok, css} -> css
|
{:ok, css} ->
|
||||||
|
css
|
||||||
|
|
||||||
:miss ->
|
:miss ->
|
||||||
css = CSSGenerator.generate(theme_settings)
|
css = CSSGenerator.generate(theme_settings)
|
||||||
CSSCache.put(css)
|
CSSCache.put(css)
|
||||||
@ -82,7 +84,9 @@ defmodule SimpleshopThemeWeb.ShopLive.Collection do
|
|||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_event("sort_changed", %{"sort" => sort}, socket) do
|
def handle_event("sort_changed", %{"sort" => sort}, socket) do
|
||||||
slug = if socket.assigns.current_category, do: socket.assigns.current_category.slug, else: "all"
|
slug =
|
||||||
|
if socket.assigns.current_category, do: socket.assigns.current_category.slug, else: "all"
|
||||||
|
|
||||||
{:noreply, push_patch(socket, to: ~p"/collections/#{slug}?sort=#{sort}")}
|
{:noreply, push_patch(socket, to: ~p"/collections/#{slug}?sort=#{sort}")}
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -100,7 +104,10 @@ defmodule SimpleshopThemeWeb.ShopLive.Collection do
|
|||||||
@impl true
|
@impl true
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<div class="shop-container min-h-screen pb-20 md:pb-0" style="background-color: var(--t-surface-base); font-family: var(--t-font-body); color: var(--t-text-primary);">
|
<div
|
||||||
|
class="shop-container min-h-screen pb-20 md:pb-0"
|
||||||
|
style="background-color: var(--t-surface-base); font-family: var(--t-font-body); color: var(--t-text-primary);"
|
||||||
|
>
|
||||||
<SimpleshopThemeWeb.ShopComponents.skip_link />
|
<SimpleshopThemeWeb.ShopComponents.skip_link />
|
||||||
|
|
||||||
<%= if @theme_settings.announcement_bar do %>
|
<%= if @theme_settings.announcement_bar do %>
|
||||||
@ -145,7 +152,11 @@ defmodule SimpleshopThemeWeb.ShopLive.Collection do
|
|||||||
<%= if @products == [] do %>
|
<%= if @products == [] do %>
|
||||||
<div class="text-center py-16" style="color: var(--t-text-secondary);">
|
<div class="text-center py-16" style="color: var(--t-text-secondary);">
|
||||||
<p class="text-lg">No products found in this collection.</p>
|
<p class="text-lg">No products found in this collection.</p>
|
||||||
<.link navigate={~p"/collections/all"} class="mt-4 inline-block underline" style="color: var(--t-text-accent);">
|
<.link
|
||||||
|
navigate={~p"/collections/all"}
|
||||||
|
class="mt-4 inline-block underline"
|
||||||
|
style="color: var(--t-text-accent);"
|
||||||
|
>
|
||||||
View all products
|
View all products
|
||||||
</.link>
|
</.link>
|
||||||
</div>
|
</div>
|
||||||
@ -155,9 +166,15 @@ defmodule SimpleshopThemeWeb.ShopLive.Collection do
|
|||||||
|
|
||||||
<SimpleshopThemeWeb.ShopComponents.shop_footer theme_settings={@theme_settings} mode={@mode} />
|
<SimpleshopThemeWeb.ShopComponents.shop_footer theme_settings={@theme_settings} mode={@mode} />
|
||||||
|
|
||||||
<SimpleshopThemeWeb.ShopComponents.cart_drawer cart_items={@cart_items} subtotal={@cart_subtotal} mode={@mode} />
|
<SimpleshopThemeWeb.ShopComponents.cart_drawer
|
||||||
|
cart_items={@cart_items}
|
||||||
|
subtotal={@cart_subtotal}
|
||||||
|
mode={@mode}
|
||||||
|
/>
|
||||||
|
|
||||||
<SimpleshopThemeWeb.ShopComponents.search_modal hint_text={~s(Try searching for "mountain", "forest", or "ocean")} />
|
<SimpleshopThemeWeb.ShopComponents.search_modal hint_text={
|
||||||
|
~s(Try searching for "mountain", "forest", or "ocean")
|
||||||
|
} />
|
||||||
|
|
||||||
<SimpleshopThemeWeb.ShopComponents.mobile_bottom_nav active_page="collection" mode={@mode} />
|
<SimpleshopThemeWeb.ShopComponents.mobile_bottom_nav active_page="collection" mode={@mode} />
|
||||||
</div>
|
</div>
|
||||||
@ -176,10 +193,12 @@ defmodule SimpleshopThemeWeb.ShopLive.Collection do
|
|||||||
"px-4 py-2 rounded-full text-sm transition-colors",
|
"px-4 py-2 rounded-full text-sm transition-colors",
|
||||||
if(@current_slug == nil, do: "font-medium", else: "hover:opacity-80")
|
if(@current_slug == nil, do: "font-medium", else: "hover:opacity-80")
|
||||||
]}
|
]}
|
||||||
style={if(@current_slug == nil,
|
style={
|
||||||
do: "background-color: var(--t-accent); color: var(--t-text-on-accent);",
|
if(@current_slug == nil,
|
||||||
else: "background-color: var(--t-surface-raised); color: var(--t-text-primary);"
|
do: "background-color: var(--t-accent); color: var(--t-text-on-accent);",
|
||||||
)}
|
else: "background-color: var(--t-surface-raised); color: var(--t-text-primary);"
|
||||||
|
)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
All
|
All
|
||||||
</.link>
|
</.link>
|
||||||
@ -192,10 +211,12 @@ defmodule SimpleshopThemeWeb.ShopLive.Collection do
|
|||||||
"px-4 py-2 rounded-full text-sm transition-colors",
|
"px-4 py-2 rounded-full text-sm transition-colors",
|
||||||
if(@current_slug == category.slug, do: "font-medium", else: "hover:opacity-80")
|
if(@current_slug == category.slug, do: "font-medium", else: "hover:opacity-80")
|
||||||
]}
|
]}
|
||||||
style={if(@current_slug == category.slug,
|
style={
|
||||||
do: "background-color: var(--t-accent); color: var(--t-text-on-accent);",
|
if(@current_slug == category.slug,
|
||||||
else: "background-color: var(--t-surface-raised); color: var(--t-text-primary);"
|
do: "background-color: var(--t-accent); color: var(--t-text-on-accent);",
|
||||||
)}
|
else: "background-color: var(--t-surface-raised); color: var(--t-text-primary);"
|
||||||
|
)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{category.name}
|
{category.name}
|
||||||
</.link>
|
</.link>
|
||||||
|
|||||||
@ -11,7 +11,9 @@ defmodule SimpleshopThemeWeb.ShopLive.Contact do
|
|||||||
|
|
||||||
generated_css =
|
generated_css =
|
||||||
case CSSCache.get() do
|
case CSSCache.get() do
|
||||||
{:ok, css} -> css
|
{:ok, css} ->
|
||||||
|
css
|
||||||
|
|
||||||
:miss ->
|
:miss ->
|
||||||
css = CSSGenerator.generate(theme_settings)
|
css = CSSGenerator.generate(theme_settings)
|
||||||
CSSCache.put(css)
|
CSSCache.put(css)
|
||||||
|
|||||||
@ -11,7 +11,9 @@ defmodule SimpleshopThemeWeb.ShopLive.Home do
|
|||||||
|
|
||||||
generated_css =
|
generated_css =
|
||||||
case CSSCache.get() do
|
case CSSCache.get() do
|
||||||
{:ok, css} -> css
|
{:ok, css} ->
|
||||||
|
css
|
||||||
|
|
||||||
:miss ->
|
:miss ->
|
||||||
css = CSSGenerator.generate(theme_settings)
|
css = CSSGenerator.generate(theme_settings)
|
||||||
CSSCache.put(css)
|
CSSCache.put(css)
|
||||||
|
|||||||
@ -11,7 +11,9 @@ defmodule SimpleshopThemeWeb.ShopLive.ProductShow do
|
|||||||
|
|
||||||
generated_css =
|
generated_css =
|
||||||
case CSSCache.get() do
|
case CSSCache.get() do
|
||||||
{:ok, css} -> css
|
{:ok, css} ->
|
||||||
|
css
|
||||||
|
|
||||||
:miss ->
|
:miss ->
|
||||||
css = CSSGenerator.generate(theme_settings)
|
css = CSSGenerator.generate(theme_settings)
|
||||||
CSSCache.put(css)
|
CSSCache.put(css)
|
||||||
|
|||||||
@ -10,6 +10,7 @@ defmodule SimpleshopThemeWeb.ThemeLive.Index do
|
|||||||
theme_settings = Settings.get_theme_settings()
|
theme_settings = Settings.get_theme_settings()
|
||||||
generated_css = CSSGenerator.generate(theme_settings)
|
generated_css = CSSGenerator.generate(theme_settings)
|
||||||
active_preset = Presets.detect_preset(theme_settings)
|
active_preset = Presets.detect_preset(theme_settings)
|
||||||
|
|
||||||
preview_data = %{
|
preview_data = %{
|
||||||
products: PreviewData.products(),
|
products: PreviewData.products(),
|
||||||
cart_items: PreviewData.cart_items(),
|
cart_items: PreviewData.cart_items(),
|
||||||
@ -361,7 +362,9 @@ defmodule SimpleshopThemeWeb.ThemeLive.Index do
|
|||||||
|
|
||||||
defp preview_page(%{page: :cart} = assigns) do
|
defp preview_page(%{page: :cart} = assigns) do
|
||||||
cart_items = assigns.preview_data.cart_items
|
cart_items = assigns.preview_data.cart_items
|
||||||
subtotal = Enum.reduce(cart_items, 0, fn item, acc -> acc + item.product.price * item.quantity end)
|
|
||||||
|
subtotal =
|
||||||
|
Enum.reduce(cart_items, 0, fn item, acc -> acc + item.product.price * item.quantity end)
|
||||||
|
|
||||||
assigns =
|
assigns =
|
||||||
assigns
|
assigns
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -126,6 +126,7 @@ defmodule SimpleshopThemeWeb.UserLive.Login do
|
|||||||
end
|
end
|
||||||
|
|
||||||
defp local_mail_adapter? do
|
defp local_mail_adapter? do
|
||||||
Application.get_env(:simpleshop_theme, SimpleshopTheme.Mailer)[:adapter] == Swoosh.Adapters.Local
|
Application.get_env(:simpleshop_theme, SimpleshopTheme.Mailer)[:adapter] ==
|
||||||
|
Swoosh.Adapters.Local
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -4,7 +4,10 @@ defmodule SimpleshopTheme.Repo.Migrations.CreateProducts do
|
|||||||
def change do
|
def change do
|
||||||
create table(:products, primary_key: false) do
|
create table(:products, primary_key: false) do
|
||||||
add :id, :binary_id, primary_key: true
|
add :id, :binary_id, primary_key: true
|
||||||
add :provider_connection_id, references(:provider_connections, type: :binary_id, on_delete: :delete_all), null: false
|
|
||||||
|
add :provider_connection_id,
|
||||||
|
references(:provider_connections, type: :binary_id, on_delete: :delete_all), null: false
|
||||||
|
|
||||||
add :provider_product_id, :string, null: false
|
add :provider_product_id, :string, null: false
|
||||||
add :title, :string, null: false
|
add :title, :string, null: false
|
||||||
add :description, :text
|
add :description, :text
|
||||||
|
|||||||
@ -4,7 +4,10 @@ defmodule SimpleshopTheme.Repo.Migrations.CreateProductImages do
|
|||||||
def change do
|
def change do
|
||||||
create table(:product_images, primary_key: false) do
|
create table(:product_images, primary_key: false) do
|
||||||
add :id, :binary_id, primary_key: true
|
add :id, :binary_id, primary_key: true
|
||||||
add :product_id, references(:products, type: :binary_id, on_delete: :delete_all), null: false
|
|
||||||
|
add :product_id, references(:products, type: :binary_id, on_delete: :delete_all),
|
||||||
|
null: false
|
||||||
|
|
||||||
add :src, :string, null: false
|
add :src, :string, null: false
|
||||||
add :position, :integer, default: 0, null: false
|
add :position, :integer, default: 0, null: false
|
||||||
add :alt, :string
|
add :alt, :string
|
||||||
|
|||||||
@ -4,7 +4,10 @@ defmodule SimpleshopTheme.Repo.Migrations.CreateProductVariants do
|
|||||||
def change do
|
def change do
|
||||||
create table(:product_variants, primary_key: false) do
|
create table(:product_variants, primary_key: false) do
|
||||||
add :id, :binary_id, primary_key: true
|
add :id, :binary_id, primary_key: true
|
||||||
add :product_id, references(:products, type: :binary_id, on_delete: :delete_all), null: false
|
|
||||||
|
add :product_id, references(:products, type: :binary_id, on_delete: :delete_all),
|
||||||
|
null: false
|
||||||
|
|
||||||
add :provider_variant_id, :string, null: false
|
add :provider_variant_id, :string, null: false
|
||||||
add :title, :string, null: false
|
add :title, :string, null: false
|
||||||
add :sku, :string
|
add :sku, :string
|
||||||
|
|||||||
@ -70,6 +70,7 @@ defmodule SimpleshopTheme.Media.SVGRecolorerTest do
|
|||||||
svg = """
|
svg = """
|
||||||
<svg><style>.st0{fill:#FFFFFF;}.st1{fill:#EF1D1D;stroke:#000000;}</style><path class="st0"/></svg>
|
<svg><style>.st0{fill:#FFFFFF;}.st1{fill:#EF1D1D;stroke:#000000;}</style><path class="st0"/></svg>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
result = SVGRecolorer.recolor(svg, "#ff6600")
|
result = SVGRecolorer.recolor(svg, "#ff6600")
|
||||||
assert result =~ "fill:#ff6600"
|
assert result =~ "fill:#ff6600"
|
||||||
refute result =~ "#FFFFFF"
|
refute result =~ "#FFFFFF"
|
||||||
@ -80,6 +81,7 @@ defmodule SimpleshopTheme.Media.SVGRecolorerTest do
|
|||||||
svg = """
|
svg = """
|
||||||
<svg><style>.st1{stroke:#000000;stroke-miterlimit:10;}</style><path class="st1"/></svg>
|
<svg><style>.st1{stroke:#000000;stroke-miterlimit:10;}</style><path class="st1"/></svg>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
result = SVGRecolorer.recolor(svg, "#ff6600")
|
result = SVGRecolorer.recolor(svg, "#ff6600")
|
||||||
assert result =~ "stroke:#ff6600"
|
assert result =~ "stroke:#ff6600"
|
||||||
refute result =~ "#000000"
|
refute result =~ "#000000"
|
||||||
@ -89,6 +91,7 @@ defmodule SimpleshopTheme.Media.SVGRecolorerTest do
|
|||||||
svg = """
|
svg = """
|
||||||
<svg><style>.st0{fill:none;stroke:#000;}</style><path class="st0"/></svg>
|
<svg><style>.st0{fill:none;stroke:#000;}</style><path class="st0"/></svg>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
result = SVGRecolorer.recolor(svg, "#ff6600")
|
result = SVGRecolorer.recolor(svg, "#ff6600")
|
||||||
assert result =~ "fill:none"
|
assert result =~ "fill:none"
|
||||||
assert result =~ "stroke:#ff6600"
|
assert result =~ "stroke:#ff6600"
|
||||||
@ -98,6 +101,7 @@ defmodule SimpleshopTheme.Media.SVGRecolorerTest do
|
|||||||
svg = """
|
svg = """
|
||||||
<svg><style>.icon{fill:black;stroke:white;}</style><path class="icon"/></svg>
|
<svg><style>.icon{fill:black;stroke:white;}</style><path class="icon"/></svg>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
result = SVGRecolorer.recolor(svg, "#ff6600")
|
result = SVGRecolorer.recolor(svg, "#ff6600")
|
||||||
assert result =~ "fill:#ff6600"
|
assert result =~ "fill:#ff6600"
|
||||||
assert result =~ "stroke:#ff6600"
|
assert result =~ "stroke:#ff6600"
|
||||||
|
|||||||
@ -96,7 +96,10 @@ defmodule SimpleshopTheme.Products.ProductTest do
|
|||||||
|
|
||||||
test "stores provider_data as map", %{conn: conn} do
|
test "stores provider_data as map", %{conn: conn} do
|
||||||
provider_data = %{"blueprint_id" => 145, "print_provider_id" => 29, "extra" => "value"}
|
provider_data = %{"blueprint_id" => 145, "print_provider_id" => 29, "extra" => "value"}
|
||||||
attrs = valid_product_attrs(%{provider_connection_id: conn.id, provider_data: provider_data})
|
|
||||||
|
attrs =
|
||||||
|
valid_product_attrs(%{provider_connection_id: conn.id, provider_data: provider_data})
|
||||||
|
|
||||||
changeset = Product.changeset(%Product{}, attrs)
|
changeset = Product.changeset(%Product{}, attrs)
|
||||||
|
|
||||||
assert changeset.valid?
|
assert changeset.valid?
|
||||||
|
|||||||
@ -437,7 +437,9 @@ defmodule SimpleshopTheme.ProductsTest do
|
|||||||
|
|
||||||
test "updates existing variants" do
|
test "updates existing variants" do
|
||||||
product = product_fixture()
|
product = product_fixture()
|
||||||
existing = product_variant_fixture(%{product: product, provider_variant_id: "v1", price: 2000})
|
|
||||||
|
existing =
|
||||||
|
product_variant_fixture(%{product: product, provider_variant_id: "v1", price: 2000})
|
||||||
|
|
||||||
variants = [
|
variants = [
|
||||||
%{provider_variant_id: "v1", title: "Small Updated", price: 2200}
|
%{provider_variant_id: "v1", title: "Small Updated", price: 2200}
|
||||||
|
|||||||
@ -76,13 +76,15 @@ defmodule SimpleshopTheme.SettingsTest do
|
|||||||
# Cache should now contain new CSS with the red accent color
|
# Cache should now contain new CSS with the red accent color
|
||||||
{:ok, updated_css} = CSSCache.get()
|
{:ok, updated_css} = CSSCache.get()
|
||||||
assert updated_css =~ ".themed {"
|
assert updated_css =~ ".themed {"
|
||||||
assert updated_css =~ "--t-accent-h: 0" # Red = hue 0
|
# Red = hue 0
|
||||||
|
assert updated_css =~ "--t-accent-h: 0"
|
||||||
|
|
||||||
# Change to blue
|
# Change to blue
|
||||||
{:ok, _settings} = Settings.update_theme_settings(%{accent_color: "#0000ff"})
|
{:ok, _settings} = Settings.update_theme_settings(%{accent_color: "#0000ff"})
|
||||||
|
|
||||||
{:ok, blue_css} = CSSCache.get()
|
{:ok, blue_css} = CSSCache.get()
|
||||||
assert blue_css =~ "--t-accent-h: 240" # Blue = hue 240
|
# Blue = hue 240
|
||||||
|
assert blue_css =~ "--t-accent-h: 240"
|
||||||
|
|
||||||
# Restore default
|
# Restore default
|
||||||
CSSCache.warm()
|
CSSCache.warm()
|
||||||
|
|||||||
@ -61,7 +61,9 @@ defmodule SimpleshopTheme.Sync.ProductSyncWorkerTest do
|
|||||||
|
|
||||||
test "new/2 with scheduled_at creates scheduled job" do
|
test "new/2 with scheduled_at creates scheduled job" do
|
||||||
future = DateTime.add(DateTime.utc_now(), 60, :second)
|
future = DateTime.add(DateTime.utc_now(), 60, :second)
|
||||||
changeset = ProductSyncWorker.new(%{provider_connection_id: "test-id"}, scheduled_at: future)
|
|
||||||
|
changeset =
|
||||||
|
ProductSyncWorker.new(%{provider_connection_id: "test-id"}, scheduled_at: future)
|
||||||
|
|
||||||
assert changeset.changes.scheduled_at == future
|
assert changeset.changes.scheduled_at == future
|
||||||
end
|
end
|
||||||
|
|||||||
@ -51,6 +51,7 @@ defmodule SimpleshopTheme.Theme.PreviewDataTest do
|
|||||||
|
|
||||||
if product.hover_image_url do
|
if product.hover_image_url do
|
||||||
assert is_binary(product.hover_image_url)
|
assert is_binary(product.hover_image_url)
|
||||||
|
|
||||||
assert String.starts_with?(product.hover_image_url, "/") or
|
assert String.starts_with?(product.hover_image_url, "/") or
|
||||||
String.starts_with?(product.hover_image_url, "http")
|
String.starts_with?(product.hover_image_url, "http")
|
||||||
end
|
end
|
||||||
|
|||||||
@ -2,7 +2,9 @@ defmodule SimpleshopThemeWeb.ErrorJSONTest do
|
|||||||
use SimpleshopThemeWeb.ConnCase, async: true
|
use SimpleshopThemeWeb.ConnCase, async: true
|
||||||
|
|
||||||
test "renders 404" do
|
test "renders 404" do
|
||||||
assert SimpleshopThemeWeb.ErrorJSON.render("404.json", %{}) == %{errors: %{detail: "Not Found"}}
|
assert SimpleshopThemeWeb.ErrorJSON.render("404.json", %{}) == %{
|
||||||
|
errors: %{detail: "Not Found"}
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "renders 500" do
|
test "renders 500" do
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user