Skip to content

Merge Shopify changes into main - #4

Merged
dan-long-dev merged 15 commits into
mainfrom
production
Sep 16, 2026
Merged

dan-long-dev merged 15 commits into
mainfrom
production

Conversation

@dan-long-dev

Copy link
Copy Markdown
Collaborator

PR Summary:

Why are these changes introduced?

Fixes #0.

What approach did you take?

Other considerations

Decision log

# Decision Alternatives Rationale Downsides
1

Visual impact on existing themes

Testing steps/scenarios

  • Step 1

Demo links

Checklist

shopify Bot added 15 commits September 14, 2026 09:26
Committed from shop: Open Home Foundation Store
Theme last edited by: Dan Long
Committed from shop: Open Home Foundation Store
Theme last edited by: Dan Long
Committed from shop: Open Home Foundation Store
Theme last edited by: Dan Long
Committed from shop: Open Home Foundation Store
Theme last edited by: Dan Long
Committed from shop: Open Home Foundation Store
Theme last edited by: Dan Long
Committed from shop: Open Home Foundation Store
Theme last edited by: Dan Long
Committed from shop: Open Home Foundation Store
Theme last edited by: Dan Long
Committed from shop: Open Home Foundation Store
Theme last edited by: Dan Long
Committed from shop: Open Home Foundation Store
Theme last edited by: Dan Long
Committed from shop: Open Home Foundation Store
Theme last edited by: Dan Long
Committed from shop: Open Home Foundation Store
Theme last edited by: Dan Long
Committed from shop: Open Home Foundation Store
Theme last edited by: Dan Long
Committed from shop: Open Home Foundation Store
Theme last edited by: Dan Long
Committed from shop: Open Home Foundation Store
Theme last edited by: Dan Long
Committed from shop: Open Home Foundation Store
Theme last edited by: Dan Long
Copilot AI lite review requested due to automatic review settings September 16, 2026 15:59
@dan-long-dev
dan-long-dev merged commit f7b07de into main Sep 16, 2026
1 check passed
@dan-long-dev
dan-long-dev deleted the production branch September 16, 2026 16:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved critical security and correctness issues, along with moderate behavior issues, must be addressed before approval.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Updates Dawn for Open Home Foundation branding, storefront configuration, product-card color swatches, and a product price-breakdown chart.

Changes:

  • Rebrands homepage, header, footer, and theme settings.
  • Adjusts homepage, collection, and product presentation.
  • Adds product-card color swatches and styling.
  • Adds a Chart.js price-breakdown chart to product pages.
File summaries
File Summary and findings
templates/product.json Adds product layout and price-breakdown chart. Moderate issues: chart values remain stale after variant changes, and Chart.js loads as a blocking external script. Critical issue: the third-party CDN dependency lacks integrity verification or a first-party asset boundary. Nit: “dependant” should be “dependent.”
templates/index.json Updates homepage branding and featured product settings.
templates/collection.json Adjusts collection product-card presentation.
snippets/card-product.liquid Adds variant color swatches. Critical issue: color_option is unescaped in HTML contexts. Moderate issue: arbitrary option text is used as a CSS color, which can produce blank swatches.
sections/header-group.json Updates header configuration.
sections/footer-group.json Updates footer menus and settings.
config/settings_data.json Updates store branding and theme settings.
assets/base.css Adds swatch styling. Moderate issue: pointer cursors on noninteractive spans create a misleading affordance, and data-color has no consumer.
Review details

Suppressed comments (1)

