Migrate product data from Kirby to Shopify Storefront API

- Add product loaders (product-loader.js, products-list-loader.js) to fetch data from Shopify
- Extend Shopify API client with getProductByHandle() and getAllProducts() methods
- Integrate Shopify metafields for multilingual support (custom.title_en, custom.description_en)
- Refactor product.php and home.php templates to load content dynamically
- Simplify product blueprint to minimal routing configuration
- Create generic buy-button.php snippet with variant selection
- Update footer.php with conditional script loading
- Refactor _section--product.scss for better Sass structure
- Add translations for loading states and product errors
- Clean up old Kirby product content files

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
isUnknown 2026-01-16 12:03:20 +01:00
parent 957cf79e45
commit ad699f0365
22 changed files with 649 additions and 579 deletions

View file

@ -1,12 +1,3 @@
.section__product,
.store__nav{
max-width: 1200px;
margin-left: auto;
margin-right: auto;
}
.section__product,
.store__nav {
max-width: 1200px;
@ -14,10 +5,6 @@
margin-right: auto;
}
.store__nav {
padding-top: calc(var(--spacing) * 1);
padding-bottom: calc(var(--spacing) * 0.5);
@ -27,174 +14,35 @@
a {
text-decoration: none;
&::before {
content: "";
}
&:hover {
text-decoration: underline;
}
}
a::before {
content: "";
}
}
.section__product .details {
// margin-bottom: calc(var(--spacing) * 2);
ul{
margin-left: 2ch;
li{
padding-bottom: 0.2em;
@media #{$small} {
a {
padding-top: 0;
font-size: var(--fs-small);
}
}
}
.section__product {
.details {
ul {
margin-left: 2ch;
.product-options__list {
list-style: none;
display: flex;
gap: 2ch;
li {
position: relative;
input[type="radio"] {
position: fixed;
opacity: 0;
pointer-events: none;
}
label {
font-family: var(--title);
font-size: var(--fs-normal);
height: 4ch;
width: 4ch;
border-radius: 50%;
border: var(--border);
border-color: transparent;
display: flex;
align-items: center;
justify-content: center;
padding-top: 0px;
cursor: pointer;
}
input[type="radio"]:checked + label {
border-color: var(--color-txt);
}
input[type="radio"]:not(:checked) + label:hover {
border-color: var(--grey-600);
background-color: var(--grey-800);
}
}
}
.product-gallery {
position: relative;
aspect-ratio: 4 / 3;
.swiper-slide {
width: 100%;
figure {
aspect-ratio: 4 / 3;
width: 100%;
height: 100%;
img {
width: 100%;
height: 100%;
object-fit: contain;
padding-bottom: 0.2em;
}
}
}
// Swiper navigation arrows
.swiper-button-prev,
.swiper-button-next {
color: var(--color-txt);
width: 20px;
height: 20px;
&:after {
font-size: 20px;
font-weight: bold;
}
&:hover {
opacity: 0.7;
}
}
// Swiper pagination dots
.swiper-pagination {
position: relative;
margin-top: calc(var(--spacing) * 0.5);
bottom: 0;
.swiper-pagination-bullet {
width: 8px;
height: 8px;
background: var(--grey-600);
opacity: 0.5;
transition: opacity 0.3s;
&:hover {
opacity: 0.7;
}
}
.swiper-pagination-bullet-active {
background: var(--color-txt);
opacity: 1;
}
}
}
.hero {
margin-bottom: calc(var(--spacing) * 1);
padding: calc(var(--spacing) * 0.5) 0;
border-top: var(--border-light);
border-bottom: var(--border-light);
.p__baseline-big {
margin: 0;
text-align: left;
}
}
.add-to-cart {
margin: 0;
border-bottom: var(--border-light);
padding: calc(var(--spacing) * 0.5) 0;
}
.product-options {
border-bottom: var(--border-light);
padding: calc(var(--spacing) * 0.25) 0;
}
@media #{$small} {
.store__nav a {
padding-top: 0;
font-size: var(--fs-small);
}
.section__product {
@media #{$small} {
display: flex;
flex-direction: column;
margin-bottom: 10vh;
@ -207,6 +55,7 @@
margin-top: calc(var(--spacing) * 0.5);
order: 1;
}
figure {
order: 2;
margin-bottom: calc(var(--spacing) * 1);
@ -226,25 +75,25 @@
order: 5;
}
.product-gallery{
.product-gallery {
width: 100vw;
position: relative;
left: calc(var(--padding-body)*-1);
left: calc(var(--padding-body) * -1);
.swiper-button-prev,
.swiper-button-next{ display: none; }
.swiper-button-next {
display: none;
}
}
}
}
@media #{$small-up} {
.section__product{
display: grid;
grid-template-columns: 1fr 1fr;
gap: calc(var(--padding-body)*2);
margin-bottom: calc(var(--spacing)*3);
@media #{$small-up} {
.product-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: calc(var(--padding-body) * 2);
margin-bottom: calc(var(--spacing) * 3);
}
.details {
margin-bottom: calc(var(--spacing) * 2);
@ -255,17 +104,140 @@
border-top: var(--border-light);
}
.col-left{
.col-left {
min-height: 100%;
padding-bottom: 40px; //dots
padding-bottom: 40px;
display: flex;
flex-direction: column;
}
}
.product-gallery .swiper-slide figure{
width: calc(100% - 60px);
}
}
.product-options {
border-bottom: var(--border-light);
padding: calc(var(--spacing) * 0.25) 0;
}
.product-options__list {
list-style: none;
display: flex;
gap: 2ch;
li {
position: relative;
input[type="radio"] {
position: fixed;
opacity: 0;
pointer-events: none;
&:checked + label {
border-color: var(--color-txt);
}
&:not(:checked) + label:hover {
border-color: var(--grey-600);
background-color: var(--grey-800);
}
}
label {
font-family: var(--title);
font-size: var(--fs-normal);
height: 4ch;
width: 4ch;
border-radius: 50%;
border: var(--border);
border-color: transparent;
display: flex;
align-items: center;
justify-content: center;
padding-top: 0px;
cursor: pointer;
}
}
}
.product-gallery {
position: relative;
aspect-ratio: 4 / 3;
.swiper-slide {
width: 100%;
figure {
aspect-ratio: 4 / 3;
width: 100%;
height: 100%;
img {
width: 100%;
height: 100%;
object-fit: contain;
}
}
@media #{$small-up} {
figure {
width: calc(100% - 60px);
}
}
}
.swiper-button-prev,
.swiper-button-next {
color: var(--color-txt);
width: 20px;
height: 20px;
&:after {
font-size: 20px;
font-weight: bold;
}
&:hover {
opacity: 0.7;
}
}
.swiper-pagination {
position: relative;
margin-top: calc(var(--spacing) * 0.5);
bottom: 0;
.swiper-pagination-bullet {
width: 8px;
height: 8px;
background: var(--grey-600);
opacity: 0.5;
transition: opacity 0.3s;
&:hover {
opacity: 0.7;
}
&.swiper-pagination-bullet-active {
background: var(--color-txt);
opacity: 1;
}
}
}
}
.hero {
margin-bottom: calc(var(--spacing) * 1);
padding: calc(var(--spacing) * 0.5) 0;
border-top: var(--border-light);
border-bottom: var(--border-light);
.p__baseline-big {
margin: 0;
text-align: left;
}
}
.add-to-cart {
margin: 0;
border-bottom: var(--border-light);
padding: calc(var(--spacing) * 0.5) 0;
}