Compare commits

..
Author SHA1 Message Date
devops ca26c6ebea fix(ecommerce): boton duplicado en mobile y leftovers fucsia en pagina de producto
Reportado en produccion: en mobile aparecian dos botones 'Añadir al
carrito' apilados. ProductPurchase.tsx nunca ocultaba su boton en
mobile, y MobileAddToCart.tsx (barra fija abajo, solo lg:hidden) ya
cubre esa misma accion ahi -- se agrega hidden lg:inline-flex al
primero para que solo uno este visible por breakpoint.

De paso, dos leftovers del esquema arcoiris original en la misma
pagina, vistos en la misma sesion de pruebas: el badge de variante
seleccionada (border-fuchsia-500 bg-fuchsia-50 text-fuchsia-700 -> azul
de marca) y la etiqueta de categoria/coleccion (text-fuchsia-600 ->
ari-coral).
2026-08-28 14:14:23 +00:00
devops 12d3c692d3 Merge fix/adr0008-logo-circular-header into main
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 18s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 8m27s
2026-08-28 14:08:37 +00:00
devops 9c441032de feat(ecommerce): logo circular en el header (pedido del usuario)
Reemplaza el lockup rectangular (logo-ari.svg) por un isotipo circular
nuevo (logo-ari-circular.svg) con el icono mariposa + wordmark 'ARI
shopping' integrados dentro del mismo circulo azul -- el formato que
tenia la version previa a ADR 0008, preferido sobre el rectangulo
segun mockup de referencia del usuario. El footer conserva el lockup
rectangular, donde si tiene sentido como bloque de color autocontenido
sobre el fondo oscuro.
2026-08-28 14:08:35 +00:00
devops 603f4b963d chore: release v1.0.195 [skip ci] 2026-08-28 06:32:19 +00:00
devops ac37774245 Merge fix/adr0008-tiles-pastel into main
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 18s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 7m1s
2026-08-28 06:25:03 +00:00
devops 7aa9f40abc feat(ecommerce): ADR 0008 sub-fase 4 - tiles de categoria pastel
category-tiles.tsx (PromoTile, compartido entre home y grid de
catalogo) nunca se toco en ninguna sub-fase de ADR 0008 -- la sub-fase
4 ('Home: hero, tiles, secciones') quedo pendiente de implementar
(confirmado: no existe merge fix/adr0008-*-subfase4-* en el historial).
Seguia con gradientes saturados rojo/violeta/magenta/cian del esquema
arcoiris original, confirmado visualmente en produccion.

Reemplaza los gradientes por fondos pastel solidos (amber/sky/rose/
emerald/orange/violet-100, patron Walmart-inspirado), texto oscuro
sobre el pastel, boton circular de accion en azul de marca
(--color-ari-marino) en vez de blanco/negro generico, y los acentos
fucsia/cian del encabezado de seccion por los tokens de marca.
2026-08-28 06:22:47 +00:00
devops 617a69d58a chore: release v1.0.194 [skip ci] 2026-08-28 06:15:43 +00:00
devops 09a8698f7e Merge fix/adr0008-buscador-un-solo-foco into main
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 21s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 6m22s
2026-08-28 06:09:08 +00:00
devops 23700c5b1d fix(ecommerce): buscador usa un solo indicador de foco (no dos)
El outline de accesibilidad global (input:focus-visible, azul de
marca, globals.css) y el indicador de foco propio del wrapper
(focus-within:border-ari-marino + ring amarillo) se mostraban ambos a
la vez -- redondear el outline (commit anterior) evito el rectangulo
recto pero seguia leyendose como dos bordes anidados, reportado en
produccion (v1.0.193).

focus-visible:outline-none en el input iguala la especificidad de la
regla global (mismo patron que ya usa buttonVariants en button.tsx) y
deja el indicador de foco del wrapper como el unico visible -- no se
pierde accesibilidad, se elimina la duplicacion.
2026-08-28 06:09:06 +00:00
devops 5c173d5f40 chore: release v1.0.193 [skip ci] 2026-08-28 06:02:07 +00:00
devops d0a3554959 Merge fix/adr0008-buscador-outline-a11y-redondeado into main
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 18s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 8m32s
2026-08-28 05:53:17 +00:00
devops 75dedc4e67 fix(ecommerce): outline de accesibilidad del buscador sigue el pill
globals.css define input:focus-visible { outline: 3px solid
rgb(0 85 184 / .5); ... } como indicador de foco por teclado global,
intencional (no se toca). Le gana en especificidad CSS a la utilidad
outline-none de Tailwind, asi que seguia mostrandose sobre el input
propio del buscador (commit anterior) -- pero como ese input no tenia
border-radius, se veia como un rectangulo de esquinas rectas
superpuesto al pill redondeado, reportado en produccion (v1.0.192).

Agrega rounded-full al input para que el mismo outline (que se debe
conservar) siga el contorno del pill en vez de cortarlo.
2026-08-28 05:53:15 +00:00
devops 801db95aa8 chore: release v1.0.192 [skip ci] 2026-08-28 05:45:57 +00:00
devops 6df24abcb9 Merge fix/adr0008-buscador-ring-input-propio into main
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 18s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 7m49s
2026-08-28 05:37:51 +00:00
devops a6291ffe14 fix(ecommerce): buscador usa input propio en vez del <Input> compartido
El fix anterior (focus:border-0 focus:ring-0) no elimino de forma
confiable el focus:ring-4 focus:ring-cyan-300/30 hardcodeado del
componente <Input> compartido dentro de este contenedor compuesto
(input + boton circular en el mismo wrapper) -- reportado en
produccion (v1.0.191): un segundo ring amarillo se superponia y
cortaba visualmente el boton de la lupa al hacer click.

En vez de seguir peleando el override via tailwind-merge, el buscador
deja de usar el <Input> compartido y usa un <input> nativo con sus
propias clases minimas, sin nada que sobreescribir.
2026-08-28 05:37:50 +00:00
devops 030bf2712a chore: release v1.0.191 [skip ci] 2026-08-28 05:20:14 +00:00
devops f5ddb63c8a Merge fix/adr0008-buscador-doble-ring into main
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 19s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 8m3s
2026-08-28 05:11:56 +00:00
devops d536b0bb8b fix(ecommerce): quita el doble ring de foco del buscador
El Input base (components/ui/input.tsx) trae focus:border-cyan-500 y
focus:ring-4 focus:ring-cyan-300/30 hardcodeados. La correccion
anterior del buscador solo anulaba focus-visible:ring-0, una variante
distinta a :focus -- el ring cian del componente base seguia
disparandose al hacer click, superpuesto al ring amarillo del wrapper
nuevo (dos anillos visibles a la vez, reportado por el usuario en
produccion tras el deploy de v1.0.190).

focus:border-0 focus:ring-0 anula correctamente ambas utilidades del
Input base via tailwind-merge (mismo variant+propiedad).
2026-08-28 05:10:22 +00:00
devops 260c7076e2 chore: release v1.0.190 [skip ci] 2026-08-28 05:06:07 +00:00
devops 59024cd6e5 Merge fix/adr0008-buscador-azul-amarillo into main
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 20s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 7m20s
2026-08-28 04:58:28 +00:00
7 changed files with 66 additions and 20 deletions

No files matched your search