templates/product.json:118

  • Loading Chart.js as a classic external script without async or defer blocks parsing and delays DOMContentLoaded on every product page. A slow or unavailable jsDelivr response can therefore delay the theme's initialization, and the current typeof Chart guard leaves this section blank on failure. Load the dependency non-blockingly with an explicit load/error path, or ship it as a theme asset.
        "custom_liquid": "<script src=\"https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js\"></script>\n\n<div style=\"width: 75%; margin: 20px auto;\">\n  <h3 style=\"text-align: center;\">Price breakdown</h3>\n\n  <p style=\"text-align: center; font-size: 13px; color: #777; margin: 0 auto 32px; max-width: 640px;\">\n    These costs represent the breakdown at the time we most recently updated the item's total price, so the percentages may change between updates. This means it's possible that the contribution to the Open Home Foundation from this purchase could be moderately higher or lower than what's shown above.\n  </p>\n\n  <div style=\"display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 30px;\">\n    <div style=\"flex-basis: 300px; flex-grow: 1; max-width: 400px; position: relative;\">\n      <canvas id=\"costBreakdownChart\"></canvas>\n    </div>\n    <div id=\"costBreakdownLegend\" style=\"flex-basis: 250px; flex-grow: 1;\"></div>\n  </div>\n</div>\n\n<script>\n(function () {\n  const totalPrice = {{ product.selected_or_first_available_variant.price | default: 0 }} / 100;\n  const currencyCode = {{ cart.currency.iso_code | json }};\n  const fmt = new Intl.NumberFormat({{ request.locale.iso_code | json }}, { style: 'currency', currency: currencyCode });\n\n  const rows = [\n    ['Manufacturing',                             0.27, '#5A6675'],\n    ['Warehousing & Logistics',                   0.15, '#09293B'],\n    ['Operational costs',                         0.06, '#A2AAB6'],\n    ['VAT (country dependant)',                   0.22, '#7A8594'],\n    ['Contribution to the Open Home Foundation',  0.30, '#18BCF2'],\n  ];\n\n  function init() {\n    const canvas = document.getElementById('costBreakdownChart');\n    if (!canvas || typeof Chart === 'undefined') return;\n\n    new Chart(canvas.getContext('2d'), {\n      type: 'doughnut',\n      data: {\n        labels: rows.map(r => r[0]),\n        datasets: [{\n          data: rows.map(r => totalPrice * r[1]),\n          backgroundColor: rows.map(r => r[2]),\n          borderWidth: 0,\n          hoverOffset: 4\n        }]\n      },\n      options: {\n        responsive: true,\n        cutout: '70%',\n        plugins: {\n          legend: { display: false },\n          tooltip: { callbacks: { label: c => `${c.label}: ${fmt.format(c.raw)}` } }\n        }\n      }\n    });\n\n    document.getElementById('costBreakdownLegend').innerHTML =\n      '<ul style=\"list-style:none;padding:0;margin:0;\">' +\n      rows.map(([label, pct, color]) => `\n        <li style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;font-size:14px;\">\n          <span style=\"display:flex;align-items:center;\">\n            <span style=\"width:12px;height:12px;border-radius:50%;background-color:${color};margin-right:10px;\"></span>\n            ${label}\n          </span>\n          <span style=\"font-weight:500;\">${(pct * 100).toFixed(0)}%</span>\n        </li>`).join('') +\n      '</ul>';\n  }\n\n  if (document.readyState === 'loading') {\n    document.addEventListener('DOMContentLoaded', init);\n  } else {\n    init();\n  }\n})();\n</script>",
  • Files reviewed: 8/8 changed files
  • Comments generated: 6
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +217 to +219
<span class="swatch-bubble" data-color="{{ color_option | downcase }}" style="background-color: {{ color_option | replace: ' ', '' | downcase }};">
<span class="visually-hidden">{{ color_option }}</span>
</span>
Comment thread templates/product.json
"type": "custom-liquid",
"name": "t:sections.custom-liquid.presets.name",
"settings": {
"custom_liquid": "<script src=\"https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js\"></script>\n\n<div style=\"width: 75%; margin: 20px auto;\">\n <h3 style=\"text-align: center;\">Price breakdown</h3>\n\n <p style=\"text-align: center; font-size: 13px; color: #777; margin: 0 auto 32px; max-width: 640px;\">\n These costs represent the breakdown at the time we most recently updated the item's total price, so the percentages may change between updates. This means it's possible that the contribution to the Open Home Foundation from this purchase could be moderately higher or lower than what's shown above.\n </p>\n\n <div style=\"display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 30px;\">\n <div style=\"flex-basis: 300px; flex-grow: 1; max-width: 400px; position: relative;\">\n <canvas id=\"costBreakdownChart\"></canvas>\n </div>\n <div id=\"costBreakdownLegend\" style=\"flex-basis: 250px; flex-grow: 1;\"></div>\n </div>\n</div>\n\n<script>\n(function () {\n const totalPrice = {{ product.selected_or_first_available_variant.price | default: 0 }} / 100;\n const currencyCode = {{ cart.currency.iso_code | json }};\n const fmt = new Intl.NumberFormat({{ request.locale.iso_code | json }}, { style: 'currency', currency: currencyCode });\n\n const rows = [\n ['Manufacturing', 0.27, '#5A6675'],\n ['Warehousing & Logistics', 0.15, '#09293B'],\n ['Operational costs', 0.06, '#A2AAB6'],\n ['VAT (country dependant)', 0.22, '#7A8594'],\n ['Contribution to the Open Home Foundation', 0.30, '#18BCF2'],\n ];\n\n function init() {\n const canvas = document.getElementById('costBreakdownChart');\n if (!canvas || typeof Chart === 'undefined') return;\n\n new Chart(canvas.getContext('2d'), {\n type: 'doughnut',\n data: {\n labels: rows.map(r => r[0]),\n datasets: [{\n data: rows.map(r => totalPrice * r[1]),\n backgroundColor: rows.map(r => r[2]),\n borderWidth: 0,\n hoverOffset: 4\n }]\n },\n options: {\n responsive: true,\n cutout: '70%',\n plugins: {\n legend: { display: false },\n tooltip: { callbacks: { label: c => `${c.label}: ${fmt.format(c.raw)}` } }\n }\n }\n });\n\n document.getElementById('costBreakdownLegend').innerHTML =\n '<ul style=\"list-style:none;padding:0;margin:0;\">' +\n rows.map(([label, pct, color]) => `\n <li style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;font-size:14px;\">\n <span style=\"display:flex;align-items:center;\">\n <span style=\"width:12px;height:12px;border-radius:50%;background-color:${color};margin-right:10px;\"></span>\n ${label}\n </span>\n <span style=\"font-weight:500;\">${(pct * 100).toFixed(0)}%</span>\n </li>`).join('') +\n '</ul>';\n }\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', init);\n } else {\n init();\n }\n})();\n</script>",
Comment thread assets/base.css
height: 16px;
border-radius: 50%;
border: 1px solid rgba(0,0,0,0.15);
cursor: pointer;
{% if card_product.options contains key %}
<div class="card-swatches-container">
{% for color_option in card_product.options_by_name[key].values %}
<span class="swatch-bubble" data-color="{{ color_option | downcase }}" style="background-color: {{ color_option | replace: ' ', '' | downcase }};">
Comment thread templates/product.json
"type": "custom-liquid",
"name": "t:sections.custom-liquid.presets.name",
"settings": {
"custom_liquid": "<script src=\"https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js\"></script>\n\n<div style=\"width: 75%; margin: 20px auto;\">\n <h3 style=\"text-align: center;\">Price breakdown</h3>\n\n <p style=\"text-align: center; font-size: 13px; color: #777; margin: 0 auto 32px; max-width: 640px;\">\n These costs represent the breakdown at the time we most recently updated the item's total price, so the percentages may change between updates. This means it's possible that the contribution to the Open Home Foundation from this purchase could be moderately higher or lower than what's shown above.\n </p>\n\n <div style=\"display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 30px;\">\n <div style=\"flex-basis: 300px; flex-grow: 1; max-width: 400px; position: relative;\">\n <canvas id=\"costBreakdownChart\"></canvas>\n </div>\n <div id=\"costBreakdownLegend\" style=\"flex-basis: 250px; flex-grow: 1;\"></div>\n </div>\n</div>\n\n<script>\n(function () {\n const totalPrice = {{ product.selected_or_first_available_variant.price | default: 0 }} / 100;\n const currencyCode = {{ cart.currency.iso_code | json }};\n const fmt = new Intl.NumberFormat({{ request.locale.iso_code | json }}, { style: 'currency', currency: currencyCode });\n\n const rows = [\n ['Manufacturing', 0.27, '#5A6675'],\n ['Warehousing & Logistics', 0.15, '#09293B'],\n ['Operational costs', 0.06, '#A2AAB6'],\n ['VAT (country dependant)', 0.22, '#7A8594'],\n ['Contribution to the Open Home Foundation', 0.30, '#18BCF2'],\n ];\n\n function init() {\n const canvas = document.getElementById('costBreakdownChart');\n if (!canvas || typeof Chart === 'undefined') return;\n\n new Chart(canvas.getContext('2d'), {\n type: 'doughnut',\n data: {\n labels: rows.map(r => r[0]),\n datasets: [{\n data: rows.map(r => totalPrice * r[1]),\n backgroundColor: rows.map(r => r[2]),\n borderWidth: 0,\n hoverOffset: 4\n }]\n },\n options: {\n responsive: true,\n cutout: '70%',\n plugins: {\n legend: { display: false },\n tooltip: { callbacks: { label: c => `${c.label}: ${fmt.format(c.raw)}` } }\n }\n }\n });\n\n document.getElementById('costBreakdownLegend').innerHTML =\n '<ul style=\"list-style:none;padding:0;margin:0;\">' +\n rows.map(([label, pct, color]) => `\n <li style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;font-size:14px;\">\n <span style=\"display:flex;align-items:center;\">\n <span style=\"width:12px;height:12px;border-radius:50%;background-color:${color};margin-right:10px;\"></span>\n ${label}\n </span>\n <span style=\"font-weight:500;\">${(pct * 100).toFixed(0)}%</span>\n </li>`).join('') +\n '</ul>';\n }\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', init);\n } else {\n init();\n }\n})();\n</script>",
Comment thread templates/product.json
"type": "custom-liquid",
"name": "t:sections.custom-liquid.presets.name",
"settings": {
"custom_liquid": "<script src=\"https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js\"></script>\n\n<div style=\"width: 75%; margin: 20px auto;\">\n <h3 style=\"text-align: center;\">Price breakdown</h3>\n\n <p style=\"text-align: center; font-size: 13px; color: #777; margin: 0 auto 32px; max-width: 640px;\">\n These costs represent the breakdown at the time we most recently updated the item's total price, so the percentages may change between updates. This means it's possible that the contribution to the Open Home Foundation from this purchase could be moderately higher or lower than what's shown above.\n </p>\n\n <div style=\"display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 30px;\">\n <div style=\"flex-basis: 300px; flex-grow: 1; max-width: 400px; position: relative;\">\n <canvas id=\"costBreakdownChart\"></canvas>\n </div>\n <div id=\"costBreakdownLegend\" style=\"flex-basis: 250px; flex-grow: 1;\"></div>\n </div>\n</div>\n\n<script>\n(function () {\n const totalPrice = {{ product.selected_or_first_available_variant.price | default: 0 }} / 100;\n const currencyCode = {{ cart.currency.iso_code | json }};\n const fmt = new Intl.NumberFormat({{ request.locale.iso_code | json }}, { style: 'currency', currency: currencyCode });\n\n const rows = [\n ['Manufacturing', 0.27, '#5A6675'],\n ['Warehousing & Logistics', 0.15, '#09293B'],\n ['Operational costs', 0.06, '#A2AAB6'],\n ['VAT (country dependant)', 0.22, '#7A8594'],\n ['Contribution to the Open Home Foundation', 0.30, '#18BCF2'],\n ];\n\n function init() {\n const canvas = document.getElementById('costBreakdownChart');\n if (!canvas || typeof Chart === 'undefined') return;\n\n new Chart(canvas.getContext('2d'), {\n type: 'doughnut',\n data: {\n labels: rows.map(r => r[0]),\n datasets: [{\n data: rows.map(r => totalPrice * r[1]),\n backgroundColor: rows.map(r => r[2]),\n borderWidth: 0,\n hoverOffset: 4\n }]\n },\n options: {\n responsive: true,\n cutout: '70%',\n plugins: {\n legend: { display: false },\n tooltip: { callbacks: { label: c => `${c.label}: ${fmt.format(c.raw)}` } }\n }\n }\n });\n\n document.getElementById('costBreakdownLegend').innerHTML =\n '<ul style=\"list-style:none;padding:0;margin:0;\">' +\n rows.map(([label, pct, color]) => `\n <li style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;font-size:14px;\">\n <span style=\"display:flex;align-items:center;\">\n <span style=\"width:12px;height:12px;border-radius:50%;background-color:${color};margin-right:10px;\"></span>\n ${label}\n </span>\n <span style=\"font-weight:500;\">${(pct * 100).toFixed(0)}%</span>\n </li>`).join('') +\n '</ul>';\n }\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', init);\n } else {\n init();\n }\n})();\n</script>",
@mrdarrengriffin
mrdarrengriffin restored the production branch September 17, 2026 13:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants