28 Commits

Author SHA1 Message Date
98ccf560c9 fix(extra-features): Product card grid now uses bootstrap cols
The product cards should use bootstrap instead of display grid for easier edits and consistency
2026-01-09 15:51:22 +01:00
e393572081 fet(extra-fetures): Pagination results text
Shows "12 van 15 resultaten" for example right acorss from the pagination
2026-01-09 15:41:10 +01:00
e37cafd839 fix(extra-features): Remove btn-outline in loop
The colors for btn-outline should be the same as the border
2026-01-09 14:22:34 +01:00
1bf0ea3450 Merge branch 'feature/falcon-PS9' into feature/extra-features 2026-01-09 10:53:45 +01:00
a128906dc0 fix(falcon-PS9): prevent 500 error on AJAX filtering by normalizing data
Resolved a Fatal Error occurring during AJAX product listing requests (e.g., price slider).

- Issue: In PHP 8.2+, accessing properties of a 'CategoryLazyArray' object
  using array syntax (dot notation) triggers a Fatal Error.
- Cause: The Faceted Search module returns a LazyArray object during
  XHR requests, whereas standard page loads provide a native array.
- Solution: Implemented a normalization block using JSON serialization
  to flatten the object into a standard associative array. This ensures
  template syntax compatibility regardless of the request type or
  property visibility (protected vs public).
2026-01-09 10:52:21 +01:00
ddec414409 fix(falcon-PS9): Auto-format postcode
This removes the annoying error when you type in 8011XD instead of 8011 XD
2026-01-09 10:17:29 +01:00
2f8a8bf527 feat(extra-features): Add section-spacer utility class
This is  a class used to standardize spacing between sections of the site, especially the home page.
2026-01-06 11:54:52 +01:00
e4c471684f feat(extra-features): Add more helpful functions 2026-01-06 11:40:34 +01:00
d38338b360 Merge remote-tracking branch 'origin/dewebsmid' into restore-old 2025-12-31 19:15:05 +01:00
cb65915c7c Merge remote-tracking branch 'origin/feature/svg_icon' into restore-old 2025-12-31 19:12:56 +01:00
10aabb24a9 Merge branch 'feature/scss' into dewebsmid 2025-12-31 18:24:50 +01:00
a8869adad6 Merge branch 'feature/svg_icon' into dewebsmid 2025-12-31 18:22:08 +01:00
ff9b9a3570 feat(scss): Replace font-size-base to 14px
This has been standard in the projects I've worked on so far so might as well replace it.
2025-12-31 16:57:43 +01:00
47f985815a feat(scss): Add gap and font-size utility functions 2025-12-31 16:56:10 +01:00
8c79477559 feat(scss): Add bootstrap-5-like grids & media queries
This branch is just for "good to have" optional stand-alone sass features.

In this commit, I aimed to make some things more like bootstrap 5 for ease of use. I  changed the grid breakpoints to match that of Bootstrap 5's and added media query mixins that are more logical like in bootstrap 5.
2025-12-31 16:54:02 +01:00
5c7750e15d feat(svg_icon): Add chevron_down to footer & menu 2025-12-31 16:25:51 +01:00
523c7d573c feat(svg_icon): Add svg_icon support for header 2025-12-31 16:25:51 +01:00
6af020d81f feat(svg-icon): Add svg_icon support for favoriteproducts module 2025-12-31 16:25:51 +01:00
f2192d11db feat(svg_icon): Add checkmark icon 2025-12-31 16:25:51 +01:00
982dc10038 feat(svg_icon): Add x icon; add svg_icon support for header heart icon 2025-12-31 16:25:51 +01:00
4d7880fcec feat(svg_icon): Fixed some icon svg codes, added hamburger-menu icon 2025-12-31 16:25:51 +01:00
fd595a0e15 feat(svg_icon): Add standard svg icons
-Adds icons to use with the svg_icon smarty helper in the is_themecore module. See is_themecore-PS9 repo.

- Uses chevron svg icons by default on bootstrap touchspin AND on main menu if it has children.
2025-12-31 16:25:51 +01:00
3e96574e0a Merge branch 'feature/falcon-PS9' 2025-12-31 16:19:19 +01:00
48e776d80d feat(falcon-PS9): Add custom.scss file to follow 7-in-1 structure 2025-12-31 16:19:02 +01:00
ea6ebb4df1 feat(standard-styling):add svg_icon support for favorite_products 2025-12-31 14:03:31 +01:00
efa88a508a feat(standard-styling): Add button color map 2025-12-24 11:55:09 +01:00
27dfb4dc70 feat(standard-styling) Enhance search and styling
Improves search bar with SVG icon support for better visual consistency.

Adds utility SCSS file for managing global styles like heading selectors.

Introduces a checkmark SVG asset and reorganizes custom SCSS files following the 7-in-1 structure for better maintainability.

Comments out optional USP bar code in header.tpl to allow easy activation.
2025-12-24 09:37:59 +01:00
7ba1dfd4c8 fix(standard-styling): Remove duplicate displayNavFullWidth 2025-12-23 09:35:14 +01:00
22 changed files with 302 additions and 91 deletions

View File

@ -23,20 +23,11 @@ $green: #28a745;
$teal: #20c997;
$cyan: #17a2b8;
$primary: $blue;
$secondary: $gray-600;
$success: $green;
$info: $cyan;
$warning: #ff9a52;
$danger: $red;
$light: $gray-100;
$dark: $gray-800;
$primary: $blue;
$secondary: $gray-600;
// Map for utility classes
$theme-colors: (
"primary": $primary,
"secondary": $secondary,
//"tertiary": $tertiary,
//"quaternary": $quaternary,,
);

View File

@ -5,3 +5,4 @@
@import "layout/index";
@import "components/index";
@import "custom/custom";

View File

@ -1,4 +1,13 @@
// NOTE: All bootstrap overrides have been configured under themes/falcon/_dev/css/abstracts/variables/bootstrap
/*
This is the main custom SCSS file for the Falcon theme.
I am loosely following the 7 in 1 structure for better organization of the styles. Learn more here:
https://medium.com/@diyorbekjuraev77/be-a-master-at-creating-the-7-1-sass-pattern-776fdfb5a3b1
NOTE: All bootstrap overrides have been configured under themes/falcon/_dev/css/abstracts/variables/bootstrap
Look up all available Bootstrap variables here: https://rstudio.github.io/bslib/articles/bs5-variables/index.html
*/
//Abstracts: Things used throughout the site such as utility classes and generic overrides.
//@import "abstracts/base";
@ -7,7 +16,7 @@
//@import "abstracts/utilities";
// Components: parts of the theme itself that are not associated with a module.
//@import "components/";
//@import "components/buttons";
@import "components/forms";
// Modules: Styling for specific modules.
@ -20,5 +29,7 @@
@import "layout/swiper";
// Pages
//@import "pages/category";
//@import "pages/checkout";
//@import "pages/home";
//@import "pages/listing";
//@import "pages/product";

View File

@ -8,10 +8,34 @@
}
}
// Font weight utility classes generator
// Generates utility classes like .fw-100, .fw-200, etc.
@for $i from 100 through 900 {
@if $i % 100 == 0 {
.fw-#{$i} {
font-weight: #{$i} !important;
}
}
}
// gap size utility classes generator
// Generates utility classes like .gap-4
// Generates utility classes like .gap-4, .gap-col-4, .gap-row-4
@for $i from 1 through 35 {
.gap-#{$i} {
gap: rem-calc($i * 1px) !important;
}
.gap-col-#{$i} {
column-gap: rem-calc($i * 1px) !important;
}
.gap-row-#{$i} {
row-gap: rem-calc($i * 1px) !important;
}
}
// hex to rgba function
@function hex-to-rgba($hex, $alpha) {
$r: red($hex);
$g: green($hex);
$b: blue($hex);
@return rgba($r, $g, $b, $alpha);
}

View File

@ -42,3 +42,32 @@
@content;
}
}
// Mixin to add an after pseudo-element with a mask image to customize button colors
/* Example:
.btn-arrow-right{
&::after {
@include btn-after("../img/arrow-right.svg");
}
}
*/
@mixin btn-after($url, $color: currentColor) {
content: "";
display: inline-block;
width: 1em;
height: 1em;
margin-left: 0.5em;
vertical-align: middle;
background-color: currentColor;
mask-image: url(#{$url});
mask-size: contain;
mask-repeat: no-repeat;
mask-position: center;
-webkit-mask-image: url(#{$url});
-webkit-mask-size: contain;
-webkit-mask-repeat: no-repeat;
-webkit-mask-position: center;
}

View File

@ -1,12 +1,32 @@
// Color utility classes
@each $name, $color in $theme-colors {
.bg-#{$name} {
background-color: $color;
// Header selector for interpolation
// Example usage: #{$headings} { ... }
$headings: "h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6";
// Section Spacers
$section-spacer: rem-calc(50px);
$section-spacer-small: rem-calc(25px);
.section-spacer-both {
margin-top: $section-spacer;
margin-bottom: $section-spacer;
@include bs5-media-breakpoint-up(lg) {
margin-top: calc($section-spacer * 1.5);
margin-bottom: calc($section-spacer * 1.5);
}
&--small {
margin-top: $section-spacer-small;
margin-bottom: $section-spacer-small;
@include bs5-media-breakpoint-up(lg) {
margin-top: calc($section-spacer-small * 2);
margin-bottom: calc($section-spacer-small * 2);
}
}
}
@each $name, $color in $theme-colors {
.text-#{$name} {
color: $color;
.section-spacer {
@extend .section-spacer-both;
margin-bottom: unset;
&--small {
margin-bottom: unset;
}
}

View File

@ -0,0 +1,16 @@
// To customize text colors per button, use this map
$btn-color: (
"primary": $white,
"secondary": $white,
"light": $primary,
"dark": $white,
);
// Generate button color overrides from the map
@each $name, $color in $btn-color {
.btn-#{$name},
.btn-lg-#{$name},
.btn-sm-#{$name} {
color: $color !important;
}
}

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check2" viewBox="0 0 16 16">
<path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0"/>
</svg>

After

Width:  |  Height:  |  Size: 271 B

View File

@ -79,4 +79,19 @@ $(() => {
$(".js-select-link").on("change", ({ target }) => {
window.location.href = $(target).val();
});
// Postcode input formatting
const $postCodeInput = $("input[name='postcode']");
$postCodeInput.on("input", function () {
let value = $(this).val();
// Match 4 digits followed by 2 letters (e.g., 1234AB)
const match = value.match(/^(\d{4})([a-zA-Z]{2})$/);
if (match) {
// Add space between numbers and letters
const formatted = `${match[1]} ${match[2]}`;
$(this).val(formatted);
}
});
});

View File

@ -0,0 +1,29 @@
<div class="col-auto mt-2 px-1">
<a
class="product-page__action-btn btn btn-light shadow rounded-circle favorite-btn p-2"
href="#"
data-action="toggleFavorite"
data-active="false"
{if isset($product.id) && isset($product.id_product_attribute)}
data-key="{$product.id}_{$product.id_product_attribute}"
{/if}
>
<div class="favorite-btn__content favorite-btn__content--added">
{capture name="svg_output"}{svg_icon file='heart.svg' }{/capture}
{if $smarty.capture.svg_output}
{$smarty.capture.svg_output nofilter}
{else}
<span class="material-icons product-page__action-btn-icon d-block">favorite</span>
{/if}
</div>
<div class="favorite-btn__content favorite-btn__content--add">
{capture name="svg_output"}{svg_icon file='heart.svg' width="22"}{/capture}
{if $smarty.capture.svg_output}
{$smarty.capture.svg_output nofilter}
{else}
<span class="material-icons product-page__action-btn-icon d-block">favorite_border</span>
{/if}
</div>
</a>
</div>

View File

@ -0,0 +1,28 @@
<a
class="product-miniature__functional-btn product-miniature__functional-btn--top btn btn-light shadow rounded-circle favorite-btn"
href="#"
data-action="toggleFavorite"
data-active="false"
{if isset($product.id) && isset($product.id_product_attribute)}
data-key="{$product.id}_{$product.id_product_attribute}"
{/if}
>
<div class="favorite-btn__content favorite-btn__content--added">
{capture name="svg_output"}{svg_icon file='heart.svg'}{/capture}
{if $smarty.capture.svg_output}
{$smarty.capture.svg_output nofilter}
{else}
<span class="material-icons product-miniature__functional-btn-icon d-block">favorite</span>
{/if}
</div>
<div class="favorite-btn__content favorite-btn__content--add">
{capture name="svg_output"}{svg_icon file='heart.svg' width="22"}{/capture}
{if $smarty.capture.svg_output}
{$smarty.capture.svg_output nofilter}
{else}
<span class="material-icons product-miniature__functional-btn-icon d-block">favorite_border</span>
{/if}
</div>
</a>

View File

@ -9,7 +9,12 @@
name="s"
value="{$search_string}">
<button type="submit" class="search-form__btn btn">
<span class="material-icons">search</span>
{capture name="svg_output"}{svg_icon file='search.svg'}{/capture}
{if $smarty.capture.svg_output}
{$smarty.capture.svg_output nofilter}
{else}
<span class="header-top__icon material-icons">search</span>
{/if}
</button>
</div>
</form>

View File

@ -28,7 +28,13 @@
<div class="d-flex align-items-center mb-3 justify-content-between position-relative">
<span class="h4 mb-0">{l s='Store information' d='Shop.Theme.Global'}</span>
<a href="#footer_contact_list" class="icon-collapse stretched-link text-reset d-block d-md-none" data-toggle="collapse">
{capture name="svg_output"}{svg_icon file='chevron_down.svg'}{/capture}
{if $smarty.capture.svg_output}
<span style="margin-bottom: 3px;">
{$smarty.capture.svg_output nofilter}
{else}
<i class="material-icons d-block"></i>
{/if}
</a>
</div>

View File

@ -28,7 +28,13 @@
<div class="d-flex align-items-center mb-3 justify-content-between position-relative">
<span class="h4 mb-0">{l s='Your account' d='Shop.Theme.Customeraccount'}</span>
<a href="#footer_account_list" class="icon-collapse stretched-link text-reset d-block d-md-none" data-toggle="collapse">
{capture name="svg_output"}{svg_icon file='chevron_down.svg'}{/capture}
{if $smarty.capture.svg_output}
<span style="margin-bottom: 3px;">
{$smarty.capture.svg_output nofilter}
{else}
<i class="material-icons d-block"></i>
{/if}
</a>
</div>

View File

@ -34,7 +34,12 @@
{/if}
>
<div class="header-top__icon-container">
{capture name="svg_output"}{svg_icon file='person.svg'}{/capture}
{if $smarty.capture.svg_output}
{$smarty.capture.svg_output nofilter}
{else}
<span class="header-top__icon material-icons">person</span>
{/if}
</div>
</a>
</div>

View File

@ -4,7 +4,13 @@
<div class="d-flex align-items-center mb-3 justify-content-between position-relative">
<span class="h4 mb-0">{$linkBlock.title}</span>
<a href="#footer_sub_menu_{$_expand_id}" class="icon-collapse stretched-link text-reset d-block d-md-none" data-toggle="collapse">
{capture name="svg_output"}{svg_icon file='chevron_down.svg'}{/capture}
{if $smarty.capture.svg_output}
<span style="margin-bottom: 3px;">
{$smarty.capture.svg_output nofilter}
{else}
<i class="material-icons d-block"></i>
{/if}
</a>
</div>
<div id="footer_sub_menu_{$_expand_id}" class="collapse d-md-block">

View File

@ -29,7 +29,13 @@
<div class="d-flex align-items-center mb-3 justify-content-between position-relative">
<span class="h4 mb-0">{$linkBlock.title}</span>
<a href="#footer_sub_menu_{$_expand_id}" class="icon-collapse stretched-link text-reset d-block d-md-none" data-toggle="collapse">
{capture name="svg_output"}{svg_icon file='chevron_down.svg'}{/capture}
{if $smarty.capture.svg_output}
<span style="margin-bottom: 3px;">
{$smarty.capture.svg_output nofilter}
{else}
<i class="material-icons d-block"></i>
{/if}
</a>
</div>
<div id="footer_sub_menu_{$_expand_id}" class="collapse d-md-block">

View File

@ -21,9 +21,14 @@
>
<span class="align-self-center">{$node.label}</span>
{if $node.children|count}
{capture name="svg_output"}{svg_icon file='chevron_down.svg'}{/capture}
{if $smarty.capture.svg_output}
<span class="d-none d-md-block pl-1" style="margin-bottom: 3px;">
{svg_icon file='chevron_down.svg' }
{$smarty.capture.svg_output nofilter}
</span>
{else}
<i class="material-icons d-block"></i>
{/if}
{/if}
</a>
{if $node.children|count}

View File

@ -37,7 +37,6 @@
<div class="header-top js-header-top">
<div class="header-top__content pb-md-0 py-2">
<div class="container">
<div class="row header-top__row">
<div class="col flex-grow-0 header-top__block header-top__block--menu-toggle d-block d-md-none">
@ -84,13 +83,6 @@
</div>
</div>
</div>
<div class="container header-main-menu">
<div class="row">
<div class="col">
{hook h='displayNavFullWidth'}
</div>
</div>
</div>
</div>
</div>
{/block}

View File

@ -26,8 +26,12 @@
{block name='pagination_page_list'}
{if $pagination.should_be_displayed}
<div class="d-flex justify-content-between align-items-center">
<div class="results__block">
{l s='%curr_numer% van %total_items% resultaten' sprintf=['%curr_numer%' => $pagination.items_shown_to,'%total_items%' => $pagination.total_items] d='Shop.Theme.Actions'}
</div>
<nav>
<ul class="pagination justify-content-center mt-4 mb-2">
<ul class="pagination justify-content-center m-0">
{foreach from=$pagination.pages item="page"}
<li class="page-item{if $page.current} active{/if} {if $page.type === 'spacer'}disabled{/if}">
{if $page.type === 'spacer'}
@ -59,5 +63,6 @@
{/foreach}
</ul>
</nav>
</div>
{/if}
{/block}

View File

@ -1,5 +1,13 @@
{* Defensive: Handles LazyArray objects for category *}
{if is_object($category)}
{$category = $category|json_encode|json_decode:true}
{if isset($category.category)}
{$category = $category.category}
{/if}
{/if}
<div id="js-product-list-footer">
{if $category.additional_description && $listing.pagination.items_shown_from == 1}
{if isset($category.additional_description) && $category.additional_description && $listing.pagination.items_shown_from == 1}
<div id="category-description-2" class="cms-content my-3">
{$category.additional_description nofilter}
</div>

View File

@ -26,7 +26,7 @@
{$listingType = $type|default:'listing'}
<div
{if $listingType === 'listing'}
class="products-list__block products-list__block--grid"
class="products-list__block col col-sm-6 col-lg-4 col-xl-3"
{elseif $listingType === 'slider'}
class="swiper-slide product-slider__item col-6 col-md-4 col-lg-3"
{/if}