@@ -33,5 +33,5 @@ export default async function ProductPage({ params }: ProductPageProps) {
if (!product) notFound();
const products = await getProducts();
const recommended = products.filter((candidate) => candidate.id !== product.id && (candidate.category === product.category || candidate.collection === product.collection)).slice(0, 8);
return <><section className="mx-auto grid max-w-7xl gap-10 px-4 py-10 lg:grid-cols-[1.08fr_.92fr] lg:py-16"><ProductGallery images={product.images} name={product.name} /><div><span className="text-xs font-black uppercase tracking-[.18em] text-fuchsia-600">{product.category} · {product.collection}</span><h1 className="mt-3 text-4xl font-black tracking-tight sm:text-6xl">{product.name}</h1><p className="mt-5 text-lg leading-8 text-slate-600">{product.description}</p><div className="mt-8"><ProductPurchase product={product} /></div><Accordion type="single" collapsible className="mt-8"><AccordionItem value="details"><AccordionTrigger>Detalles del producto</AccordionTrigger><AccordionContent>Marca: {product.brand}. Edad recomendada: {product.ageRange}. La disponibilidad y presentación final se confirman con Ari Shopping.</AccordionContent></AccordionItem><AccordionItem value="shipping"><AccordionTrigger>Envíos y entregas</AccordionTrigger><AccordionContent>Coordinamos envíos nacionales y entrega según ubicación. Los tiempos se confirman durante la cotización.</AccordionContent></AccordionItem></Accordion></div></section>{recommended.length > 0 && <section className="mx-auto max-w-7xl px-4 pb-24"><h2 className="mb-7 text-3xl font-black">También te puede gustar</h2><ProductCarousel products={recommended} /></section>}<MobileAddToCart product={product} /></>;
return <><section className="mx-auto grid max-w-7xl gap-10 px-4 py-10 lg:grid-cols-[1.08fr_.92fr] lg:py-16"><ProductGallery images={product.images} name={product.name} /><div><span className="text-xs font-black uppercase tracking-[.18em] text-ari-coral">{product.category} · {product.collection}</span><h1 className="mt-3 text-4xl font-black tracking-tight sm:text-6xl">{product.name}</h1><p className="mt-5 text-lg leading-8 text-slate-600">{product.description}</p><div className="mt-8"><ProductPurchase product={product} /></div><Accordion type="single" collapsible className="mt-8"><AccordionItem value="details"><AccordionTrigger>Detalles del producto</AccordionTrigger><AccordionContent>Marca: {product.brand}. Edad recomendada: {product.ageRange}. La disponibilidad y presentación final se confirman con Ari Shopping.</AccordionContent></AccordionItem><AccordionItem value="shipping"><AccordionTrigger>Envíos y entregas</AccordionTrigger><AccordionContent>Coordinamos envíos nacionales y entrega según ubicación. Los tiempos se confirman durante la cotización.</AccordionContent></AccordionItem></Accordion></div></section>{recommended.length > 0 && <section className="mx-auto max-w-7xl px-4 pb-24"><h2 className="mb-7 text-3xl font-black">También te puede gustar</h2><ProductCarousel products={recommended} /></section>}<MobileAddToCart product={product} /></>;
}
@@ -10,16 +10,20 @@ type TileContent = { subtitle: string; image?: string; color: string };
// (ver ADR 0005) -- solo se mapean imagen/subtitulo para las que ya tienen
// un asset en public/images/categories/. Las demas caen al tile de solo
// gradiente en vez de mostrar una imagen que no les corresponde.
// Fondos pastel solidos (patron Walmart-inspirado, ADR 0008 sub-fase 4)
// en vez de los gradientes saturados originales del esquema arcoiris --
// un tono pastel distinto por categoria, no una escala de marca (serian
// todos casi iguales), pero coordinados en la misma temperatura suave.
const tileContent: Record<string, TileContent> = {
juguetes: { subtitle: "Personajes que inspiran", image: "/images/categories/figuras.webp", color: "from-yellow-300 to-orange-400" },
"mochilas-y-morrales": { subtitle: "Estilo para cada aventura", image: "/images/categories/mochilas.webp", color: "from-cyan-400 to-blue-500" },
"bebes-y-primera-infancia": { subtitle: "Primeros descubrimientos", color: "from-pink-300 to-fuchsia-400" },
educativos: { subtitle: "Aprender jugando", color: "from-emerald-400 to-teal-600" },
"accion-y-aventura": { subtitle: "Para explorar sin límites", color: "from-red-500 to-rose-700" },
variedades: { subtitle: "Un poco de todo", color: "from-violet-400 to-purple-600" },
juguetes: { subtitle: "Personajes que inspiran", image: "/images/categories/figuras.webp", color: "bg-amber-100" },
"mochilas-y-morrales": { subtitle: "Estilo para cada aventura", image: "/images/categories/mochilas.webp", color: "bg-sky-100" },
"bebes-y-primera-infancia": { subtitle: "Primeros descubrimientos", color: "bg-rose-100" },
educativos: { subtitle: "Aprender jugando", color: "bg-emerald-100" },
"accion-y-aventura": { subtitle: "Para explorar sin límites", color: "bg-orange-100" },
variedades: { subtitle: "Un poco de todo", color: "bg-violet-100" },
};
const defaultTile: TileContent = { subtitle: "Explora esta categoría", color: "from-slate-400 to-slate-600" };
const defaultTile: TileContent = { subtitle: "Explora esta categoría", color: "bg-slate-100" };
// Tile individual reutilizado tanto por la seccion de mundos del home
// como por el grid del catalogo (tiles promocionales intercalados,
@@ -31,20 +35,20 @@ export function PromoTile({ category, className = "" }: { category: Category; cl
return (
<Link
href={`/catalog?category=${encodeURIComponent(category.name)}`}
className={cn(`group relative min-h-64 overflow-hidden rounded-[2rem] bg-gradient-to-br ${content.color} shadow-xl`, className)}
className={cn(`group relative min-h-64 overflow-hidden rounded-[2rem] ${content.color} shadow-sm ring-1 ring-slate-900/5`, className)}
>
{content.image && (
<>
<Image src={content.image} alt={category.name} fill sizes="(max-width: 640px) 100vw, (max-width: 1024px) 33vw, 16vw" className="object-cover transition duration-500 group-hover:scale-105" />
<div className="absolute inset-0 bg-gradient-to-t from-slate-950/80 via-transparent to-white/5" />
<div className="absolute inset-x-0 bottom-0 h-2/5 bg-gradient-to-t from-white/95 via-white/70 to-transparent" />
</>
)}
<div className="absolute inset-x-0 bottom-0 flex items-end justify-between p-6 text-white">
<div className="absolute inset-x-0 bottom-0 flex items-end justify-between p-6 text-slate-900">
<div>
<h3 className="text-xl font-black">{category.name}</h3>
<p className="mt-1 text-sm font-semibold text-white/80">{content.subtitle}</p>
<p className="mt-1 text-sm font-semibold text-slate-600">{content.subtitle}</p>
</div>
<span className="grid size-11 shrink-0 place-items-center rounded-full bg-white text-slate-950 transition group-hover:rotate-45">
<span className="grid size-11 shrink-0 place-items-center rounded-full bg-ari-marino text-white transition group-hover:rotate-45">
<ArrowUpRight />
</span>
</div>
@@ -61,10 +65,10 @@ export function CategoryTiles({ categories }: { categories: Category[] }) {
<section className="mx-auto max-w-7xl px-4 py-14">
<div className="mb-8 flex items-end justify-between gap-4">
<div>
<span className="text-xs font-black uppercase tracking-[.18em] text-fuchsia-600">Explora por mundos</span>
<span className="text-xs font-black uppercase tracking-[.18em] text-ari-coral">Explora por mundos</span>
<h2 className="mt-2 text-4xl font-black tracking-tight sm:text-5xl">Encuentra tu próximo tesoro</h2>
</div>
<Link href="/catalog" className="hidden font-black text-cyan-700 sm:block">Ver todo →</Link>
<Link href="/catalog" className="hidden font-black text-ari-marino sm:block">Ver todo →</Link>
</div>
<div className="grid gap-5 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6">
{roots.map((category) => (
@@ -52,9 +52,13 @@ export function Navbar({ products, categories }: { products: Product[]; categori
<div className="relative overflow-visible bg-white">
<div className="pointer-events-none absolute inset-x-0 top-0 h-1 bg-ari-coral-claro" />
<div className="mx-auto grid max-w-7xl grid-cols-[auto_1fr_auto] items-center gap-4 px-4 py-4 lg:gap-8">
{/* Isotipo circular con icono + wordmark integrados (como en la
version previa a ADR 0008), pedido explicito del usuario en
vez del lockup rectangular. logo-ari.svg (rectangular) se
mantiene para el footer. */}
<Link href="/" aria-label="ARI shopping" className="shrink-0">
{/* eslint-disable-next-line @next/next/no-img-element -- vector propio, next/image no optimiza SVG sin habilitar dangerouslyAllowSVG */}
<img src="/images/brand/logo-ari.svg" alt="ARI shopping" className="h-11 w-auto lg:h-14" width={200} height={64} />
<img src="/images/brand/logo-ari-circular.svg" alt="ARI shopping" className="size-16 lg:size-20" width={200} height={200} />
</Link>
<PredictiveSearch />
<div className="flex items-center gap-2">
@@ -18,5 +18,5 @@ export function ProductPurchase({ product }: { product: Product }) {
selectedVariant.inventoryQuantity <= LOW_STOCK_THRESHOLD
? selectedVariant.inventoryQuantity
: null;
return <div><div className="mb-5 flex flex-wrap gap-2">{product.variants.map((variant) => <button key={variant.id} onClick={() => setVariantId(variant.id)} className={`rounded-full border px-4 py-2 text-sm font-bold ${variantId === variant.id ? "border-fuchsia-500 bg-fuchsia-50 text-fuchsia-700" : "border-slate-200"}`}>{variant.value}</button>)}</div><div className="mb-6 flex items-end gap-3"><strong className="text-3xl font-black">{formatMoney(product.price, product.currency)}</strong>{product.compareAtPrice && <del className="text-slate-400">{formatMoney(product.compareAtPrice, product.currency)}</del>}</div><Button variant="primary" size="lg" className="w-full" onClick={() => addItem(product, variantId)}><ShoppingBag />Añadir al carrito</Button><div className="mt-5 grid gap-3 rounded-2xl bg-slate-50 p-4 text-sm">{lowStock !== null ? <span className="flex items-center gap-2 font-bold text-amber-600"><TriangleAlert className="size-4" />Quedan {lowStock} unidades</span> : <span className="flex items-center gap-2 font-bold"><CheckCircle2 className="size-4 text-emerald-500" />Disponibilidad por confirmar</span>}<span className="flex items-center gap-2 font-bold"><Truck className="size-4 text-cyan-600" />Envíos nacionales</span></div></div>;
return <div><div className="mb-5 flex flex-wrap gap-2">{product.variants.map((variant) => <button key={variant.id} onClick={() => setVariantId(variant.id)} className={`rounded-full border px-4 py-2 text-sm font-bold ${variantId === variant.id ? "border-ari-marino bg-ari-marino text-white" : "border-slate-200"}`}>{variant.value}</button>)}</div><div className="mb-6 flex items-end gap-3"><strong className="text-3xl font-black">{formatMoney(product.price, product.currency)}</strong>{product.compareAtPrice && <del className="text-slate-400">{formatMoney(product.compareAtPrice, product.currency)}</del>}</div>{/* oculto en mobile: MobileAddToCart (barra fija abajo, lg:hidden) ya cubre esa misma accion ahi -- sin el hidden aqui, ambos se mostraban a la vez. */}<Button variant="primary" size="lg" className="hidden w-full lg:inline-flex" onClick={() => addItem(product, variantId)}><ShoppingBag />Añadir al carrito</Button><div className="mt-5 grid gap-3 rounded-2xl bg-slate-50 p-4 text-sm">{lowStock !== null ? <span className="flex items-center gap-2 font-bold text-amber-600"><TriangleAlert className="size-4" />Quedan {lowStock} unidades</span> : <span className="flex items-center gap-2 font-bold"><CheckCircle2 className="size-4 text-emerald-500" />Disponibilidad por confirmar</span>}<span className="flex items-center gap-2 font-bold"><Truck className="size-4 text-cyan-600" />Envíos nacionales</span></div></div>;
}
@@ -5,7 +5,6 @@ import Link from "next/link";
import { useRouter } from "next/navigation";
import { Search, X } from "lucide-react";
import { FormEvent, useEffect, useState } from "react";
import { Input } from "@/components/ui/input";
import type { Product } from "@/lib/headless/types";
export function PredictiveSearch() {
@@ -55,7 +54,29 @@ export function PredictiveSearch() {
return (
<form onSubmit={submit} className="relative w-full">
<div className="flex items-center rounded-full border-2 border-slate-200 bg-white pl-5 pr-1.5 shadow-sm transition focus-within:border-ari-marino focus-within:ring-4 focus-within:ring-ari-coral-claro/30">
<Input value={query} onChange={(event) => setQuery(event.target.value)} placeholder="Busca juguetes, mochilas, personajes…" className="h-[48px] border-0 bg-transparent p-0 shadow-none focus-visible:ring-0" />
{/* input propio (no el <Input> compartido) -- ese componente trae su
propio focus:ring-4 focus:ring-cyan-300/30 hardcodeado que no se
anulaba de forma confiable via tailwind-merge dentro de este
contenedor compuesto (input + boton circular), causando un
segundo ring visible al hacer foco. Mas simple y robusto no
heredar clases de foco que hay que pelear despues.
focus-visible:outline-none (no outline-none a secas): globals.css
define un outline de accesibilidad global por teclado
(input:focus-visible, azul de marca) que le gana en
especificidad a un outline-none plano. El wrapper de este
componente ya tiene su propio indicador de foco visible
(focus-within:border-ari-marino + ring amarillo, mismo patron
que button.tsx) que cumple el mismo proposito de accesibilidad
sin duplicarlo -- variante focus-visible: en vez de la base
iguala la especificidad de la regla global (mismo truco que ya
usa button.tsx) y evita el doble indicador de foco. */}
<input
value={query}
onChange={(event) => setQuery(event.target.value)}
placeholder="Busca juguetes, mochilas, personajes…"
className="h-[48px] w-full border-0 bg-transparent p-0 text-sm text-slate-950 focus-visible:outline-none"
/>
{query && <button type="button" aria-label="Limpiar búsqueda" className="mr-1 shrink-0 rounded-full p-1.5 text-slate-400 hover:bg-slate-100" onClick={() => setQuery("")}><X className="size-4" /></button>}
<button type="submit" aria-label="Buscar" className="grid size-10 shrink-0 place-items-center rounded-full bg-ari-marino text-white transition hover:brightness-110">
<Search className="size-4.5" />
@@ -25,7 +25,7 @@ spec:
runAsUser: 1001
containers:
- name: app
image: gitea.cruzcloud.net/devops/ecommerce-frontend:v1.0.189
image: gitea.cruzcloud.net/devops/ecommerce-frontend:v1.0.195
env:
- name: HEADLESS_PROVIDER
value: medusa
@@ -0,0 +1,17 @@
<!-- ADR 0008, paleta "Azul & Amarillo". Isotipo circular (formato de la
version previa a ADR 0008, pedido explicito del usuario en vez del
lockup rectangular de logo-ari.svg): mariposa geometrica de 4 elipses
+ wordmark "ARI shopping", todo dentro del mismo circulo azul.
Ver docs-portal/docs/decisiones/0008-identidad-navy-coral.md -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" role="img" aria-label="ARI shopping">
<circle cx="100" cy="100" r="98" fill="#0055B8"/>
<g transform="translate(100 68) scale(2.6) translate(-17 -11)">
<ellipse cx="10" cy="8" rx="9" ry="7" transform="rotate(-18 10 8)" fill="#FFC220"/>
<ellipse cx="24" cy="8" rx="9" ry="7" transform="rotate(18 24 8)" fill="#FFC220"/>
<ellipse cx="12" cy="16" rx="6" ry="5" transform="rotate(-10 12 16)" fill="#FFDD73"/>
<ellipse cx="22" cy="16" rx="6" ry="5" transform="rotate(10 22 16)" fill="#FFDD73"/>
<rect x="16" y="3" width="2" height="18" rx="1" fill="#0055B8"/>
</g>
<text x="100" y="132" text-anchor="middle" font-family="Poppins, ui-sans-serif, system-ui, sans-serif" font-weight="700" font-size="38" fill="#FFFFFF">ARI</text>
<text x="100" y="153" text-anchor="middle" font-family="Poppins, ui-sans-serif, system-ui, sans-serif" font-weight="700" font-size="14" letter-spacing="3" fill="#FFC220">shopping</text>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB