Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
137 commits
Select commit Hold shift + click to select a range
1a4dd5f
estrutura home page
murielpereira Apr 20, 2026
01bd980
⚡ Bolt: Inline image rendering in loops to remove N+1 overhead
google-labs-jules[bot] Apr 21, 2026
33f720a
🎨 Palette: Add "Skip to content" accessibility link
google-labs-jules[bot] Apr 21, 2026
7f72b0c
UX & A11y enhancements: added focus-visible and improved button states
google-labs-jules[bot] Apr 22, 2026
a5fdb36
Merge pull request #1 from murielpereira/bolt-perf-liquid-snippet-inl…
murielpereira Apr 22, 2026
fe4e9c1
Merge pull request #2 from murielpereira/palette-skip-to-content-1134…
murielpereira Apr 22, 2026
46962e0
Merge pull request #3 from murielpereira/palette/ux-a11y-improvements…
murielpereira Apr 22, 2026
6d79ed0
correcao layout carrinho
murielpereira Apr 22, 2026
ce96c40
ajuste na pdp
murielpereira Apr 22, 2026
abda49a
correcao .gitignore
murielpereira Apr 22, 2026
7b4ce58
ajuste carrosel pdp
murielpereira Apr 22, 2026
86957b2
🛡️ Sentinel: [Security Enhancement] Add noreferrer to target="_blank"…
google-labs-jules[bot] Apr 23, 2026
b6a9df4
🎨 Palette: Fix missing ARIA labels on dynamic cart updates
google-labs-jules[bot] Apr 23, 2026
d76b396
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 23, 2026
0d3d644
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 23, 2026
7a15ba9
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 23, 2026
373fb54
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 23, 2026
23d7836
Merge pull request #4 from murielpereira/sentinel/fix-noopener-norefe…
murielpereira Apr 23, 2026
513cb30
Merge pull request #5 from murielpereira/palette-dynamic-aria-6935361…
murielpereira Apr 23, 2026
49059e6
ajuste carrosel pdp
murielpereira Apr 23, 2026
f9f082c
ajuste responsividade
murielpereira Apr 23, 2026
c63dca7
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 23, 2026
1a202d6
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 23, 2026
c9082bc
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 23, 2026
eef7104
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 23, 2026
bc28829
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 23, 2026
6171ab5
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 23, 2026
7894d33
ajuste campo preços
murielpereira Apr 23, 2026
266446c
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 23, 2026
f026543
...
murielpereira Apr 23, 2026
31504db
ajuste config painel
murielpereira Apr 23, 2026
f45ef93
...
murielpereira Apr 23, 2026
c70e754
fix: desconto não aparecia nos cards de produto
murielpereira Apr 23, 2026
9c8d622
teste
murielpereira Apr 23, 2026
849d798
🛡️ Sentinel: [HIGH] Fix Reflected XSS in Search Template
google-labs-jules[bot] Apr 24, 2026
fff35b2
🎨 Palette: [A11y] Add semantic states to product buttons
google-labs-jules[bot] Apr 24, 2026
cf6d99a
Merge pull request #6 from murielpereira/sentinel-fix-xss-search-1523…
murielpereira Apr 24, 2026
9e537b2
Merge pull request #7 from murielpereira/palette/wishlist-a11y-575830…
murielpereira Apr 24, 2026
50da1b4
correção para mais de 250 variantes
murielpereira Apr 24, 2026
719c00a
ajuste swatches
murielpereira Apr 24, 2026
9aea889
personalizacao pingente
murielpereira Apr 24, 2026
bf96e1e
ajuste painel
murielpereira Apr 24, 2026
cd24740
🛡️ Sentinel: [HIGH] Fix Reflected XSS in article comment form
google-labs-jules[bot] Apr 25, 2026
3992072
🎨 Palette: Add focus-visible styles for keyboard accessibility
google-labs-jules[bot] Apr 25, 2026
de15ef6
⚡ Bolt: Optimize product-card rendering overhead using render-for syntax
google-labs-jules[bot] Apr 25, 2026
36d4d08
🛡️ Sentinel: [HIGH] Fix Reflected XSS in article comment form
google-labs-jules[bot] Apr 26, 2026
b193831
feat: Add `aria-controls` to product accordions for better accessibility
google-labs-jules[bot] Apr 27, 2026
caa6356
ajuste pingente
murielpereira Apr 27, 2026
2a38b4f
ajuste pingentes
murielpereira Apr 27, 2026
2eebf77
Merge pull request #8 from murielpereira/sentinel/fix-article-comment…
murielpereira Apr 27, 2026
6fe7301
Merge pull request #9 from murielpereira/palette-focus-visible-enhanc…
murielpereira Apr 27, 2026
45a1afa
Merge pull request #10 from murielpereira/bolt-liquid-render-for-opti…
murielpereira Apr 27, 2026
0d25763
Merge branch 'main' into sentinel-fix-xss-article-form-17525241253591…
murielpereira Apr 27, 2026
dd7b437
Merge pull request #11 from murielpereira/sentinel-fix-xss-article-fo…
murielpereira Apr 27, 2026
342f569
Merge branch 'main' into palette-add-aria-controls-accordions-7078954…
murielpereira Apr 27, 2026
b99d735
Merge pull request #14 from murielpereira/palette-add-aria-controls-a…
murielpereira Apr 27, 2026
feffb4d
config. pingente
murielpereira Apr 27, 2026
318d950
widget video
murielpereira Apr 27, 2026
6066be0
ajuste widget video
murielpereira Apr 27, 2026
8edde3b
correcao widget video
murielpereira Apr 27, 2026
b8ada1e
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 27, 2026
498dab4
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 27, 2026
511ea4c
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 27, 2026
d2b9807
🎨 Palette: Hide decorative icon ligatures from screen readers
google-labs-jules[bot] Apr 28, 2026
e094407
⚡ Bolt: Add `widths` to `image_tag` for responsive images
google-labs-jules[bot] Apr 28, 2026
5370b2c
Merge pull request #16 from murielpereira/palette-aria-hidden-icons-1…
murielpereira Apr 28, 2026
aefb8c9
Merge pull request #17 from murielpereira/bolt/responsive-image-width…
murielpereira Apr 28, 2026
39ae78b
🛡️ Sentinel: [HIGH] Sanitize user input to prevent DOM XSS in templates
google-labs-jules[bot] Apr 29, 2026
ed442e0
Eager load LCP image on product page
google-labs-jules[bot] Apr 29, 2026
39ada97
Merge pull request #18 from murielpereira/sentinel/fix-dom-xss-innerh…
murielpereira Apr 29, 2026
74c6dd9
Merge pull request #19 from murielpereira/bolt-optimize-lcp-259260269…
murielpereira Apr 29, 2026
b4401cb
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 29, 2026
f25d14d
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 29, 2026
4fafa68
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 29, 2026
2903b55
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 29, 2026
dc91144
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 29, 2026
cca6aaf
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 29, 2026
503df49
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 29, 2026
0862568
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 29, 2026
7324b5f
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 29, 2026
4294fb7
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 29, 2026
f1ffe95
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 29, 2026
4482460
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 29, 2026
9571150
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 29, 2026
614e5bb
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 29, 2026
b0b71f1
correcao carrinho
murielpereira Apr 29, 2026
03ad250
⚡ Bolt: Conditionally eager load LCP elements in image galleries
google-labs-jules[bot] Apr 30, 2026
f013042
Add aria-hidden to decorative icon ligatures
google-labs-jules[bot] Apr 30, 2026
5e897fb
Merge pull request #20 from murielpereira/bolt-fix-lcp-eager-load-171…
murielpereira Apr 30, 2026
549c4c9
Merge pull request #21 from murielpereira/jules-palette-a11y-icons-63…
murielpereira Apr 30, 2026
83b727d
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 30, 2026
0291ef3
Update from Shopify for theme shopify-theme/main
shopify[bot] Apr 30, 2026
083f317
🎨 Palette: Add aria-hidden="true" to purely decorative material symbols
google-labs-jules[bot] May 1, 2026
913628c
Optimize LCP for blog and article images using eager loading
google-labs-jules[bot] May 2, 2026
a1f46f8
🛡️ Sentinel: [HIGH] Fix Reflected XSS in Article Author via Localized…
google-labs-jules[bot] May 3, 2026
308937d
⚡ Bolt: Add responsive image support via widths in image_tag
google-labs-jules[bot] May 3, 2026
1f1c379
UX: Expand focus rings and add missing ARIA labels to buttons
google-labs-jules[bot] May 4, 2026
f937703
Merge pull request #22 from murielpereira/palette-aria-hidden-icons-4…
murielpereira May 4, 2026
778251b
Merge pull request #23 from murielpereira/bolt-optimize-blog-lcp-1010…
murielpereira May 4, 2026
2c12fe7
Merge pull request #25 from murielpereira/sentinel-xss-article-author…
murielpereira May 4, 2026
ceb4093
Merge pull request #26 from murielpereira/bolt-responsive-images-1701…
murielpereira May 4, 2026
b479f48
Merge branch 'main' into palette-focus-aria-labels-7413094423319514599
murielpereira May 4, 2026
09db1be
Merge pull request #27 from murielpereira/palette-focus-aria-labels-7…
murielpereira May 4, 2026
72b6686
ajuste para layout bianca
murielpereira May 4, 2026
99ec86b
ajuste overlay pingente
murielpereira May 4, 2026
029f74b
ajuste botões pdp
murielpereira May 4, 2026
d75ff55
ajustes css
murielpereira May 4, 2026
2913bfa
Fix mobile layout overflow for product swatches
google-labs-jules[bot] May 5, 2026
c74aad9
perf(product): replace O(M*N) nested loop with O(N) array contains check
google-labs-jules[bot] May 5, 2026
e7f66cd
UX: Add text to the 'Add to Cart' loading state
google-labs-jules[bot] May 5, 2026
227532c
Merge pull request #28 from murielpereira/breakpoint-fix-mobile-swatc…
murielpereira May 5, 2026
af31945
Merge pull request #29 from murielpereira/bolt-optimize-custom-fields…
murielpereira May 5, 2026
96d6521
Merge pull request #30 from murielpereira/palette-pdp-add-btn-a11y-63…
murielpereira May 5, 2026
8db4f0d
ajuste sistema pingentes
murielpereira May 5, 2026
2d9c10a
Update from Shopify for theme shopify-theme/main
shopify[bot] May 5, 2026
e302144
ajustes css
murielpereira May 5, 2026
909b54b
correcao logs
murielpereira May 5, 2026
f1b95c7
correcao galeria mobile
murielpereira May 5, 2026
b3d728e
correcao qtd carrinho
murielpereira May 5, 2026
1cbaa64
correcao variacoes
murielpereira May 5, 2026
ea373d7
...
murielpereira May 5, 2026
06d5394
ajuste overlay pingente
murielpereira May 6, 2026
fd7a5e8
contador caracteres
murielpereira May 6, 2026
608721d
correcao dynamic island
murielpereira May 6, 2026
1b445b3
Update from Shopify for theme shopify-theme/main
shopify[bot] May 6, 2026
e17ce94
ajuste galeria mobile
murielpereira May 6, 2026
41add26
contador de caracteres
murielpereira May 6, 2026
856d04e
Update from Shopify for theme shopify-theme/main
shopify[bot] May 6, 2026
920248f
ajuste contador caracteres
murielpereira May 6, 2026
0918bc3
correcao aviso pingente
murielpereira May 6, 2026
a456824
font size aviso pgt
murielpereira May 6, 2026
e9e5bbf
ajuste pingente
murielpereira May 6, 2026
a3bd71e
UX: Add aria-hidden to decorative expand_more icon in collection filter
google-labs-jules[bot] May 7, 2026
93d16c6
Merge pull request #31 from murielpereira/palette/add-aria-hidden-col…
murielpereira May 7, 2026
3b29b09
🛡️ Sentinel: [HIGH] Fix DOM XSS via innerHTML in video stories
google-labs-jules[bot] May 7, 2026
6e2c6a5
Update from Shopify for theme shopify-theme/main
shopify[bot] May 7, 2026
d469f5f
Merge branch 'main' into sentinel-dom-xss-video-stories-6557954144457…
murielpereira May 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .Jules/palette.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## 2025-04-21 - Added Skip to Content Link
**Learning:** For a custom built Shopify theme, adding a 'skip to content' link via `layout/theme.liquid` requires placing it as the very first interactive element in the body, which requires manual integration with the custom styling and `#main-content` structure.
**Action:** When working on themes with custom headers and sections, remember to include skip links and implement visual focus management for accessibility.

## 2024-05-05 - Add to Cart Loading State Accessibility
**Learning:** In the product page (`sections/product.liquid`), the "Add to Cart" button logic entirely overwrote the button's inner HTML with an icon during an asynchronous network request. Because the icon was `aria-hidden="true"` and the text was removed, screen reader users lost all context about the button's state and purpose during loading.
**Action:** When creating asynchronous button loading states (like adding to cart), preserve the textual context or use an `aria-live` region, rather than solely replacing the entire content with a decorative loading spinner.
9 changes: 9 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"permissions": {
"allow": [
"Bash(node -e ' *)",
"Bash(git add *)",
"Bash(git commit -m ' *)"
]
}
}
18 changes: 18 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"permissions": {
"allow": [
"Bash(python -c \"import json; json.load\\(open\\('config/settings_schema.json', encoding='utf-8'\\)\\); print\\('JSON válido'\\)\")",
"PowerShell($json = Get-Content \"c:\\\\Users\\\\pedid\\\\OneDrive\\\\Área de Trabalho\\\\Arquivos Âme\\\\Muriel\\\\Projetos\\\\shopify-theme\\\\config\\\\settings_schema.json\" -Raw -Encoding UTF8; try { $null = ConvertFrom-Json $json; Write-Host \"JSON válido\" } catch { Write-Host \"ERRO: $_\" })",
"Bash(node -e \"try { JSON.parse\\(require\\('fs'\\).readFileSync\\('config/settings_schema.json','utf8'\\)\\); console.log\\('JSON válido'\\); } catch\\(e\\) { console.log\\('ERRO:', e.message\\); }\")",
"Bash(node -e \"try { JSON.parse\\(require\\('fs'\\).readFileSync\\('locales/en.default.schema.json','utf8'\\)\\); console.log\\('JSON válido'\\); } catch\\(e\\) { console.log\\('ERRO:', e.message\\); }\")",
"Bash(node -e \"const d=require\\('fs'\\).readFileSync\\('/dev/stdin','utf8'\\); const j=JSON.parse\\(d\\); console.log\\('grupos:', j.map\\(g=>g.name||'\\(sem nome\\)'\\).join\\(', '\\)\\)\")",
"Bash(git show *)",
"Bash(node -e \"const j=JSON.parse\\(require\\('fs'\\).readFileSync\\('/tmp/schema_head.json','utf8'\\)\\); console.log\\('grupos HEAD:', j.map\\(g=>g.name||'\\(sem nome\\)'\\).join\\(', '\\)\\)\")",
"Bash(awk 'NR>=610 && NR<=705 { for\\(i=1;i<=length\\($0\\);i++\\){ c=substr\\($0,i,1\\); if\\(c!~/[\\\\x20-\\\\x7E\\\\t]/\\) print NR\":\"i\": [\"c\"] \\(\"sprintf\\(\"%02x\",ord\\(c\\)\\)\"\\)\" } }' sections/product.liquid)",
"Bash(python -c ' *)",
"Bash(node -e \"JSON.parse\\(require\\('fs'\\).readFileSync\\('config/settings_schema.json','utf8'\\)\\); console.log\\('OK — JSON válido'\\)\")",
"Bash(node -e ' *)",
"Bash(node -e \"JSON.parse\\(require\\('fs'\\).readFileSync\\('c:/Users/pedid/OneDrive/Área de Trabalho/Arquivos Âme/Muriel/Projetos/shopify-theme/config/settings_schema.json','utf8'\\)\\); console.log\\('settings_schema.json OK'\\)\")"
]
}
}
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ node_modules/
## Release files
release
*.zip

instrucoes.txt
nuvemshop/
referencias/
13 changes: 13 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## 2024-05-24 - Liquid Snippet N+1 Overhead
**Learning:** Rendering snippets (e.g., `{% render 'image' %}`) inside `for` loops in Shopify Liquid introduces significant overhead due to parsing and scoping per iteration, effectively causing an N+1 rendering bottleneck for templates with many items like collections, search results, or large carts.
**Action:** Always inline simple HTML logic using native Liquid filters like `image_url` and `image_tag` instead of using snippet renders inside loops to improve template compilation and server response time.
## 2026-04-25 - Render for loop N+1 overhead\n**Learning:** Liquid processes a `for` loop with a `render` inside by parsing and scoping the snippet per iteration (N+1 overhead). It is better to use the native `{% render 'snippet' for array %}` syntax which parses the snippet once.\n**Action:** Use `{% render 'snippet' for array %}` to eliminate N+1 rendering overhead instead of `for` loops with `render` inside. Pre-filter arrays with `where` or `slice` beforehand to recreate loop conditions.
## 2026-05-01 - Add responsive image support via widths in image_tag
**Learning:** Supplying the `widths` attribute to `image_tag` automatically outputs the `srcset` attribute, which enables the browser to download the most appropriate size based on the user's screen width, saving bandwidth and improving performance.
**Action:** Always include the `widths` attribute inside `image_tag` to provide responsive image support.
## 2024-05-14 - Eager Load LCP Images
**Learning:** Hardcoding `loading: 'lazy'` inside loops for image galleries (like `{% for media in product.media %}`) is a common anti-pattern that causes the Largest Contentful Paint (LCP) element to be delayed, severely impacting Web Vitals. Liquid `forloop.first` can be used to conditionally apply `loading: 'eager'` and `fetchpriority: 'high'` to the first element instead.
**Action:** Always check image rendering loops to ensure the first item (often the LCP candidate) is eager-loaded while subsequent items remain lazy-loaded.
## 2026-05-18 - Optimize nested loops with contains operator
**Learning:** When matching items from a large array (like `product.tags`) against dynamic settings, using a nested loop (`{% for tag in product.tags %} {% for i in (1..10) %}`) results in O(M*N) iteration overhead. Liquid's `contains` operator (`product.tags contains setting_val`) provides a much faster O(N) lookup.
**Action:** Replace nested loops that merely check for array membership with a single loop and the native `contains` array operator to reduce iteration overhead.
3 changes: 3 additions & 0 deletions .jules/breakpoint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## $(date +%Y-%m-%d) - [Fix Swatches Layout Overflow]
**Learning:** Found a recurring layout issue pattern where fixed column grid layouts (e.g. `grid-template-columns: repeat(6, 1fr)`) fail to fit gracefully when content exceeds available width or when there is insufficient padding/gap on mobile, resulting in truncated items.
**Action:** Use a flexbox wrapper with `flex-wrap: wrap` and percentage-based `width` values calculated via `calc()` based on the column count and gap (e.g., `width: calc(16.666% - 5px)` for 6 columns) to allow seamless wrapping while maintaining layout integrity.
3 changes: 3 additions & 0 deletions .jules/palette.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 2024-05-07 - Add aria-hidden to decorative icons
**Learning:** Found instances where material symbols (like `expand_more` in select dropdowns) were missing `aria-hidden="true"`, causing screen readers to improperly announce them as the ligature text.
**Action:** Ensure all decorative `<span class="material-symbols-outlined">` elements are accompanied by `aria-hidden="true"` when placed next to visually meaningful text or inputs.
28 changes: 28 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
## 2024-05-18 - [Missing noreferrer in target="_blank" links]
**Vulnerability:** Some external links using `target="_blank"` only had `rel="noopener"`, omitting `noreferrer`.
**Learning:** While `noopener` prevents the new page from accessing the `window.opener` object, omitting `noreferrer` can still leak the Referer header (which may contain sensitive information in the URL) to the external site, posing a privacy risk. Both should always be used together for external links.
**Prevention:** Always use `rel="noopener noreferrer"` when using `target="_blank"`. Added this to the project's coding conventions check.

## 2024-05-24 - [Reflected XSS in Liquid Localized Strings]
**Vulnerability:** Unsanitized user input (`search.terms`) was passed to Shopify translation strings ending in `_html`.
**Learning:** Shopify localizations with keys ending in `_html` output raw HTML directly, ignoring standard escaping if the parameters are not pre-escaped.
**Prevention:** Always use the `escape` filter on user input before passing it as arguments to `_html` translation keys (e.g., `{% assign escaped_terms = search.terms | escape %}`).

## 2024-05-25 - [Reflected XSS in Shopify Form Variables]
**Vulnerability:** Unsanitized user input (`form.author`, `form.email`, `form.body`) was output directly in `sections/article.liquid`.
**Learning:** In Shopify Liquid templates, user inputs like form variables are not auto-escaped. Outputting them dynamically back to the user inside HTML tags or attributes can lead to Reflected XSS.
**Prevention:** Always apply the `escape` filter (e.g., `{{ form.field | escape }}`) when outputting form variables dynamically back to the user to prevent Reflected XSS.
## 2024-05-25 - [Reflected XSS in Form Variables]
**Vulnerability:** Unsanitized user input (`form.author`, `form.email`, `form.body`) was being directly outputted back to the user in `sections/article.liquid`.
**Learning:** If a form submission fails and the form is re-rendered to show validation errors to the user, directly rendering the previous inputs (`value="{{ form.author }}"`) opens the application up to a reflected XSS vulnerability.
**Prevention:** Always use the `escape` filter when outputting user input dynamically back to the user inside HTML tags or attributes (e.g., `{{ form.author | escape }}`).

## 2024-05-25 - [Reflected XSS in Article Author via Localized String]
**Vulnerability:** Unsanitized variable `article.author` was passed to a Shopify translation string ending in `_html` in `sections/article.liquid` and `sections/blog.liquid`.
**Learning:** Shopify localizations with keys ending in `_html` output raw HTML directly. If unescaped variables are passed as arguments to these translations, they become vulnerable to Reflected XSS.
**Prevention:** Always use the `escape` filter on user input or dynamic properties like `article.author` before passing them as arguments to `_html` translation keys (e.g., `{% assign escaped_author = article.author | escape %}`).

## 2024-05-25 - [DOM-based XSS via innerHTML]
**Vulnerability:** Unsanitized dynamic properties (like `data.src` and `data.id`) were being interpolated directly into `<iframe>` and `<video>` tags via `innerHTML` assignment without proper HTML escaping. Using a rudimentary `.replace(/"/g, '&quot;')` is insufficient.
**Learning:** Assigning unescaped user-controlled or dynamic data to `innerHTML` can lead to DOM-based Cross-Site Scripting (XSS).
**Prevention:** Always sanitize dynamic variables using robust local escaping functions (like `escapeHTML()` that escapes `&`, `<`, `>`, `"`, and `'`) before interpolating them into HTML strings that will be parsed by `innerHTML`.
80 changes: 80 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project

Shopify Online Store 2.0 theme for **Âme Acessórios Pet**, a luxury pet-accessories store. Forked from Shopify's Skeleton Theme and heavily customized. The store sells leather collars, harnesses, and add-on identification pendants ("pingentes"). All UI strings are written directly in Brazilian Portuguese — `locales/pt-BR.json` is empty and unused. Do not introduce translation keys (`{{ '...' | t }}`); copy the surrounding pattern of hardcoded PT-BR text.

The visual language ("Aerodynamic Elegance") is documented in [instructions.md](instructions.md) and lived-in via design tokens in [snippets/css-variables.liquid](snippets/css-variables.liquid). Color palette is cream/brown with `--color-primary: #5a4742`. Avoid 100% black (`#000`); use `--color-on-background: #201b14`.

## Development commands

This is a Shopify theme — no build step, no test runner. The Shopify CLI handles dev preview and uploads.

```bash
shopify theme dev # local preview against the connected dev store
shopify theme push # upload to dev/staging theme on the store
shopify theme pull # pull settings_data.json + templates back from store
shopify theme check # run theme-check linter (matches CI)
```

CI ([.github/workflows/ci.yml](.github/workflows/ci.yml)) only runs `shopify/theme-check-action`. There are no unit tests; `playwright` in `package.json` is unused infra.

The user typically asks Claude to make changes locally, then themselves runs `shopify theme push` and reports the rendered result back (often via screenshots). Do not attempt to push or upload — the user controls deployment.

## Architecture quirks worth knowing

### `assets/critical.css` is the global stylesheet
Everything that's *not* scoped to a single section/snippet lives there. New section-specific styles go in `<style>` (or `{% stylesheet %}` if not inside a conditional) inside the section file itself. **`{% stylesheet %}` cannot be nested inside `{% if %}`** — Shopify rejects it at validation. Snippets that conditionally render should use plain `<style>` tags instead.

### Product page: Section Rendering API for variants (>250-variant safe)
[sections/product.liquid](sections/product.liquid) does **not** dump `{{ product.variants | json }}`. Variant picking uses Shopify's [Section Rendering API](https://shopify.dev/docs/storefronts/themes/architecture/templates/product#section-rendering): on click, the JS reads `data-option-value-id` from buttons, fetches `/products/<handle>?section_id=<id>&option_values=<ids>`, and DOM-swaps four fixed wrappers from the response:

- `#pdp-options-wrap` — variant picker (refreshes availability + selected state)
- `#pdp-price-block` — price, compare-at, discount badge, PIX, installments, cashback
- `#pdp-add-btn-wrap` — submit button enabled/disabled + label
- `#pdp-img-badge-wrap` — discount badge over the main image

After a successful refresh, the section dispatches `document.dispatchEvent(new CustomEvent('pdp:variant-changed'))`. Other on-page modules (the pingente snippet) listen to this event to re-validate. **Preserve these IDs** when refactoring; the JS depends on them.

### Cart: AJAX with `items: []` JSON, plus client-rendered drawer
The PDP submit handler in [sections/product.liquid](sections/product.liquid) builds a JSON payload (`{ items: [coleira, pingente?] }`) — *not* `FormData` — so it can post multiple items in one atomic call. After success, it calls `window.AmeCart.refresh(cartData)` and `window.AmeCart.open()`, both defined in [layout/theme.liquid](layout/theme.liquid). The drawer template exists in two places that must stay in sync:

- [snippets/cart-drawer.liquid](snippets/cart-drawer.liquid) — initial server-rendered Liquid
- `itemHTML()` in [layout/theme.liquid](layout/theme.liquid) — JS template-literal version used after AJAX add/update

Any change to a cart line's structure (e.g. adding line item properties, badges) must be applied in **both** places.

### Pingente personalizado (custom add-on flow)
[snippets/pingente-customization.liquid](snippets/pingente-customization.liquid) renders a progressive-disclosure block on products with the tag `customizacao_pingente`. It exposes `window.amePingente.{ isActive, validate, getCartItem }` which the product submit handler consults to add a *second* cart item alongside the collar. Pingente product handles follow a strict naming convention:

- `pingente-de-metal-para-identificacao-pet`
- `pingente-de-couro-para-identificacao-pet-<slug-cor>`
- `pingente-de-metal-com-couro-para-identificacao-pet-<slug-cor>`

The `<slug-cor>` is the *last* word of the collar's `Cor` option (split on `" com "`, slugified). Variant options inside each pingente product must be exactly `Cor do Metal`, `Formato`, `Tamanho`. Collar size → pingente size mapping is hardcoded in `SIZE_MAP`: XPP/XPP+/PP/P → P; M/G → G.

### Custom fields on collars
Theme settings define up to 10 generic custom fields (`custom_field_1_*` through `custom_field_10_*`) gated by tag (`custom_field_N_tag`). [sections/product.liquid](sections/product.liquid) renders fields whose tag is in `product.tags`. Each field's `_label` is the visible label, `_placeholder` is the input placeholder (falls back to label for back-compat). The fields submit as `name="properties[<cf_name>]"` — line item properties on the collar item. To hide a property from the customer-facing cart but keep it on the order, prefix the internal name with `_`.

### Money formatting
Calculations are done in cents (integer). Display uses `money_without_currency` filter (respects shop's locale: BRL → `1.820,50`). Avoid `round: 1 | replace: '.', ','` — that produces `18,2` instead of `18,20`. The `Shopify.formatMoney` JS helper is available client-side.

### Material Symbols icons
Loaded via Google Fonts in [snippets/css-variables.liquid](snippets/css-variables.liquid) with `&display=block` (not `swap`). This is intentional: icons render via ligatures, so `swap` would briefly show literal text like "shopping_bag" while the font loads. **Do not** change to `swap`. Lexend (the body font) uses `swap` correctly because text fallback is acceptable.

### Settings schema gotchas
- A bad value in `config/settings_data.json` (e.g. `"type_primary_font": "lexend_n4"` when Shopify doesn't recognize the handle) makes the entire theme settings panel render blank. Symptoms: empty panel + Shopify CLI error "New schema is incompatible with the current setting value".
- Shopify's `range` settings have a soft limit of ~100 stops. `(max - min) / step` must stay under that, and step needs to evenly divide the range to make `max` reachable.
- After modifying schema files via PowerShell/scripts, re-validate the JSON parses (`node -e "JSON.parse(...)"`) before pushing. The auto-edits in this codebase have produced double-comma JSON before.

### `.Jules/*.md` are agent review memories
Files in [.Jules/](.Jules/) (`bolt.md` = performance, `palette.md` = accessibility, `sentinel.md` = security) accumulate "Learning / Action / Prevention" notes from prior automated reviews of this repo. They reflect real bugs that were fixed — read them when working on the relevant area (e.g. `sentinel.md` when adding form input rendering, `palette.md` when touching interactive ARIA, `bolt.md` when iterating over collections). Do not overwrite or delete them.

### Reference projects (gitignored)
The `referencias/` and `nuvemshop/` directories are gitignored — they contain unrelated reference code (a Node app called `Waltz`, a Nuvemshop theme used for inspiration on the cashback snippet). Do not edit them and do not include their files in greps when working on the live theme.

## Communication conventions

The user works in Brazilian Portuguese. Replies, commit messages, and code comments destined for the user should be in PT-BR. Code identifiers stay in English/Portuguese mix as already used (`card_compare_price`, `pdp__price-block`, etc.). Don't translate existing identifiers.
Loading
Loading