├── resources └── .gitkeep ├── translations ├── merged │ ├── .gitkeep │ ├── en-gb.untranslated.yaml │ ├── de-de.all.yaml │ ├── de-de.untranslated.yaml │ └── en-gb.all.yaml ├── translated │ └── .gitkeep ├── src │ ├── de-de.home.json │ ├── en-gb.home.json │ ├── en-gb.common.json │ ├── en-gb.productpage.json │ ├── en-gb.checkout.json │ ├── en-gb.cart.json │ └── en-gb.search.json └── Readme.md ├── frontend ├── src │ ├── mock │ │ └── _mockmap.js │ ├── page │ │ ├── error │ │ │ ├── error.sass │ │ │ ├── 503.pug │ │ │ ├── withCode.pug │ │ │ └── 404.pug │ │ ├── home │ │ │ ├── home.sass │ │ │ ├── home.pug │ │ │ └── molecule │ │ │ │ └── carousel │ │ │ │ └── carousel.pug │ │ ├── search │ │ │ ├── search.sass │ │ │ └── products.pug │ │ ├── category │ │ │ ├── category.sass │ │ │ └── category.pug │ │ ├── product │ │ │ ├── product.js │ │ │ └── product.pug │ │ ├── checkout │ │ │ ├── checkout.js │ │ │ ├── emptycart.pug │ │ │ ├── carterror.pug │ │ │ ├── cart.pug │ │ │ ├── success.pug │ │ │ ├── startcheckout.pug │ │ │ ├── checkout.pug │ │ │ ├── review.pug │ │ │ └── organism │ │ │ │ └── checkoutform.pug │ │ └── offers │ │ │ └── offers.pug │ ├── index.js │ ├── asset │ │ ├── img │ │ │ ├── sample.jpg │ │ │ ├── overlays │ │ │ │ ├── 01.png │ │ │ │ ├── 02.png │ │ │ │ ├── 03.png │ │ │ │ ├── 04.png │ │ │ │ ├── 05.png │ │ │ │ ├── 06.png │ │ │ │ ├── 07.png │ │ │ │ ├── 08.png │ │ │ │ └── 09.png │ │ │ ├── flamingo-logo-black.png │ │ │ ├── lightbox │ │ │ │ ├── preloader.gif │ │ │ │ ├── default-skin.png │ │ │ │ └── default-skin.svg │ │ │ ├── visuals │ │ │ │ ├── flamingo-scetch.jpg │ │ │ │ ├── flamingo-600205_1280.jpg │ │ │ │ └── digital-art-3054735_1280.jpg │ │ │ └── svg │ │ │ │ ├── arrow_left.svg │ │ │ │ └── arrow_right.svg │ │ ├── font │ │ │ └── roboto │ │ │ │ ├── Roboto-Bold.eot │ │ │ │ ├── Roboto-Bold.ttf │ │ │ │ ├── Roboto-Bold.woff │ │ │ │ ├── Roboto-Light.eot │ │ │ │ ├── Roboto-Light.ttf │ │ │ │ ├── Roboto-Thin.eot │ │ │ │ ├── Roboto-Thin.ttf │ │ │ │ ├── Roboto-Thin.woff │ │ │ │ ├── Roboto-Bold.woff2 │ │ │ │ ├── Roboto-Light.woff │ │ │ │ ├── Roboto-Light.woff2 │ │ │ │ ├── Roboto-Medium.eot │ │ │ │ ├── Roboto-Medium.ttf │ │ │ │ ├── Roboto-Medium.woff │ │ │ │ ├── Roboto-Regular.eot │ │ │ │ ├── Roboto-Regular.ttf │ │ │ │ ├── Roboto-Thin.woff2 │ │ │ │ ├── Roboto-Medium.woff2 │ │ │ │ ├── Roboto-Regular.woff │ │ │ │ └── Roboto-Regular.woff2 │ │ └── i18n │ │ │ └── en-gb.js │ ├── base │ │ └── style │ │ │ └── mdp-ecom-base │ │ │ ├── free │ │ │ ├── _dropdowns.sass │ │ │ ├── _msc.sass │ │ │ ├── _footers.sass │ │ │ ├── _badges.sass │ │ │ ├── _depreciated.sass │ │ │ ├── _input-group.sass │ │ │ ├── _cards.sass │ │ │ ├── _list-group.sass │ │ │ ├── _tables.sass │ │ │ ├── _carousels.sass │ │ │ ├── _pagination.sass │ │ │ ├── _navbars.sass │ │ │ ├── _buttons.sass │ │ │ ├── _forms.sass │ │ │ ├── _animations-basic.sass │ │ │ └── _modals.sass │ │ │ └── core │ │ │ ├── _helpers.sass │ │ │ ├── _global.sass │ │ │ ├── _masks.sass │ │ │ ├── bootstrap │ │ │ └── _functions.sass │ │ │ ├── _waves.sass │ │ │ ├── _typography.sass │ │ │ ├── _mixins.sass │ │ │ └── _variables.sass │ ├── molecule │ │ ├── productTile │ │ │ ├── productTileTruncate.pug │ │ │ ├── productTile.sass │ │ │ └── productTile.pug │ │ ├── productMedia │ │ │ └── productMedia.pug │ │ └── pagination │ │ │ └── pagination.pug │ ├── organism │ │ ├── productList │ │ │ ├── productList.sass │ │ │ └── productList.pug │ │ └── cart │ │ │ └── cart.pug │ ├── atom │ │ ├── debug │ │ │ └── debug.pug │ │ ├── console │ │ │ └── console.pug │ │ ├── dropdown │ │ │ └── dropdown.pug │ │ └── price │ │ │ ├── price.pug │ │ │ └── price.sass │ ├── template │ │ └── base │ │ │ ├── style.sass │ │ │ ├── molecule │ │ │ ├── head │ │ │ │ └── head.pug │ │ │ ├── categoryMenu │ │ │ │ └── categoryMenu.pug │ │ │ └── footer │ │ │ │ └── footer.pug │ │ │ └── base.pug │ └── index.sass ├── postcss.config.js └── package.json ├── .dockerignore ├── graphql ├── schema │ ├── schema.graphql │ ├── flamingo.me_flamingo-commerce_v3_price_interfaces_graphql-Service.graphql │ ├── flamingo.me_flamingo-commerce_v3_category_interfaces_graphql-Service.graphql │ ├── flamingo.me_flamingo-commerce_v3_customer_interfaces_graphql-Service.graphql │ ├── flamingo.me_flamingo-commerce_v3_search_interfaces_graphql-Service.graphql │ ├── flamingo.me_flamingo-commerce_v3_checkout_interfaces_graphql-Service.graphql │ └── flamingo.me_flamingo-commerce_v3_product_interfaces_graphql-Service.graphql ├── emptymodule.go └── module.go ├── config ├── config_dev.yml ├── routes.yml ├── magento2 │ ├── config.yml │ └── de │ │ └── config.yml ├── csv │ ├── config.yml │ └── de │ │ └── config.yml └── config.yml ├── preparetranslations.sh ├── docs ├── swagger.yaml ├── swagger.json └── docs.go ├── .gitignore ├── Dockerfile ├── Makefile ├── main.go ├── Readme.md └── go.mod /resources/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /translations/merged/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/mock/_mockmap.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /translations/translated/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/page/error/error.sass: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /translations/merged/en-gb.untranslated.yaml: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | config/config_local.yml 2 | resources/products.zip -------------------------------------------------------------------------------- /frontend/src/index.js: -------------------------------------------------------------------------------- 1 | import 'index.sass' 2 | //import 'page/checkout/checkout.js' 3 | import 'page/product/product.js' -------------------------------------------------------------------------------- /frontend/src/asset/img/sample.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/img/sample.jpg -------------------------------------------------------------------------------- /graphql/schema/schema.graphql: -------------------------------------------------------------------------------- 1 | type Query { flamingo: String } 2 | type Mutation { flamingo: String } 3 | scalar Time 4 | scalar Map 5 | scalar Date -------------------------------------------------------------------------------- /frontend/src/asset/img/overlays/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/img/overlays/01.png -------------------------------------------------------------------------------- /frontend/src/asset/img/overlays/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/img/overlays/02.png -------------------------------------------------------------------------------- /frontend/src/asset/img/overlays/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/img/overlays/03.png -------------------------------------------------------------------------------- /frontend/src/asset/img/overlays/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/img/overlays/04.png -------------------------------------------------------------------------------- /frontend/src/asset/img/overlays/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/img/overlays/05.png -------------------------------------------------------------------------------- /frontend/src/asset/img/overlays/06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/img/overlays/06.png -------------------------------------------------------------------------------- /frontend/src/asset/img/overlays/07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/img/overlays/07.png -------------------------------------------------------------------------------- /frontend/src/asset/img/overlays/08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/img/overlays/08.png -------------------------------------------------------------------------------- /frontend/src/asset/img/overlays/09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/img/overlays/09.png -------------------------------------------------------------------------------- /config/config_dev.yml: -------------------------------------------------------------------------------- 1 | flamingo: 2 | session: 3 | cookie: 4 | secure: false 5 | debug: 6 | mode: true 7 | core: 8 | zap: 9 | loglevel: Debug -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Bold.eot -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Bold.ttf -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Bold.woff -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Light.eot -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Light.ttf -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Thin.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Thin.eot -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Thin.ttf -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Thin.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Thin.woff -------------------------------------------------------------------------------- /frontend/src/asset/img/flamingo-logo-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/img/flamingo-logo-black.png -------------------------------------------------------------------------------- /frontend/src/asset/img/lightbox/preloader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/img/lightbox/preloader.gif -------------------------------------------------------------------------------- /translations/src/de-de.home.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "header.welcome.subtitle", 4 | "translation": "Standart demo shop mit carotene templates" 5 | } 6 | ] 7 | -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Bold.woff2 -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Light.woff -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Light.woff2 -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Medium.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Medium.eot -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Medium.ttf -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Medium.woff -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Regular.eot -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Regular.ttf -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Thin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Thin.woff2 -------------------------------------------------------------------------------- /frontend/src/asset/img/lightbox/default-skin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/img/lightbox/default-skin.png -------------------------------------------------------------------------------- /translations/src/en-gb.home.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "header.welcome.subtitle", 4 | "translation": "Standard demo shop with carotene templates" 5 | } 6 | ] 7 | -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Medium.woff2 -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Regular.woff -------------------------------------------------------------------------------- /frontend/src/asset/font/roboto/Roboto-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/font/roboto/Roboto-Regular.woff2 -------------------------------------------------------------------------------- /frontend/src/asset/img/visuals/flamingo-scetch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/img/visuals/flamingo-scetch.jpg -------------------------------------------------------------------------------- /frontend/src/asset/img/visuals/flamingo-600205_1280.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/img/visuals/flamingo-600205_1280.jpg -------------------------------------------------------------------------------- /config/routes.yml: -------------------------------------------------------------------------------- 1 | - path: / 2 | name: index 3 | controller: flamingo.render(tpl="home/home") 4 | 5 | - path: /offers 6 | name: index 7 | controller: flamingo.render(tpl="offers/offers") -------------------------------------------------------------------------------- /frontend/src/asset/img/visuals/digital-art-3054735_1280.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-love-flamingo/commerce-demo-carotene/HEAD/frontend/src/asset/img/visuals/digital-art-3054735_1280.jpg -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/free/_dropdowns.sass: -------------------------------------------------------------------------------- 1 | // Dropdowns 2 | .dropdown 3 | .dropdown-menu 4 | .dropdown-item 5 | &:active 6 | background-color: $grey-darken-1 7 | -------------------------------------------------------------------------------- /frontend/src/molecule/productTile/productTileTruncate.pug: -------------------------------------------------------------------------------- 1 | mixin productTileTruncate(text, maxLength) 2 | if text.length > maxLength 3 | = text.slice(0, maxLength-1) + '…' 4 | else 5 | = text 6 | -------------------------------------------------------------------------------- /frontend/src/organism/productList/productList.sass: -------------------------------------------------------------------------------- 1 | .productList 2 | .product-image 3 | max-height: 220px 4 | margin: auto 5 | margin-top: 10px 6 | 7 | .product-card 8 | min-height: 400px -------------------------------------------------------------------------------- /preparetranslations.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Preparing merged file for common side.. (main)" 4 | go run github.com/nicksnyder/go-i18n/goi18n merge -sourceLanguage en-gb -format yaml -outdir translations/merged translations/src/*.json 5 | -------------------------------------------------------------------------------- /frontend/src/page/home/home.sass: -------------------------------------------------------------------------------- 1 | .carousel 2 | height: 60vh 3 | 4 | @media (max-width: 740px) 5 | .carousel 6 | height: 100vh 7 | 8 | @media (min-width: 800px) and (max-width: 850px) 9 | .carousel 10 | height: 100vh 11 | -------------------------------------------------------------------------------- /frontend/src/asset/img/svg/arrow_left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/asset/img/svg/arrow_right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/asset/i18n/en-gb.js: -------------------------------------------------------------------------------- 1 | /* this file is generated via the carotene-cli buildAssets task */ 2 | import i18n from 'carotene/src/base/js/lib/i18n' 3 | const translations = require('../../../dist/asset/i18n/en-gb.json') 4 | i18n.setLocaleMessage('default', translations) 5 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/free/_msc.sass: -------------------------------------------------------------------------------- 1 | // Miscellaneous 2 | // Edge Headers 3 | .edge-header 4 | display: block 5 | height: $edge-header-height 6 | background-color: $edge-header-background-color 7 | 8 | .free-bird 9 | margin-top: $edge-header-margin-top 10 | -------------------------------------------------------------------------------- /frontend/src/atom/debug/debug.pug: -------------------------------------------------------------------------------- 1 | mixin debug(obj, headline) 2 | if config('flamingo.debug.mode') 3 | - var title = 'Debug:' 4 | if headline 5 | - title= 'Debug: ' + headline 6 | 7 | .utilDebug 8 | h5.utilDebugTitle= title 9 | pre.utilDebugContents= debug(obj) 10 | -------------------------------------------------------------------------------- /frontend/src/page/search/search.sass: -------------------------------------------------------------------------------- 1 | .wrapper 2 | display: flex 3 | width: 100% 4 | align-items: stretch 5 | 6 | #sidebar 7 | min-width: 250px 8 | max-width: 250px 9 | 10 | 11 | .category 12 | a.active 13 | background-color: #dafdff 14 | .level2-item 15 | padding: .25rem 1.5rem -------------------------------------------------------------------------------- /docs/swagger.yaml: -------------------------------------------------------------------------------- 1 | basePath: /en 2 | info: 3 | contact: 4 | email: flamingo@aoe.com 5 | name: Flamingo 6 | url: https://gitter.im/i-love-flamingo/community# 7 | license: 8 | name: MIT 9 | title: Flamingo Commerce Demo Shop 10 | version: "1.0" 11 | paths: {} 12 | swagger: "2.0" 13 | -------------------------------------------------------------------------------- /frontend/src/page/category/category.sass: -------------------------------------------------------------------------------- 1 | .wrapper 2 | display: flex 3 | width: 100% 4 | align-items: stretch 5 | 6 | #sidebar 7 | min-width: 250px 8 | max-width: 250px 9 | 10 | 11 | .category 12 | a.active 13 | background-color: #dafdff 14 | .level2-item 15 | padding: .25rem 1.5rem -------------------------------------------------------------------------------- /frontend/src/atom/console/console.pug: -------------------------------------------------------------------------------- 1 | mixin console(obj, group) 2 | if config('debug.mode') 3 | if group 4 | script!= 'console.group("' + group + '")' 5 | 6 | - var output = debug(obj, true) 7 | 8 | script!= 'console.log(' + output + ')' 9 | 10 | if group 11 | script!= 'console.groupEnd()' 12 | -------------------------------------------------------------------------------- /frontend/src/page/product/product.js: -------------------------------------------------------------------------------- 1 | 2 | jQuery(function () { 3 | jQuery("#variant-selector").change(function () { 4 | let url = jQuery("#variant-selector").children("option:selected").data('url') 5 | if (url !== undefined && url !== "") { 6 | window.location.href = url 7 | } 8 | }); 9 | }); -------------------------------------------------------------------------------- /frontend/src/page/checkout/checkout.js: -------------------------------------------------------------------------------- 1 | 2 | jQuery(function () { 3 | jQuery("#useBillingAddress").change(function () { 4 | if (jQuery("#useBillingAddress").prop('checked')) { 5 | jQuery("#useBillingAddressToggle").collapse("hide") 6 | } 7 | jQuery("#useBillingAddressToggle").collapse("show") 8 | }); 9 | }); -------------------------------------------------------------------------------- /frontend/src/page/checkout/emptycart.pug: -------------------------------------------------------------------------------- 1 | extends /template/base/base 2 | include /organism/cart/cart 3 | 4 | block maincontent 5 | main.mt-5.pt-4 6 | div.container.wow.fadeIn 7 | h2.my-5.h2.text-center Checkout 8 | h3 Your cart is empty 9 | a.btn.btn-primary.btn-md.my-0.p(href=url("index")) Back to home 10 | 11 | -------------------------------------------------------------------------------- /frontend/src/page/error/503.pug: -------------------------------------------------------------------------------- 1 | extends /template/base/base 2 | 3 | 4 | block content 5 | .errorTile 6 | h1.errorHeadline= __('error.503.headline', 'Sorry, something has gone wrong…') 7 | a(href='/')= __('error.homeButton', 'Go to homepage') 8 | 9 | if config('debug.mode') 10 | .errorDebug 11 | .errorDebugTitle Debug: 12 | pre.errorDebugContent= error 13 | -------------------------------------------------------------------------------- /frontend/src/page/error/withCode.pug: -------------------------------------------------------------------------------- 1 | extends /template/base/base 2 | 3 | 4 | block content 5 | .errorTile 6 | h1.errorHeadline= __('error.common.headline', 'Sorry, something went wrong') 7 | a(href='/')= __('error.homeButton', 'Go to homepage') 8 | 9 | if config('debug.mode') 10 | .errorDebug 11 | .errorDebugTitle Debug: 12 | pre.errorDebugContent= error 13 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/free/_footers.sass: -------------------------------------------------------------------------------- 1 | // Footers 2 | footer 3 | &.page-footer 4 | bottom: 0 5 | color: $white-base 6 | 7 | .container-fluid 8 | width: auto 9 | 10 | .footer-copyright 11 | overflow: hidden 12 | background-color: $footer-copyright-bg-color 13 | color: $footer-copyright-color 14 | 15 | a 16 | color: $white-base 17 | -------------------------------------------------------------------------------- /translations/src/en-gb.common.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "error.common.headline", 4 | "translation": "Error occured" 5 | }, 6 | { 7 | "id": "error.homeButton", 8 | "translation": "Back to home" 9 | }, 10 | { 11 | "id": "error.404.headline", 12 | "translation": "Error 404" 13 | }, 14 | { 15 | "id": "error.503.headline", 16 | "translation": "Error 503" 17 | } 18 | ] 19 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/free/_badges.sass: -------------------------------------------------------------------------------- 1 | // Badges 2 | .badge 3 | box-shadow: $z-depth-1 4 | border-radius: $border-radius-base 5 | color: $white !important 6 | 7 | .badge-pill 8 | border-radius: $badge-pill-border-radius 9 | padding-right: $badge-pill-padding-x 10 | padding-left: $badge-pill-padding-x 11 | 12 | @each $name, $color in $basic-mdb-colors 13 | +make-badge($name, $color) 14 | -------------------------------------------------------------------------------- /frontend/src/page/error/404.pug: -------------------------------------------------------------------------------- 1 | extends /template/base/base 2 | 3 | 4 | block content 5 | .errorTile 6 | h1.errorHeadline= __('error.404.headline', 'Sorry, we can\'t find that page or something has gone wrong…') 7 | a(href='/')= __('error.homeButton', 'Go to homepage') 8 | 9 | 10 | if config('debug.mode') 11 | .errorDebug 12 | .errorDebugTitle Debug: 13 | pre.errorDebugContent= error 14 | -------------------------------------------------------------------------------- /graphql/emptymodule.go: -------------------------------------------------------------------------------- 1 | // Code generated by flamingo.me/graphql DO NOT EDIT! 2 | //go:build graphql 3 | // +build graphql 4 | 5 | package graphql 6 | 7 | import "flamingo.me/dingo" 8 | 9 | // this empty module is used by go generate to provide a dingo module because module.go is not compiled during generate 10 | type Module struct{} 11 | 12 | // Configure dummy method 13 | func (Module) Configure(injector *dingo.Injector) {} 14 | -------------------------------------------------------------------------------- /config/magento2/config.yml: -------------------------------------------------------------------------------- 1 | flamingo: 2 | router: 3 | path: /magento 4 | 5 | commerce: 6 | category: 7 | useCategoryFixedAdapter: false 8 | 9 | flamingo-commerce-adapter-magento2: 10 | product: 11 | csvPath: "resources/magento/catalog_product.csv" 12 | magento2: 13 | #accessToken: REPLACEME 14 | #host: local.magento 15 | #scheme: http 16 | path: /rest/default 17 | 18 | flamingo-commerce-adapter-standalone: 19 | enableIndexing: true -------------------------------------------------------------------------------- /docs/swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "Flamingo Commerce Demo Shop", 5 | "contact": { 6 | "name": "Flamingo", 7 | "url": "https://gitter.im/i-love-flamingo/community#", 8 | "email": "flamingo@aoe.com" 9 | }, 10 | "license": { 11 | "name": "MIT" 12 | }, 13 | "version": "1.0" 14 | }, 15 | "basePath": "/en", 16 | "paths": {} 17 | } -------------------------------------------------------------------------------- /frontend/src/page/checkout/carterror.pug: -------------------------------------------------------------------------------- 1 | extends /template/base/base 2 | include /organism/cart/cart 3 | 4 | 5 | block maincontent 6 | main.mt-5.pt-4 7 | div.container.wow.fadeIn.content-minheight 8 | //-h2.my-5.h2.text-center Cart 9 | h3.d-flex.justify-content-between.align-items-center.mb-3.mt-4=__("Your cart") 10 | h4 Error: Something unexpected happend 11 | a.btn.btn-primary.btn-md.my-0.p(href=url("cart.view")) Proceed to cart 12 | 13 | -------------------------------------------------------------------------------- /config/csv/config.yml: -------------------------------------------------------------------------------- 1 | flamingo: 2 | router: 3 | path: /en 4 | 5 | # Configure the modules flamingoCommerceAdapterStandalone 6 | flamingoCommerceAdapterStandalone: 7 | csvindexing: 8 | products: 9 | file: 10 | path: "resources/products/products_en.csv" 11 | delimiter: "," 12 | categories: 13 | file: 14 | path: "resources/products/categories.csv" 15 | delimiter: "," 16 | locale: "en_GB" 17 | currency: "GBP" 18 | -------------------------------------------------------------------------------- /frontend/src/page/checkout/cart.pug: -------------------------------------------------------------------------------- 1 | extends /template/base/base 2 | include /organism/cart/cart 3 | 4 | 5 | block maincontent 6 | main.mt-5.pt-4 7 | div.container.wow.fadeIn.content-minheight 8 | //-h2.my-5.h2.text-center Cart 9 | h3.d-flex.justify-content-between.align-items-center.mb-3.mt-4=__("Your cart") 10 | +cart(decoratedCart,cartValidationResult,true) 11 | a.btn.btn-primary.btn-md.my-0.p(href=url("checkout.start")) Proceed to checkout 12 | 13 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/free/_depreciated.sass: -------------------------------------------------------------------------------- 1 | // These settings will be only for one version 2 | 3 | // Masks 4 | .view 5 | .full-bg-img 6 | height: 100% 7 | 8 | .full-bg-img, 9 | .full-bg-img video 10 | background-repeat: no-repeat 11 | background-position: center center 12 | background-size: cover 13 | 14 | // Full background 15 | .full-height, 16 | .full-height body, 17 | .full-height header, 18 | .full-height header .view 19 | height: 100% 20 | -------------------------------------------------------------------------------- /translations/src/en-gb.productpage.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "product.attribute.__group_packageSizes", 4 | "translation": "Package size" 5 | }, 6 | { 7 | "id": "product.attribute.washingInstructions", 8 | "translation": "Washing Instruction" 9 | }, 10 | { 11 | "id": "product.attribute.baseColor", 12 | "translation": "Base color" 13 | }, 14 | { 15 | "id": "product.attribute.manufacturerColor", 16 | "translation": "Manufacturer color" 17 | } 18 | ] 19 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/free/_input-group.sass: -------------------------------------------------------------------------------- 1 | // Input group 2 | .md-form 3 | &.input-group 4 | label 5 | top: 0 6 | margin-bottom: 0 7 | 8 | .input-group-text 9 | background-color: $input-group-text-bgc 10 | 11 | &.md-addon 12 | border: none 13 | background-color: transparent 14 | font-weight: 500 15 | 16 | .form-control 17 | margin: 0 18 | padding: $input-group-form-control-py $input-group-form-control-px 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | orders 2 | frontend.zip 3 | flamingo-commerce-demo-carotene 4 | frontend/dist 5 | .DS_Store 6 | .cache 7 | .idea 8 | .gradle 9 | .sass-cache 10 | .temp 11 | node_modules 12 | npm-debug.log 13 | yarn-error.log 14 | src/sass/.includes 15 | coverage 16 | junit.xml 17 | /vendor 18 | /integration-test/shared 19 | context_local.yml 20 | resources/magento 21 | resources/magento.zip 22 | resources/products 23 | resources/products.zip 24 | **/logs/pact.log 25 | **/pacts/*.json 26 | config/config_local.yml 27 | -------------------------------------------------------------------------------- /frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('mqpacker')({ 4 | sort: true 5 | }), 6 | require('autoprefixer'), 7 | require('postcss-plugin-px2rem')({ 8 | rootValue: 16, 9 | unitPrecision: 5, 10 | propWhiteList: [], 11 | propBlackList: [], 12 | selectorBlackList: [], 13 | ignoreIdentifier: false, 14 | replace: true, 15 | mediaQuery: false, 16 | minPixelValue: 0 17 | }), 18 | require('postcss-object-fit-images') 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/free/_cards.sass: -------------------------------------------------------------------------------- 1 | // Cards 2 | .card 3 | box-shadow: $z-depth-1 4 | border: 0 5 | font-weight: 400 6 | 7 | &[class*="border"] 8 | border: 1px solid $grey-base 9 | box-shadow: none 10 | 11 | .card-body 12 | h1, h2, h3, h4, h5, h6 13 | font-weight: 400 14 | 15 | .card-title 16 | a 17 | transition: $md-card-link-transition 18 | 19 | &:hover 20 | transition: $md-card-link-transition 21 | 22 | .card-text 23 | color: $md-card-text-color 24 | font-size: $md-card-font-size 25 | font-weight: 400 26 | -------------------------------------------------------------------------------- /frontend/src/page/offers/offers.pug: -------------------------------------------------------------------------------- 1 | extends /template/base/base 2 | 3 | include /organism/productList/productList 4 | 5 | 6 | block maincontent 7 | main.mt-5.pt-4 8 | .container 9 | h1=__("special-offers").setDefaultLabel("Special Offers") 10 | section.text-center.mb-4 11 | // Grid row 12 | //+productListByProductSearchResult(findProducts("homepagewidget",{"query":"","pageSize": "10","sortDirection":"A","sortBy":'name'},{"categories":['laptops']})) 13 | +productListByProductSearchResult(findProducts("homepagewidget",{"query":"","pageSize": "8","sortDirection":"A","sortBy":'name'},{})) -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:alpine AS builder 2 | RUN apk update && apk add --no-cache ca-certificates tzdata && update-ca-certificates 3 | 4 | FROM scratch 5 | COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo 6 | COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ 7 | 8 | ADD frontend/dist /frontend/dist 9 | ADD frontend/src /frontend/src 10 | ADD flamingo-commerce-demo-carotene /flamingo-commerce-demo-carotene 11 | ADD config /config 12 | ADD translations /translations 13 | ADD resources /resources 14 | ADD docs/swagger.json /docs/swagger.json 15 | 16 | ENTRYPOINT ["/flamingo-commerce-demo-carotene"] 17 | CMD ["serve"] 18 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/free/_list-group.sass: -------------------------------------------------------------------------------- 1 | // List group 2 | .media 3 | .media-left 4 | padding: $list-group-padding 5 | 6 | img 7 | box-shadow: $z-depth-1 8 | 9 | .list-group 10 | .list-group-item 11 | &:first-child 12 | border-top-left-radius: $border-radius-base 13 | border-top-right-radius: $border-radius-base 14 | 15 | &:last-child 16 | border-bottom-left-radius: $border-radius-base 17 | border-bottom-right-radius: $border-radius-base 18 | 19 | a, 20 | button 21 | transition: $list-group-transition 22 | 23 | &:hover 24 | transition: $list-group-transition 25 | -------------------------------------------------------------------------------- /config/magento2/de/config.yml: -------------------------------------------------------------------------------- 1 | flamingo: 2 | router: 3 | path: /magento/de 4 | core: 5 | locale: 6 | locale: de-de 7 | fallbackLocales: 8 | - en-gb 9 | translationFiles: 10 | - translations/merged/de-de.all.yaml 11 | - translations/merged/en-gb.all.yaml 12 | accounting: 13 | thousand: '.' 14 | decimal: ',' 15 | formatZero: '-,- %s' 16 | format: "%v %s" 17 | numbers: 18 | decimal: '.' 19 | thousand: ',' 20 | precision: 1 21 | date: 22 | dateFormat: 02 Jan 2006 23 | timeFormat: 15:04 24 | dateTimeFormat: 02 Jan 2006 15:04:05 25 | location: Europe/Berlin -------------------------------------------------------------------------------- /frontend/src/molecule/productMedia/productMedia.pug: -------------------------------------------------------------------------------- 1 | mixin productMedia(mediaItem, size) 2 | if !size 3 | - var size = "200x" 4 | 5 | case mediaItem.type 6 | when 'image-external' 7 | img(src=mediaItem.reference alt=mediaItem.title)&attributes(attributes) 8 | when 'magento-product-image' 9 | img(src="http://local.magento/pub/media/catalog/product/"+mediaItem.reference alt=mediaItem.title)&attributes(attributes) 10 | when 'csvCommerceReference' 11 | img(src=url("csvcommerce.image.get", { 12 | "size": size, 13 | "filename": mediaItem.reference 14 | }) alt=mediaItem.title)&attributes(attributes) 15 | 16 | -------------------------------------------------------------------------------- /frontend/src/page/checkout/success.pug: -------------------------------------------------------------------------------- 1 | extends /template/base/base 2 | include /organism/cart/cart 3 | 4 | block maincontent 5 | main.mt-5.pt-4 6 | div.container 7 | //+debug(decoratedCart.cart) 8 | h2.my-5.h2.text-center Checkout - Thank you 9 | div.row 10 | div.col-md-8.mb-4 11 | h4.d-flex.justify-content-between.align-items-center.mb-3 12 | span.text-muted Your order has been received 13 | div.card 14 | .card-body 15 | 16 | p We will send an email to #{email} 17 | 18 | each placedOrder in placedOrderInfos 19 | p Order number #{placedOrder.orderNumber} -------------------------------------------------------------------------------- /frontend/src/template/base/style.sass: -------------------------------------------------------------------------------- 1 | // Template style 2 | 3 | /* Required height of parents of the Half Page Carousel for proper displaying carousel itself 4 | html, 5 | body, 6 | .view 7 | height: 100% 8 | 9 | /* Half Page Carousel itself 10 | .carousel 11 | height: 50% 12 | 13 | .carousel-inner 14 | height: 100% 15 | 16 | .carousel-item, 17 | .active 18 | height: 100% 19 | 20 | /* Adjustment for mobile devices 21 | @media (max-width: 776px) 22 | .carousel 23 | height: 100% 24 | 25 | /* Footer color for sake of consistency with Navbar 26 | .page-footer 27 | background-color: #929FBA 28 | 29 | .content-minheight 30 | min-height: 500px 31 | 32 | #content 33 | width: 100% -------------------------------------------------------------------------------- /frontend/src/page/checkout/startcheckout.pug: -------------------------------------------------------------------------------- 1 | extends /template/base/base 2 | include /organism/cart/cart 3 | 4 | block maincontent 5 | main.mt-5.pt-4 6 | div.container.wow.fadeIn 7 | h2.my-5.h2.text-center Checkout 8 | div.row 9 | div.col-md-8.mb-4 10 | div.card 11 | div.row.p-5 12 | div.col-md-6.mb-4 13 | h2 Login 14 | p (here link to login - see flamingo.auth module) 15 | div.col-md-6.mb-4 16 | h2 Guest 17 | a.btn.btn-primary.btn-md.my-0.p(href=url("checkout")) Proceed as guest 18 | div.col-md-4.mb-4 19 | +cart(decoratedCart,cartValidationResult,false) 20 | 21 | -------------------------------------------------------------------------------- /frontend/src/template/base/molecule/head/head.pug: -------------------------------------------------------------------------------- 1 | head 2 | meta(charset='utf-8') 3 | meta(name='viewport', content='width=device-width, initial-scale=1, shrink-to-fit=no') 4 | meta(http-equiv='x-ua-compatible', content='ie=edge') 5 | block title 6 | title= config('template.defaultTitle') 7 | block styles 8 | 9 | // Font Awesome 10 | link(rel='stylesheet', href='https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css') 11 | // Bootstrap core CSS 12 | link(rel="stylesheet", href=asset("asset/css/bootstrap.min.css")) 13 | //our build app.css 14 | link(rel="stylesheet", href=asset("css/main.css")) 15 | 16 | block js-vendor 17 | //script(src=asset("js/vendor.js")) 18 | 19 | -------------------------------------------------------------------------------- /frontend/src/atom/dropdown/dropdown.pug: -------------------------------------------------------------------------------- 1 | //- 2 | param: cfg [Object] The config object 3 | { 4 | size: 'medium' | 'large' 5 | emptyOption: true | false 6 | } 7 | 8 | mixin dropdown(cfg) 9 | - 10 | cfg = cfg || {} 11 | cfg.size = cfg.size || 'medium' 12 | 13 | if (Object.keys(cfg).indexOf('emptyOption') > -1) 14 | cfg.emptyOption = cfg.emptyOption 15 | else 16 | cfg.emptyOption = true 17 | 18 | var sizeClass = 'dropdownSize' + cfg.size.charAt(0).toUpperCase() + cfg.size.slice(1) 19 | 20 | .dropdownWrapper(class=sizeClass) 21 | select&attributes(attributes) 22 | if cfg.emptyOption 23 | option(value='')= __('Please select') 24 | if block 25 | block 26 | -------------------------------------------------------------------------------- /config/csv/de/config.yml: -------------------------------------------------------------------------------- 1 | flamingo: 2 | router: 3 | path: /de 4 | core: 5 | locale: 6 | locale: de-de 7 | fallbackLocales: 8 | - en-gb 9 | translationFiles: 10 | - translations/merged/de-de.all.yaml 11 | - translations/merged/en-gb.all.yaml 12 | numbers: 13 | decimal: ',' 14 | thousand: '.' 15 | precision: 1 16 | date: 17 | dateFormat: 02 Jan 2006 18 | timeFormat: 15:04 19 | dateTimeFormat: 02 Jan 2006 15:04:05 20 | location: Europe/Berlin 21 | 22 | # Configure the module flamingo-commerce-adapter-standalone 23 | flamingoCommerceAdapterStandalone: 24 | csvindexing: 25 | products: 26 | file: 27 | path: "resources/products/products_de.csv" 28 | delimiter: "," 29 | locale: "de_DE" 30 | currency: "EUR" -------------------------------------------------------------------------------- /graphql/schema/flamingo.me_flamingo-commerce_v3_price_interfaces_graphql-Service.graphql: -------------------------------------------------------------------------------- 1 | type Commerce_Price{ 2 | amount: Float 3 | currency: String! 4 | } 5 | 6 | type Commerce_Price_Charge { 7 | price: Commerce_Price! 8 | value: Commerce_Price! 9 | type: String! 10 | reference: String! 11 | } 12 | 13 | type Commerce_Price_ChargeQualifier { 14 | type: String! 15 | reference: String! 16 | } 17 | 18 | input Commerce_Price_ChargeQualifierInput { 19 | type: String! 20 | reference: String! 21 | } 22 | 23 | type Commerce_Price_Charges { 24 | items: [Commerce_Price_Charge!] 25 | hasType(ctype: String): Boolean 26 | hasChargeQualifier(qualifier: Commerce_Price_ChargeQualifierInput!): Boolean 27 | getByChargeQualifierForced(qualifier: Commerce_Price_ChargeQualifierInput!): Commerce_Price_Charge 28 | getByTypeForced(ctype: String): Commerce_Price_Charge 29 | } -------------------------------------------------------------------------------- /frontend/src/index.sass: -------------------------------------------------------------------------------- 1 | @import 'base/style/mdp-ecom-base/core/bootstrap/functions.sass' 2 | @import 'base/style/mdp-ecom-base/core/bootstrap/variables.sass' 3 | 4 | @import 'base/style/mdp-ecom-base/core/mixins.sass' 5 | @import 'base/style/mdp-ecom-base/core/colors.sass' 6 | @import 'base/style/mdp-ecom-base/core/variables.sass' 7 | @import 'base/style/mdp-ecom-base/core/global.sass' 8 | @import 'base/style/mdp-ecom-base/core/helpers.sass' 9 | @import 'base/style/mdp-ecom-base/core/typography.sass' 10 | @import 'base/style/mdp-ecom-base/core/masks.sass' 11 | @import 'base/style/mdp-ecom-base/core/waves.sass' 12 | 13 | @import 'base/style/mdp-ecom-base/free/*.sass' 14 | 15 | 16 | 17 | // Import all sass files via glob 18 | // sass-lint:disable clean-import-paths 19 | //@import 'atom/**/*.sass' 20 | //@import 'molecule/**/*.sass' 21 | @import 'organism/**/*.sass' 22 | @import 'template/**/*.sass' 23 | @import 'page/**/*.sass' 24 | // sass-lint:enable clean-import-paths -------------------------------------------------------------------------------- /frontend/src/page/checkout/checkout.pug: -------------------------------------------------------------------------------- 1 | extends /template/base/base 2 | include /organism/cart/cart 3 | 4 | block maincontent 5 | main.mt-5.pt-4 6 | div.container 7 | h2.my-5.h2.text-center Checkout 8 | if errorInfos 9 | if errorInfos.hasError 10 | if errorInfos.hasPaymentError 11 | div.alert.alert-error(role="alert") Payment Error 12 | div.alert.alert-warning(role="alert")=errorInfos.errorMessage 13 | div.row 14 | div.col-md-8.mb-4 15 | include /page/checkout/organism/checkoutform.pug 16 | div.col-md-4.mb-4 17 | if cartValidationResult 18 | if cartValidationResult.hasCommonError 19 | div.alert.alert-warning(role="alert")=cartValidationResult.commonErrorMessageKey 20 | each itemResult in cartValidationResult.itemResults 21 | div.alert.alert-warning(role="alert")=itemResult.errorMessageKey 22 | +cart(decoratedCart,cartValidationResult,false) 23 | 24 | -------------------------------------------------------------------------------- /frontend/src/template/base/molecule/categoryMenu/categoryMenu.pug: -------------------------------------------------------------------------------- 1 | ul.navbar-nav.mr-auto 2 | - var rootTreeNode = data("category.tree",{'code': ''}) 3 | li.nav-item.active 4 | a.nav-link.waves-effect(href='/') 5 | | Home 6 | span.sr-only (current) 7 | for treeNode in rootTreeNode.subTrees 8 | - var categoryUrl = url('category.view', {code: treeNode.code,name: treeNode.name}) 9 | if treeNode.hasChilds 10 | li.nav-item.dropdown 11 | a(href="#", id="navbarDropdown", role="button",data-toggle="dropdown", aria-haspopup="true", aria-expanded="false").nav-link.dropdown-toggle=treeNode.name 12 | div(aria-labelledby="navbarDropdown").dropdown-menu.waves-effect 13 | for subTreeNode in treeNode.subTrees 14 | - var categoryUrl = url('category.view', {code: subTreeNode.code,name: subTreeNode.name}) 15 | a.dropdown-item(href=categoryUrl)=subTreeNode.name 16 | else 17 | li.nav-item 18 | a(href=categoryUrl).nav-link=treeNode.name -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/core/_helpers.sass: -------------------------------------------------------------------------------- 1 | // Helpers 2 | // MDB helpers 3 | .img-fluid, 4 | .video-fluid 5 | max-width: 100% 6 | height: auto 7 | 8 | .flex-center 9 | display: flex 10 | justify-content: center 11 | align-items: center 12 | height: 100% 13 | 14 | p 15 | margin: 0 16 | 17 | ul 18 | text-align: center 19 | 20 | li 21 | margin-bottom: $flex-center-ul-mb 22 | 23 | &:last-of-type 24 | margin-bottom: 0 25 | 26 | .hr-light 27 | border-top: 1px solid $hr-light 28 | 29 | .hr-dark 30 | border-top: 1px solid $hr-dark 31 | 32 | // Responsive width 33 | .w-responsive 34 | width: 75% 35 | 36 | @media (max-width: 740px) 37 | width: 100% 38 | 39 | // Collapsible body 40 | .collapsible-body 41 | display: none 42 | 43 | .jumbotron 44 | box-shadow: $z-depth-1 45 | border-radius: $border-radius-base 46 | background-color: $white-base 47 | 48 | @each $name, $color in $basic-mdb-colors 49 | +bg-variant(".bg-#{$name}", $color) 50 | 51 | .border-#{$name} 52 | border-color: $color !important 53 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/free/_tables.sass: -------------------------------------------------------------------------------- 1 | // Tables 2 | table 3 | th 4 | font-size: $table-th-font-size 5 | font-weight: 400 6 | 7 | td 8 | font-size: $table-td-font-size 9 | font-weight: 300 10 | 11 | &.table 12 | thead th 13 | border-top: none 14 | 15 | th, 16 | td 17 | padding-top: $table-th-padding-top 18 | padding-bottom: $table-td-padding-bottom 19 | 20 | a 21 | margin: 0 22 | color: $table-a-color 23 | 24 | .label-table 25 | margin: 0 26 | padding: 0 27 | line-height: 15px 28 | height: 15px 29 | 30 | &.btn-table 31 | td 32 | vertical-align: middle 33 | 34 | &.table-hover 35 | tbody 36 | tr 37 | &:hover 38 | transition: $table-hover-transition 39 | background-color: $table-hover-background-color 40 | 41 | .th-lg 42 | min-width: 9rem 43 | 44 | .th-sm 45 | min-width: 6rem 46 | 47 | &.table-sm 48 | th, 49 | td 50 | padding-top: $table-sm-padding-y 51 | padding-bottom: $table-sm-padding-y 52 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flamingo-commerce-demo-theme", 3 | "version": "1.2.0", 4 | "main": "postcss.config.js", 5 | "scripts": { 6 | "build": "rm -rf dist && rm -rf .cache && npx fc build", 7 | "dev": "npx fc dev", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@babel/core": "^7.23.0", 14 | "@babel/preset-env": "^7.22.20", 15 | "autoprefixer": "^10.4.16", 16 | "fast-sass-loader": "^2.0.1", 17 | "flamingo-carotene-core": "^9.0.0-alpha.13", 18 | "flamingo-carotene-dev-server": "^9.0.0-alpha.13", 19 | "flamingo-carotene-postcss": "^8.1.0", 20 | "flamingo-carotene-pug": "^9.0.0-alpha.13", 21 | "flamingo-carotene-static-asset": "^9.0.0-alpha.13", 22 | "flamingo-carotene-webpack": "^9.0.0-alpha.13", 23 | "mqpacker": "^7.0.0", 24 | "node-sass-glob-importer": "^3.0.2", 25 | "postcss-object-fit-images": "^1.1.2", 26 | "postcss-plugin-px2rem": "^0.8.1" 27 | }, 28 | "devDependencies": { 29 | "sass": "^1.69.1", 30 | "sass-loader": "^13.3.2", 31 | "webpack": "^5.88.2" 32 | }, 33 | "description": "" 34 | } 35 | -------------------------------------------------------------------------------- /frontend/src/molecule/pagination/pagination.pug: -------------------------------------------------------------------------------- 1 | include /atom/debug/debug 2 | 3 | mixin pagination(paginationInfo) 4 | if paginationInfo && paginationInfo.totalHits && paginationInfo.totalHits > 0 5 | nav.d-flex.justify-content-center.wow.fadeIn 6 | ul.pagination.pg-blue 7 | if paginationInfo.previousPage 8 | li.page-item 9 | a.page-link(href=paginationInfo.previousPage.uRL, aria-label='Previous') 10 | span(aria-hidden='true') « 11 | span.sr-only Previous 12 | if paginationInfo.pageNavigation.length > 1 13 | each page in paginationInfo.pageNavigation 14 | if page.isSpacer 15 | li.page-item ... 16 | else 17 | if page.isActive 18 | li.page-item.active 19 | a.page-link(href=page.uRL)=page.page 20 | else 21 | li.page-item 22 | a.page-link(href=page.uRL)=page.page 23 | if paginationInfo.nextPage 24 | li.page-item 25 | a.page-link(href=paginationInfo.nextPage.uRL, aria-label='Next') 26 | span(aria-hidden='true') » 27 | span.sr-only Next 28 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/core/_global.sass: -------------------------------------------------------------------------------- 1 | // Globals 2 | // Shadows 3 | .z-depth-0 4 | box-shadow: none !important 5 | 6 | .z-depth-1 7 | box-shadow: $z-depth-1 8 | 9 | .z-depth-1-half 10 | box-shadow: $z-depth-1-half 11 | 12 | .z-depth-2 13 | box-shadow: $z-depth-2 14 | 15 | .z-depth-3 16 | box-shadow: $z-depth-3 17 | 18 | .z-depth-4 19 | box-shadow: $z-depth-4 20 | 21 | .z-depth-5 22 | box-shadow: $z-depth-5 23 | 24 | // Shadow on hover 25 | .hoverable 26 | box-shadow: none 27 | transition: $transition-hoverable 28 | 29 | &:hover 30 | box-shadow: $z-depth-2 31 | transition: $transition-hoverable 32 | 33 | // Disabled cursor 34 | .disabled, 35 | a:disabled 36 | pointer-events: none !important 37 | 38 | // Links 39 | a 40 | cursor: pointer 41 | text-decoration: none 42 | color: $link-color 43 | transition: $transition-basic 44 | 45 | &:hover 46 | transition: $transition-basic 47 | text-decoration: none 48 | 49 | &.disabled, 50 | &:disabled 51 | &:hover 52 | color: $link-color 53 | 54 | a:not([href]):not([tabindex]), a:not([href]):not([tabindex]):focus, a:not([href]):not([tabindex]):hover 55 | color: inherit 56 | text-decoration: none 57 | -------------------------------------------------------------------------------- /translations/src/en-gb.checkout.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "checkout.success_message1", 4 | "translation": "Your order has been received. Your order number is: {{.OrderId}}" 5 | }, 6 | 7 | { 8 | "id": "checkout.success_message2", 9 | "translation": "An confirmation email will be send to {{.Email}}." 10 | }, 11 | 12 | { 13 | "id": "checkout.cart_item_error_hint", 14 | "translation": "There are invalid items in your cart. Please check below and resolve the issue." 15 | }, 16 | 17 | { 18 | "id": "checkout.back_to_cart", 19 | "translation": "Back to cart" 20 | }, 21 | 22 | { 23 | "id": "checkout.no_items_in_cart", 24 | "translation": "No Items in your cart" 25 | }, 26 | 27 | { 28 | "id":"checkout.legalConfirmation.termsAndConditions", 29 | "translation": "Check here to indicate that you have read and agree to the privacy policies and terms and conditions of the Heathrow Boutique." 30 | }, 31 | 32 | { 33 | "id":"checkout.error.terms_and_conditions_required", 34 | "translation": "Please accept the terms and conditions." 35 | } 36 | ] 37 | -------------------------------------------------------------------------------- /frontend/src/atom/price/price.pug: -------------------------------------------------------------------------------- 1 | 2 | mixin price(product) 3 | case product.type() 4 | when 'simple' 5 | - var baseData = product.baseData 6 | - var saleableProductData = product.saleableData 7 | when 'configurable' 8 | - var baseData = product.baseData 9 | - var saleableProductData = false 10 | when 'configurable_with_activevariant' 11 | - var baseData = product.activeVariant.baseData 12 | - var saleableProductData = product.activeVariant.saleableData 13 | default 14 | - throw 'No proper productType given' 15 | 16 | if saleableProductData 17 | - var priceInfo = saleableProductData.activePrice 18 | if priceInfo.isDiscounted 19 | span.mr-1 20 | del=commercePriceFormat(priceInfo.default) 21 | span=commercePriceFormat(priceInfo.discounted) 22 | else 23 | span=commercePriceFormat(priceInfo.default) 24 | else 25 | span 26 | p Select a Variant to see the price 27 | 28 | mixin teaserPrice(product) 29 | - var priceInfo = product.teaser.teaserPrice 30 | if priceInfo.isDiscounted 31 | span.mr-1 32 | del=commercePriceFormat(priceInfo.default) 33 | span=commercePriceFormat(priceInfo.discounted) 34 | else 35 | span=commercePriceFormat(priceInfo.default) -------------------------------------------------------------------------------- /docs/docs.go: -------------------------------------------------------------------------------- 1 | // Package docs Code generated by swaggo/swag. DO NOT EDIT 2 | package docs 3 | 4 | import "github.com/swaggo/swag" 5 | 6 | const docTemplate = `{ 7 | "schemes": {{ marshal .Schemes }}, 8 | "swagger": "2.0", 9 | "info": { 10 | "description": "{{escape .Description}}", 11 | "title": "{{.Title}}", 12 | "contact": { 13 | "name": "Flamingo", 14 | "url": "https://gitter.im/i-love-flamingo/community#", 15 | "email": "flamingo@aoe.com" 16 | }, 17 | "license": { 18 | "name": "MIT" 19 | }, 20 | "version": "{{.Version}}" 21 | }, 22 | "host": "{{.Host}}", 23 | "basePath": "{{.BasePath}}", 24 | "paths": {} 25 | }` 26 | 27 | // SwaggerInfo holds exported Swagger Info so clients can modify it 28 | var SwaggerInfo = &swag.Spec{ 29 | Version: "1.0", 30 | Host: "", 31 | BasePath: "/en", 32 | Schemes: []string{}, 33 | Title: "Flamingo Commerce Demo Shop", 34 | Description: "", 35 | InfoInstanceName: "swagger", 36 | SwaggerTemplate: docTemplate, 37 | LeftDelim: "{{", 38 | RightDelim: "}}", 39 | } 40 | 41 | func init() { 42 | swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) 43 | } 44 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/core/_masks.sass: -------------------------------------------------------------------------------- 1 | // Masks 2 | // General properties 3 | .view 4 | position: relative 5 | overflow: hidden 6 | cursor: default 7 | 8 | .mask 9 | position: absolute 10 | top: 0 11 | overflow: hidden 12 | width: 100% 13 | height: 100% 14 | background-attachment: fixed 15 | 16 | img, video 17 | position: relative 18 | display: block 19 | 20 | video 21 | &.video-intro 22 | z-index: -100 23 | top: 50% 24 | left: 50% 25 | transform: $intro-video-transform 26 | transition: $intro-video-transition opacity 27 | min-width: 100% 28 | min-height: 100% 29 | width: auto 30 | height: auto 31 | 32 | // Overlay 33 | .overlay 34 | .mask 35 | opacity: 0 36 | transition: $mask-overlay-transition 37 | 38 | &:hover 39 | opacity: 1 40 | 41 | // Zoom 42 | .zoom 43 | img, video 44 | transition: $mask-zoom-transition 45 | 46 | &:hover 47 | img, video 48 | transform: $mask-zoom-transform 49 | 50 | // Patterns 51 | $patterns: (1: "01", 2: "02", 3: "03", 4: "04", 5: "05", 6: "06", 7: "07", 8: "08", 9: "09") 52 | 53 | @each $no, $filename in $patterns 54 | .pattern-#{$no} 55 | background: url("#{$image-path}/overlays/#{$filename}.png") 56 | -------------------------------------------------------------------------------- /translations/Readme.md: -------------------------------------------------------------------------------- 1 | # Translation structure: 2 | 3 | * src: 4 | * This is the folder where developer add the labels and a best guess for the translation. 5 | * Files should be splitted nicely (e.g. per module) - so that we can also reuse them over projects 6 | 7 | * merged: 8 | * This contains the "src/*.json" files merged to *.all.yaml and *.untranslated.yaml 9 | * The complete folder can be given to external translation 10 | * The files here are build on build time 11 | * Local you can run `./preparetranslations.sh` (requires *goi18n*) 12 | 13 | 14 | * translated: 15 | * This contains the files that came back from external translation. (They are loaded after "merged") 16 | 17 | # Troubleshooting 18 | * `./preparetranslations.sh: line 4: goi18n: command not found` 19 | 20 | __Solution__: Install *goi18n* by executing `go get -u github.com/nicksnyder/go-i18n/goi18n` 21 | 22 | * If `go get -u github.com/nicksnyder/go-i18n/goi18n` results in following error: 23 | 24 | `package github.com/nicksnyder/go-i18n/goi18n: directory "/Users/patrick.schaper/.virtualgo/flamingo/src/github.com/nicksnyder/go-i18n/goi18n" is not using a known version control system` 25 | 26 | __Solution__: `rm -rf PATH_TO/.virtualgo/flamingo/src/github.com/nicksnyder/go-i18n/` and retry installation of *goi18n* 27 | 28 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/free/_carousels.sass: -------------------------------------------------------------------------------- 1 | // Carousels 2 | .carousel 3 | .carousel-control-prev-icon, 4 | .carousel-control-next-icon 5 | width: $carousel-control-icon-width 6 | height: $carousel-control-icon-height 7 | 8 | .carousel-control-prev-icon 9 | background-image: $carousel-control-prev-icon 10 | 11 | .carousel-control-next-icon 12 | background-image: $carousel-control-next-icon 13 | 14 | .carousel-indicators 15 | li 16 | width: $carousel-indicators-width 17 | height: $carousel-indicators-height 18 | border-radius: $carousel-indicators-border-radius 19 | cursor: pointer 20 | 21 | .carousel-fade 22 | .carousel-item 23 | opacity: 0 24 | transition-duration: $carousel-transition-duration 25 | transition-property: opacity 26 | 27 | .carousel-item.active, 28 | .carousel-item-next.carousel-item-left, 29 | .carousel-item-prev.carousel-item-right 30 | opacity: 1 31 | 32 | .carousel-item-left, 33 | .carousel-item-right 34 | &.active 35 | opacity: 0 36 | 37 | .carousel-item-next, 38 | .carousel-item-prev, 39 | .carousel-item.active, 40 | .carousel-item-left.active, 41 | .carousel-item-prev.active 42 | transform: $carousel-item-transform 43 | 44 | @supports (transform-style: preserve-3d) 45 | transform: $carousel-item-transform-2 46 | -------------------------------------------------------------------------------- /frontend/src/organism/productList/productList.pug: -------------------------------------------------------------------------------- 1 | include /molecule/productMedia/productMedia 2 | include /molecule/pagination/pagination 3 | include /atom/price/price 4 | include /atom/debug/debug 5 | 6 | mixin productList(products, paginationInfo) 7 | //+debug(productSearchResult) 8 | .row.wow.fadeIn.productList 9 | // Grid column 10 | each product in products 11 | //+debug(product) 12 | .col-lg-3.col-md-6.mb-4 13 | // Card 14 | .card.product-card 15 | // Card image 16 | .view.overlay 17 | +productMedia(product.baseData.getListMedia,"200x").product-image 18 | a(href=getProductUrl(product)) 19 | .mask.rgba-white-slight 20 | // Card image 21 | // Card content 22 | .card-body.text-center 23 | // Category & Title 24 | a.grey-text(href=getProductUrl(product)) 25 | h5=product.baseData.title 26 | h5 27 | strong 28 | a.dark-grey-text(href=getProductUrl(product)) 29 | span.badge.badge-pill.danger-color NEW 30 | span.badge.badge-pill.primary-color=product.type() 31 | h4.font-weight-bold.blue-text 32 | +teaserPrice(product) 33 | +pagination(paginationInfo) 34 | 35 | 36 | mixin productListByProductSearchResult(productSearchResult) 37 | +productList(productSearchResult.products, productSearchResult.paginationInfo) -------------------------------------------------------------------------------- /frontend/src/molecule/productTile/productTile.sass: -------------------------------------------------------------------------------- 1 | $productTileBorderRadius: 6px 2 | 3 | .productTile 4 | +hover 5 | &::before 6 | box-shadow: 1px 1px 7px 0 $colorBlackShadowLight2 7 | 8 | text-align: center 9 | position: relative 10 | display: flex 11 | justify-content: flex-start 12 | flex-direction: column 13 | flex-wrap: nowrap 14 | padding: 5px 15 | 16 | &::before 17 | content: '' 18 | position: absolute 19 | width: 100% 20 | height: 100% 21 | background-color: $colorWhite 22 | border-radius: $productTileBorderRadius 23 | transition: box-shadow .3s ease-out 24 | top: 0 25 | left: 0 26 | 27 | > * 28 | z-index: 1 29 | 30 | .productTileFigure 31 | margin-bottom: 5px 32 | position: relative 33 | display: block 34 | border-radius: $productTileBorderRadius 35 | 36 | &::before 37 | content: '' 38 | display: block 39 | position: relative 40 | padding-top: 100% 41 | 42 | 43 | .productTileImage 44 | position: absolute 45 | left: 0 46 | top: 0 47 | width: 100% 48 | height: 100% 49 | object-fit: contain 50 | border-radius: $productTileBorderRadius 51 | 52 | .productTileBrand 53 | margin-bottom: 5px 54 | font-size: 12px 55 | line-height: 22px 56 | flex-shrink: 0 57 | font-weight: bold 58 | 59 | .productTileTitle 60 | margin-bottom: 20px 61 | font-size: 14px 62 | line-height: 22px 63 | flex-shrink: 0 64 | 65 | .productTilePrice 66 | margin-top: auto 67 | margin-bottom: 5px 68 | -------------------------------------------------------------------------------- /frontend/src/asset/img/lightbox/default-skin.svg: -------------------------------------------------------------------------------- 1 | default-skin 2 -------------------------------------------------------------------------------- /frontend/src/page/category/category.pug: -------------------------------------------------------------------------------- 1 | extends /template/base/base 2 | 3 | include /organism/productList/productList 4 | 5 | block maincontent 6 | main.mt-5.p-4.dark-grey-text.category 7 | h2.mt-4.mb-4.h2.text-center=category.name 8 | .row 9 | nav.col-md-3.order-md-first 10 | //+debug(categoryTree) 11 | if categoryTree.subTrees 12 | button.d-block.d-md-none.btn.btn-primary.btn-block.mb-3(type="button" data-toggle="collapse" data-target="#filters") Subcategories ▾ 13 | div.collapse.d-md-block(id="filters") 14 | ul.navbar-nav.mr-auto 15 | for treeNode in categoryTree.subTrees 16 | - var className= "" 17 | if treeNode.active 18 | - var className= "active" 19 | - var categoryUrl = url('category.view', {code: treeNode.code,name: treeNode.name}) 20 | //- level 1 21 | li 22 | a(href=url("category.view",{code:treeNode.code, name:treeNode.name}) class=className)=treeNode.name 23 | if treeNode.hasChilds 24 | ul 25 | for subTreeNode in treeNode.subTrees 26 | - var className= "" 27 | if treeNode.active 28 | - var className= "active" 29 | //- level 2 30 | li 31 | - var categoryUrl = url('category.view', {code: subTreeNode.code,name: subTreeNode.name}) 32 | a.level2-item(href=categoryUrl class=className)=subTreeNode.name 33 | div.col-md-9.order-md-last(id="") 34 | +productList(productSearchResult.products, productSearchResult.paginationInfo) 35 | //+debug(productSearchResult) 36 | //+debug(categoryTree) -------------------------------------------------------------------------------- /graphql/schema/flamingo.me_flamingo-commerce_v3_category_interfaces_graphql-Service.graphql: -------------------------------------------------------------------------------- 1 | type Commerce_Category_Attributes { 2 | get(code: String!): Commerce_Category_Attribute 3 | has(code: String!): Boolean 4 | all: [Commerce_Category_Attribute!] 5 | } 6 | 7 | type Commerce_Category_Attribute { 8 | code: String! 9 | label: String! 10 | values: [Commerce_Category_AttributeValue!] 11 | } 12 | 13 | type Commerce_Category_AttributeValue { 14 | value: String! 15 | label: String! 16 | } 17 | 18 | interface Commerce_Category { 19 | code: String! 20 | name: String! 21 | path: String! 22 | active: Boolean! 23 | promoted: Boolean! 24 | attributes: Commerce_Category_Attributes! 25 | } 26 | 27 | type Commerce_CategoryData implements Commerce_Category { 28 | code: String! 29 | name: String! 30 | path: String! 31 | active: Boolean! 32 | promoted: Boolean! 33 | attributes: Commerce_Category_Attributes! 34 | } 35 | 36 | interface Commerce_Tree { 37 | code: String! 38 | name: String! 39 | path: String! 40 | active: Boolean! 41 | subTrees: [Commerce_Tree] 42 | hasChilds: Boolean! 43 | documentCount: Int! 44 | } 45 | 46 | type Commerce_CategoryTree implements Commerce_Tree{ 47 | code: String! 48 | name: String! 49 | path: String! 50 | active: Boolean! 51 | subTrees: [Commerce_Tree] 52 | hasChilds: Boolean! 53 | documentCount: Int! 54 | } 55 | 56 | type Commerce_Category_SearchResult { 57 | category: Commerce_Category! 58 | productSearchResult: Commerce_Product_SearchResult! 59 | } 60 | 61 | extend type Query { 62 | Commerce_CategoryTree(activeCategoryCode: String!): Commerce_Tree! 63 | Commerce_Category(categoryCode: String!, categorySearchRequest: Commerce_Search_Request): Commerce_Category_SearchResult 64 | } 65 | -------------------------------------------------------------------------------- /frontend/src/page/home/home.pug: -------------------------------------------------------------------------------- 1 | extends /template/base/base 2 | 3 | include /organism/productList/productList 4 | 5 | block precontent 6 | include /page/home/molecule/carousel/carousel 7 | 8 | block maincontent 9 | main 10 | .container 11 | // Sub-Navbar for findProducts (TODO) 12 | //nav.navbar.navbar-expand-lg.navbar-dark.mdb-color.lighten-3.mt-3.mb-5 13 | // Navbar brand 14 | span.navbar-brand Categories: 15 | // Collapse button 16 | button.navbar-toggler(type='button', data-toggle='collapse', data-target='#basicExampleNav', aria-controls='basicExampleNav', aria-expanded='false', aria-label='Toggle navigation') 17 | span.navbar-toggler-icon 18 | // Collapsible content 19 | #basicExampleNav.collapse.navbar-collapse 20 | // Links 21 | ul.navbar-nav.mr-auto 22 | li.nav-item.active 23 | a.nav-link(href='#') 24 | | All 25 | span.sr-only (current) 26 | li.nav-item 27 | a.nav-link(href='#') Shirts 28 | li.nav-item 29 | a.nav-link(href='#') Sport wears 30 | li.nav-item 31 | a.nav-link(href='#') Outwears 32 | // Links 33 | form.form-inline 34 | .md-form.my-0 35 | input.form-control.mr-sm-2(type='text', placeholder='Search', aria-label='Search') 36 | // Collapsible content 37 | // /.Navbar 38 | // Section: Products v.3 39 | section.text-center.mb-4 40 | // Grid row 41 | //+productListByProductSearchResult(findProducts("homepagewidget",{"query":"","pageSize": "10","sortDirection":"A","sortBy":'name'},{"categories":['laptops']})) 42 | +productListByProductSearchResult(findProducts("homepagewidget",{"query":"","pageSize": "8","sortDirection":"A","sortBy":'name'},{})) -------------------------------------------------------------------------------- /frontend/src/template/base/molecule/footer/footer.pug: -------------------------------------------------------------------------------- 1 | footer.page-footer.text-center.font-small.mt-4.wow.fadeIn 2 | // /.Call to action 3 | hr.my-4 4 | // Social icons 5 | .pb-4 6 | a(href='https://twitter.com/aoepeople', target='_blank') 7 | i.fa.fa-twitter.mr-3 8 | a(href='https://www.youtube.com/watch?v=7MUISDJ5ZZ4', target='_blank') 9 | i.fa.fa-youtube.mr-3 10 | a(href='https://github.com/i-love-flamingo', target='_blank') 11 | i.fa.fa-github.mr-3 12 | // Social icons 13 | // Copyright 14 | .footer-copyright.py-3 15 | | © 2018 Copyright: 16 | a(href='https://mdbootstrap.com/bootstrap-tutorial/', target='_blank') Template based on MDBootstrap.com 17 | | © 2018 Copyright: 18 | a(href='https://flamingo.me/', target='_blank') Flamingo by AOE 19 | // /.Copyright 20 | // /.Footer 21 | // SCRIPTS 22 | // JQuery 23 | link(rel="stylesheet", href=asset("asset/css/bootstrap.min.css")) 24 | 25 | 26 | script(type='text/javascript', src=asset("asset/js/jquery-3.3.1.min.js")) 27 | // Bootstrap tooltips 28 | script(type='text/javascript', src=asset("asset/js/popper.min.js")) 29 | // Bootstrap core JavaScript 30 | script(type='text/javascript', src=asset("asset/js/bootstrap.min.js")) 31 | // MDB core JavaScript 32 | script(type='text/javascript', src=asset("asset/js/mdb.min.js")) 33 | // Initializations 34 | script(type='text/javascript'). 35 | // Animations initialization 36 | new WOW().init(); 37 | block js-application 38 | //script(src=asset("js/app.js")) 39 | script(src=asset("js/main.js")) 40 | // 41 | script(async src="https://www.googletagmanager.com/gtag/js?id=UA-129655449-1") 42 | script. 43 | window.dataLayer = window.dataLayer || []; 44 | function gtag() { 45 | dataLayer.push(arguments); 46 | } 47 | gtag('js', new Date()); 48 | 49 | gtag('config', 'UA-129655449-1'); -------------------------------------------------------------------------------- /graphql/module.go: -------------------------------------------------------------------------------- 1 | // Code generated by flamingo.me/graphql, DO NOT EDIT. 2 | //go:build !graphql 3 | // +build !graphql 4 | 5 | package graphql 6 | 7 | import ( 8 | "context" 9 | "encoding/json" 10 | "log" 11 | "reflect" 12 | 13 | "flamingo.me/dingo" 14 | "github.com/99designs/gqlgen/graphql" 15 | "github.com/spf13/cobra" 16 | ) 17 | 18 | // Module is an autogenerated dingo Module to bind the root resolver 19 | type Module struct{} 20 | 21 | // Configure sets the graphql.ExecutableSchema binding via a provider, passing in the correct root resolver 22 | func (*Module) Configure(injector *dingo.Injector) { 23 | injector.Bind(new(graphql.ExecutableSchema)).ToProvider(func(root *rootResolver) graphql.ExecutableSchema { 24 | return NewExecutableSchema(Config{Resolvers: root, Directives: root.directives()}) 25 | }) 26 | 27 | injector.BindMulti(new(cobra.Command)).ToProvider(func(root *rootResolver) *cobra.Command { 28 | return &cobra.Command{ 29 | Use: "gql calls a gql function like 'go run main.go gql User.Todos '{\"Name\":\"User a\"}' ", 30 | Run: func(cmd *cobra.Command, args []string) { 31 | if len(args) == 0 { 32 | for k := range direct(root) { 33 | log.Println(k) 34 | } 35 | return 36 | } else if len(args) == 1 { 37 | v := reflect.ValueOf(direct(root)[args[0]]) 38 | log.Printf("%s", v.Type().String()) 39 | return 40 | } 41 | 42 | v := reflect.ValueOf(direct(root)[args[0]]) 43 | in := make([]reflect.Value, v.Type().NumIn()-1) 44 | for i := 1; i < v.Type().NumIn(); i++ { 45 | in[i-1] = reflect.New(v.Type().In(i)) 46 | log.Println(json.Unmarshal([]byte(args[i]), in[i-1].Interface())) 47 | in[i-1] = in[i-1].Elem() 48 | } 49 | res := v.Call(append([]reflect.Value{reflect.ValueOf(context.Background())}, in...)) 50 | for _, r := range res { 51 | v, _ := json.Marshal(r.Interface()) 52 | log.Print(string(v)) 53 | } 54 | }, 55 | } 56 | }) 57 | } 58 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/free/_pagination.sass: -------------------------------------------------------------------------------- 1 | // Pagination 2 | .pagination 3 | .page-item 4 | &.active 5 | .page-link 6 | box-shadow: $z-depth-1 7 | transition: $pagination-active-transition 8 | border-radius: $border-radius-base 9 | background-color: $primary-color 10 | color: $white-base 11 | 12 | &:hover 13 | background-color: $primary-color 14 | 15 | &.disabled 16 | .page-link 17 | color: $pagination-page-item-disabled-color 18 | 19 | .page-link 20 | transition: $pagination-page-link-transition 21 | outline: 0 22 | border: 0 23 | background-color: transparent 24 | font-size: $pagination-page-link-font-size 25 | color: $pagination-page-link-color 26 | 27 | &:hover 28 | transition: $pagination-page-link-transition 29 | border-radius: $border-radius-base 30 | background-color: $pagination-page-link-hover-bg-color 31 | 32 | &:focus 33 | background-color: transparent 34 | 35 | &.pagination-lg 36 | .page-item 37 | .page-link 38 | font-size: $pagination-page-link-font-size-lg 39 | 40 | &.pagination-sm 41 | .page-item 42 | .page-link 43 | font-size: $pagination-page-link-font-size-sm 44 | 45 | &.pagination-circle 46 | .page-item 47 | .page-link 48 | margin-left: $pagination-circle-margin-x 49 | margin-right: $pagination-circle-margin-x 50 | border-radius: $pagination-circle-border-radius 51 | 52 | &:hover 53 | border-radius: $pagination-circle-border-radius 54 | 55 | &.active 56 | .page-link 57 | border-radius: $pagination-circle-border-radius 58 | 59 | @each $name, $color in $pagination-colors 60 | &.pg-#{$name} 61 | .page-item 62 | &.active 63 | .page-link 64 | background-color: $color 65 | 66 | &:hover 67 | background-color: $color 68 | -------------------------------------------------------------------------------- /frontend/src/page/search/products.pug: -------------------------------------------------------------------------------- 1 | extends /template/base/base 2 | 3 | include /organism/productList/productList 4 | include /atom/debug/debug 5 | 6 | mixin catTreeItems(facetItems, queryS) 7 | each facetItem in facetItems 8 | li 9 | - 10 | urlValues = {type: "products", q: queryS} 11 | urlValues["category"] = facetItem.value 12 | 13 | a(href=url('search.search', urlValues)) #{facetItem.label} (#{facetItem.count}) 14 | if facetItem.items 15 | ul 16 | +catTreeItems(facetItem.items, queryS) 17 | 18 | block maincontent 19 | main.mt-5.p-4.dark-grey-text.category 20 | h2.mt-4.mb-4.h2.text-center Search result 21 | p.text-center #{searchMeta.numResults} hits for your search for 22 | i "#{searchMeta.query}" 23 | .row 24 | nav.col-md-3.order-md-first 25 | button.d-block.d-md-none.btn.btn-primary.btn-block.mb-3(type="button" data-toggle="collapse" data-target="#filters") Filters ▾ 26 | div.collapse.d-md-block(id="filters") 27 | if searchResult["products"].facets["category"] 28 | h2=__("facet.header.category").setDefaultLabel("Category") 29 | ul 30 | +catTreeItems(searchResult["products"].facets["category"].items,searchMeta.query) 31 | each facet, facetKey in searchResult["products"].facets 32 | if facetKey == "category" 33 | else 34 | h2=__("facet.header."+facetKey).setDefaultLabel(capitalize(facetKey)) 35 | if facet.items 36 | ul 37 | each facetItem in facet.items 38 | - 39 | addUrlParam = {} 40 | addUrlParam[facetKey] = facetItem.value 41 | li 42 | a(href=url('', addUrlParam)) #{capitalize(facetItem.label)} (#{facetItem.count}) 43 | 44 | div.col-md-9.order-md-last(id="") 45 | +productList(searchResult["products"].hits, searchResult["products"].paginationInfo) 46 | //+debug(productSearchResult) 47 | //+debug(categoryTree) -------------------------------------------------------------------------------- /frontend/src/organism/cart/cart.pug: -------------------------------------------------------------------------------- 1 | include /molecule/productMedia/productMedia 2 | include /atom/price/price 3 | include /atom/debug/debug 4 | include /molecule/productMedia/productMedia 5 | 6 | mixin cart(decoratedCart,cartValidationResult, showActions) 7 | 8 | if decoratedCart.cart.isEmpty 9 | h4=__("emptycart").setDefaultLabel("Your cart is empty") 10 | else 11 | if cartValidationResult 12 | if cartValidationResult.isValid === false 13 | .error 14 | if cartValidationResult.hasCommonError 15 | p(data-alert)= __(cartValidationResult.commonErrorMessageKey) 16 | else 17 | p(data-alert)= __('checkout.cart_item_error_hint').setDefaultLabel() 18 | 19 | 20 | 21 | each decoratedDelivery in decoratedCart.decoratedDeliveries 22 | if decoratedDelivery.delivery.hasItems 23 | h4(data-deliverycode=decoratedDelivery.delivery.deliveryInfo.code).d-flex.justify-content-between.align-items-center.mb-3 24 | span.text-muted=__(decoratedDelivery.delivery.deliveryInfo.code) 25 | ul.list-group.mb-3.z-depth-1 26 | each decoratedItem in decoratedDelivery.decoratedItems 27 | li.list-group-item.d-flex.justify-content-between.lh-condensed 28 | div 29 | h6.my-0.mb-1 30 | +productMedia(decoratedItem.product.getListMedia, '40x')(height="30px").mr-3 31 | a(href=getProductUrl(decoratedItem.product))=decoratedItem.item.productName 32 | small.text-muted=truncate(decoratedItem.product.baseData.shortDescription,80) 33 | if showActions 34 | small.text-muted 35 | a(href=url('cart.deleteItem', {id: decoratedItem.item.iD,deliveryCode:decoratedDelivery.delivery.deliveryInfo.code})) [delete] 36 | span.text-muted=commercePriceFormat(decoratedItem.item.rowPriceGrossWithDiscount) 37 | li.list-group-item.d-flex.justify-content-between 38 | span Sum: 39 | strong=commercePriceFormat(decoratedDelivery.delivery.subTotalGrossWithDiscounts) 40 | if !decoratedCart.cart.sumTotalTaxAmount.isZero 41 | div.text-right Included Tax: 42 | strong=commercePriceFormat(decoratedCart.cart.sumTotalTaxAmount) 43 | div.text-right Total: 44 | strong=commercePriceFormat(decoratedCart.cart.grandTotal) -------------------------------------------------------------------------------- /graphql/schema/flamingo.me_flamingo-commerce_v3_customer_interfaces_graphql-Service.graphql: -------------------------------------------------------------------------------- 1 | type Commerce_Customer_Status_Result { 2 | isLoggedIn: Boolean! 3 | userID: String! 4 | } 5 | 6 | type Commerce_Customer_Result { 7 | id: String! 8 | "Customers personal data" 9 | personalData: Commerce_Customer_PersonData! 10 | "Get a specific address from the customer" 11 | getAddress(id: ID!): Commerce_Customer_Address 12 | "Addresses that the customer provided, can be used for billing / shipping" 13 | addresses: [Commerce_Customer_Address!] 14 | "The default shipping address of the customer, null if there is none" 15 | defaultShippingAddress: Commerce_Customer_Address 16 | "The default billing address of the customer, null if there is none" 17 | defaultBillingAddress: Commerce_Customer_Address 18 | } 19 | 20 | type Commerce_Customer_PersonData { 21 | gender: String! 22 | firstName: String! 23 | lastName: String! 24 | middleName: String! 25 | mainEmail: String! 26 | prefix: String! 27 | birthday: Date 28 | nationality: String! 29 | } 30 | 31 | type Commerce_Customer_Address { 32 | id: ID! 33 | additionalAddressLines: [String!] 34 | city: String! 35 | company: String! 36 | countryCode: String! 37 | "Flag if this address should be used as the default billing address" 38 | defaultBilling: Boolean! 39 | "Flag if this address should be used as the default shipping address" 40 | defaultShipping: Boolean! 41 | firstName: String! 42 | lastName: String! 43 | postCode: String! 44 | prefix: String! 45 | regionCode: String! 46 | street: String! 47 | streetNumber: String! 48 | state: String! 49 | telephone: String! 50 | email: String! 51 | } 52 | 53 | extend type Query { 54 | """ 55 | Returns the logged in status for the current session 56 | """ 57 | Commerce_Customer_Status: Commerce_Customer_Status_Result 58 | """ 59 | Returns the logged in customer for the current session or an error if it is not logged in. 60 | If you don't want to handle the error, check with Commerce_Customer_Status first. 61 | """ 62 | Commerce_Customer: Commerce_Customer_Result 63 | } 64 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/free/_navbars.sass: -------------------------------------------------------------------------------- 1 | // Navbars 2 | .navbar 3 | box-shadow: $z-depth-1 4 | font-weight: $navbar-font-weight 5 | 6 | form 7 | .md-form 8 | input 9 | margin: 0 $navbar-form-input-mr $navbar-form-input-mb $navbar-form-input-ml 10 | 11 | .breadcrumb 12 | margin: 0 13 | padding: $navbar-breadcrumb-padding-top 0 0 $navbar-breadcrumb-padding-left 14 | background-color: inherit 15 | font-size: $navbar-double-font-size 16 | font-weight: $navbar-font-weight 17 | 18 | .breadcrumb-item 19 | color: $white-base 20 | 21 | &.active 22 | color: $navbar-breadcrumb-color 23 | 24 | &:before 25 | color: $navbar-breadcrumb-color 26 | 27 | .navbar-toggler 28 | outline: 0 29 | border-width: 0 30 | 31 | .nav-flex-icons 32 | flex-direction: row 33 | 34 | .container 35 | @media (max-width: $medium-screen) 36 | width: 100% 37 | 38 | .navbar-toggler-right 39 | right: 0 40 | 41 | .nav-item 42 | .nav-link 43 | display: block 44 | 45 | &.disabled 46 | &:active 47 | pointer-events: none 48 | 49 | .fa 50 | padding-right: $navbar-flex-icons-padding-lg 51 | padding-left: $navbar-flex-icons-padding-lg 52 | 53 | @media (max-width: $medium-screen) 54 | padding-right: $navbar-flex-icons-padding-md 55 | padding-left: $navbar-flex-icons-padding-md 56 | 57 | .dropdown-menu 58 | position: absolute !important 59 | margin-top: 0 60 | z-index: 5 61 | 62 | a 63 | padding: $navbar-dropdown-menu-padding 64 | font-size: $navbar-dropdown-font-size 65 | font-weight: $navbar-font-weight 66 | color: $black !important 67 | 68 | &.navbar-light 69 | +make-navbar($navbar-light-disabled-color, $navbar-light-toggler-icon, $black, $navbar-light-hover-color, $navbar-light-bg-active-color) 70 | 71 | &.navbar-dark 72 | +make-navbar($navbar-dark-disabled-color, $navbar-dark-toggler-icon, $white, $navbar-dark-hover-color, $navbar-dark-bg-active-color) 73 | 74 | &.scrolling-navbar 75 | @media (min-width: $small-screen) 76 | transition: $navbar-scrolling-transition 77 | padding-top: $navbar-scrolling-padding 78 | padding-bottom: $navbar-scrolling-padding 79 | 80 | .navbar-nav > li 81 | transition-duration: $navbar-scrolling-transition-duration 82 | 83 | &.top-nav-collapse 84 | padding-top: $navbar-top-collapse-padding 85 | padding-bottom: $navbar-top-collapse-padding 86 | -------------------------------------------------------------------------------- /frontend/src/template/base/base.pug: -------------------------------------------------------------------------------- 1 | if config('debug.mode') 2 | include /atom/debug/debug 3 | include /atom/console/console 4 | 5 | doctype html 6 | html(lang='en') 7 | block head 8 | include /template/base/molecule/head/head 9 | body 10 | // Navbar 11 | nav.navbar.fixed-top.navbar-expand-lg.navbar-light.white.scrolling-navbar 12 | .container 13 | // Brand 14 | a.navbar-brand.waves-effect(href='/') 15 | img.img-fluid(src=asset("asset/img/flamingo-logo-black.png") style="max-height:30px") 16 | strong.ml-2 demoshop 17 | // Collapse 18 | button.navbar-toggler(type='button', data-toggle='collapse', data-target='#navbarSupportedContent', aria-controls='navbarSupportedContent', aria-expanded='false', aria-label='Toggle navigation') 19 | span.navbar-toggler-icon 20 | // Links 21 | #navbarSupportedContent.collapse.navbar-collapse 22 | // Left 23 | include /template/base/molecule/categoryMenu/categoryMenu 24 | form(class="form-inline my-2 my-lg-0" action=url('search.search', {type: "products"})) 25 | if searchMeta 26 | input(class="form-control mr-sm-2" type="search" name="q" placeholder="Search" aria-label="Search" value=searchMeta.query) 27 | else 28 | input(class="form-control mr-sm-2" type="search" name="q" placeholder="Search" aria-label="Search") 29 | button(class="btn btn-dark btn-sm" type="submit") Search 30 | // Right 31 | ul.navbar-nav.nav-flex-icons 32 | li.nav-item 33 | a.nav-link.waves-effect(href=url('cart.view')) 34 | - 35 | var miniCart = getCart() 36 | var currentCount = miniCart.getCartTeaser.itemCount 37 | span.badge.red.z-depth-1.mr-1=currentCount 38 | i.fa.fa-shopping-cart 39 | span.clearfix.d-none.d-sm-inline-block Cart 40 | //li.nav-item 41 | a.nav-link.waves-effect(href='https://twitter.com/aoepeople', target='_blank') 42 | i.fa.fa-twitter 43 | //li.nav-item 44 | a.nav-link.border.border-light.rounded.waves-effect(href='https://github.com/i-love-flamingo', target='_blank') 45 | i.fa.fa-github.mr-2 46 | | GitHub 47 | // Navbar 48 | // Carousel Wrapper 49 | block precontent 50 | block maincontent 51 | main.mt-5.pt-4 52 | block content 53 | 54 | // Pagination 55 | // Main layout 56 | // Footer 57 | include /template/base/molecule/footer/footer 58 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CONTEXT?=dev:testproducts 2 | REPLACE?=-replace flamingo.me/flamingo/v3=../flamingo -replace flamingo.me/flamingo-commerce/v3=../flamingo-commerce -replace flamingo.me/flamingo-commerce-adapter-standalone=../flamingo-commerce-adapter-standalone -replace flamingo.me/flamingo-commerce-adapter-magento2=../flamingo-commerce-adapter-magento2 -replace flamingo.me/form=../form 3 | DROPREPLACE?=-dropreplace flamingo.me/flamingo/v3 -dropreplace flamingo.me/flamingo-commerce/v3 -dropreplace flamingo.me/flamingo-commerce-adapter-standalone -dropreplace flamingo.me/flamingo-commerce-adapter-magento2 -dropreplace flamingo.me/form 4 | 5 | .PHONY: prepare-product-data download-product-data build serve serve-jaeger jaeger-docker local unlocal frontend frontend-build translation update dockerpublish 6 | 7 | prepare-product-data: 8 | cd resources && zip -r products.zip products 9 | 10 | download-product-data: 11 | cd resources && wget https://github.com/i-love-flamingo/commerce-demo-carotene/releases/download/productdata1/products.zip && unzip products.zip 12 | 13 | build: 14 | go build main.go 15 | 16 | serve: 17 | DEBUG=1 CONTEXT=$(CONTEXT) go run main.go serve 18 | 19 | serve-jaeger: translation 20 | DEBUG=1 CONTEXT=$(CONTEXT) go run main.go --flamingo-config 'opencensus.jaeger.enable: true' serve 21 | 22 | jaeger-docker: 23 | docker run -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 -p 5775:5775/udp -p 6831:6831/udp -p 6832:6832/udp -p 5778:5778 -p 16686:16686 -p 14268:14268 -p 9411:9411 jaegertracing/all-in-one:latest 24 | 25 | frontend: frontend-build 26 | bash -c 'cd frontend && npm run dev' 27 | 28 | frontend-build: 29 | bash -c 'cd frontend && npm ci && npm run build' 30 | 31 | translation: 32 | ./preparetranslations.sh 33 | 34 | local: 35 | git config filter.gomod-commercedemo-flamingo.smudge 'go mod edit -fmt -print $(REPLACE) /dev/stdin' 36 | git config filter.gomod-commercedemo-flamingo.clean 'go mod edit -fmt -print $(DROPREPLACE) /dev/stdin' 37 | git config filter.gomod-commercedemo-flamingo.required true 38 | go mod edit -fmt $(REPLACE) 39 | 40 | unlocal: 41 | git config filter.gomod-commercedemo-flamingo.smudge '' 42 | git config filter.gomod-commercedemo-flamingo.clean '' 43 | git config filter.gomod-commercedemo-flamingo.required false 44 | go mod edit -fmt $(DROPREPLACE) 45 | 46 | update: 47 | go get -u flamingo.me/flamingo/v3 flamingo.me/flamingo-commerce/v3@v3 48 | 49 | dockerpublish: 50 | GOOS=linux go build -o flamingo-commerce-demo-carotene main.go 51 | docker build --no-cache -t iloveflamingo/flamingo-commerce-demo-carotene . 52 | docker push iloveflamingo/flamingo-commerce-demo-carotene:latest 53 | 54 | generate-graphql: 55 | go generate -------------------------------------------------------------------------------- /translations/src/en-gb.cart.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "delivery", 4 | "translation": "Home delivery" 5 | }, 6 | { 7 | "id": "pickup_store", 8 | "translation": "Instore pickup" 9 | }, 10 | { 11 | "id": "cart.group.title", 12 | "translation": "products" 13 | }, 14 | 15 | { 16 | "id": "cart.column.quantity", 17 | "translation": "Quantity" 18 | }, 19 | 20 | { 21 | "id": "cart.column.price", 22 | "translation": "Price" 23 | }, 24 | 25 | { 26 | "id": "cart.column.sum", 27 | "translation": "Sum" 28 | }, 29 | 30 | { 31 | "id": "cart.item.detail", 32 | "translation": "SKU: {{ .SKU }}" 33 | }, 34 | 35 | { 36 | "id": "cart.item.remove", 37 | "translation": "remove item" 38 | }, 39 | 40 | { 41 | "id": "cart.loyalty.label", 42 | "translation": "Heathrow Reward points" 43 | }, 44 | 45 | { 46 | "id": "cart.total.label", 47 | "translation": "Total" 48 | }, 49 | 50 | { 51 | "id": "cart.button.reserveAndCollect", 52 | "translation": "Reserve & Collect" 53 | }, 54 | 55 | { 56 | "id": "cart.button.continueShopping", 57 | "translation": "Continue Shopping" 58 | }, 59 | 60 | { 61 | "id": "miniCart.removeItem", 62 | "translation": "Remove {{.title}}" 63 | }, 64 | 65 | { 66 | "id": "miniCart.hiddenProducts", 67 | "translation": "{{.qty}} more products" 68 | }, 69 | 70 | { 71 | "id": "miniCart.hiddenProduct", 72 | "translation": "1 more product" 73 | }, 74 | 75 | { 76 | "id": "miniCart.total", 77 | "translation": "Total: {{.total}}" 78 | }, 79 | 80 | { 81 | "id": "miniCart.empty", 82 | "translation": "Your cart is empty" 83 | }, 84 | 85 | { 86 | "id": "miniCart.buttonCartView", 87 | "translation": "Shopping Bag" 88 | }, 89 | 90 | { 91 | "id": "miniCart.buttonReserveAndCollect", 92 | "translation": "Reserve & Collect" 93 | }, 94 | 95 | { 96 | "id": "cart.reserveInfo.noPayment", 97 | "translation": "No payment is taken and you have no obligation to purchase your reserved shopping requests if you change your mind." 98 | }, 99 | 100 | { 101 | "id": "cart.reserveInfo.collectedAtShop", 102 | "translation": "The items must be paid for and collected at the shop you have made the purchase from on your day of travel, prior to flying." 103 | }, 104 | 105 | { 106 | "id": "cart.reserveInfo.individualStorePolicy", 107 | "translation": "Reservations will be confirmed in accordance with individual store policy, which our customer service team will verify to you." 108 | } 109 | 110 | 111 | ] 112 | -------------------------------------------------------------------------------- /frontend/src/molecule/productTile/productTile.pug: -------------------------------------------------------------------------------- 1 | include /atom/price/price 2 | include /molecule/productMedia/productMedia 3 | include /molecule/productTile/productTileTruncate 4 | include /atom/debug/debug 5 | 6 | mixin productTile(productData) 7 | - var teaserData = productData.teaserData 8 | 9 | - var baseData = productData.baseData 10 | case productData.type 11 | when 'simple' 12 | - var productUrl = url('product.view', {marketplacecode: teaserData.marketPlaceCode, name: teaserData.shortTitle}) 13 | when 'configurable' 14 | - var variantcode = teaserData.preSelectedVariantSku ? teaserData.preSelectedVariantSku : null 15 | 16 | if variantcode 17 | - var productUrl = url('product.view', {marketplacecode: teaserData.marketPlaceCode, variantcode: variantcode, name: teaserData.shortTitle}) 18 | else 19 | - var productUrl = url('product.view', {marketplacecode: teaserData.marketPlaceCode, name: teaserData.shortTitle}) 20 | default 21 | - throw 'unknown product type' 22 | 23 | if baseData 24 | // init brandLabel and set to brandName 25 | - var brandLabel = "" 26 | if (baseData.attributes.brandName) 27 | - var brandLabel = baseData.attributes.brandName.value 28 | 29 | //- Check for promo badge 30 | - var hasPromoBadge = false 31 | - var promoCode = null 32 | if baseData.attributes.campaignCodes && baseData.attributes.campaignCodes.values.length > 0 33 | - hasPromoBadge = true 34 | - promoCode = baseData.attributes.campaignCodes.values[0] 35 | 36 | if !hasPromoBadge && productData.type === 'configurable' 37 | if productData.variants && productData.variants.length > 0 38 | each variant, index in productData.variants 39 | if variant.baseData.attributes.campaignCodes && variant.baseData.attributes.campaignCodes.values.length > 0 40 | - hasPromoBadge = true 41 | // use first promo code of variants 42 | if !promoCode 43 | - promoCode = variant.baseData.attributes.campaignCodes.values[0] 44 | 45 | a.productTile(href=productUrl title=teaserData.shortTitle)&attributes(attributes) 46 | .productTileFigure 47 | - var inserted = false 48 | each mediaItem in teaserData.media 49 | if (!inserted && mediaItem.usage === 'list') 50 | - inserted = true 51 | +productMedia(mediaItem, '400x').productTileImage 52 | if hasPromoBadge 53 | +promoBadge() 54 | p.productTileBrand 55 | +productTileTruncate(brandLabel, 15) 56 | h5.productTileTitle 57 | +productTileTruncate(teaserData.shortTitle, 50) 58 | 59 | +price(productData, productData.type, true, promoCode).productTilePrice 60 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flamingo.me/dingo" 5 | "flamingo.me/graphql" 6 | 7 | "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch" 8 | "flamingo.me/flamingo-commerce-adapter-standalone/csvindexing" 9 | "flamingo.me/flamingo-commerce/v3/cart" 10 | "flamingo.me/flamingo-commerce/v3/category" 11 | "flamingo.me/flamingo-commerce/v3/checkout" 12 | "flamingo.me/flamingo-commerce/v3/customer" 13 | "flamingo.me/flamingo-commerce/v3/payment" 14 | "flamingo.me/flamingo-commerce/v3/product" 15 | "flamingo.me/flamingo/v3" 16 | "flamingo.me/flamingo/v3/core/healthcheck" 17 | "flamingo.me/flamingo/v3/core/locale" 18 | "flamingo.me/flamingo/v3/core/requestlogger" 19 | "flamingo.me/flamingo/v3/framework/config" 20 | flamingoFramework "flamingo.me/flamingo/v3/framework/flamingo" 21 | "flamingo.me/flamingo/v3/framework/opencensus" 22 | "flamingo.me/flamingo/v3/framework/prefixrouter" 23 | "flamingo.me/flamingo/v3/framework/systemendpoint" 24 | "flamingo.me/form" 25 | "flamingo.me/pugtemplate" 26 | 27 | "flamingo.me/swagger" 28 | 29 | projectGraphql "flamingo.me/commerce-demo-carotene/graphql" 30 | ) 31 | 32 | //go:generate rm -f graphql/generated.go 33 | //go:generate go run -tags graphql main.go graphql 34 | //go:generate go run github.com/swaggo/swag/cmd/swag init --parseDependency=1 --generalInfo=main.go 35 | 36 | // main is our entry point 37 | 38 | // @title Flamingo Commerce Demo Shop 39 | // @version 1.0 40 | // @BasePath /en 41 | // @license.name MIT 42 | // @contact.name Flamingo 43 | // @contact.url https://gitter.im/i-love-flamingo/community# 44 | // @contact.email flamingo@aoe.com 45 | func main() { 46 | 47 | flamingo.App([]dingo.Module{ 48 | //flamingo framework modules: 49 | new(requestlogger.Module), // requestlogger show request logs 50 | new(prefixrouter.Module), 51 | new(flamingoFramework.SessionModule), 52 | 53 | new(locale.Module), 54 | new(opencensus.Module), 55 | new(systemendpoint.Module), 56 | new(healthcheck.Module), 57 | new(projectGraphql.Module), 58 | //form module (required by commerce) 59 | new(form.Module), 60 | //flamingo-commerce modules 61 | new(product.Module), 62 | //new(price.Module), 63 | new(category.Module), 64 | new(cart.Module), 65 | new(customer.Module), 66 | new(payment.Module), 67 | new(checkout.Module), 68 | //flamingo-commerce-adpater-standalone modules: 69 | new(commercesearch.Module), 70 | new(commercesearch.CategoryModule), 71 | new(commercesearch.SearchModule), 72 | new(csvindexing.ProductModule), 73 | //new(emailplaceorder.Module), 74 | new(graphql.Module), 75 | new(pugtemplate.Module), 76 | new(swagger.Module), 77 | }, flamingo.ChildAreas( 78 | config.NewArea("csv", nil, 79 | config.NewArea("de", nil), 80 | ), 81 | ), 82 | ) 83 | } 84 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/core/bootstrap/_functions.sass: -------------------------------------------------------------------------------- 1 | // Bootstrap functions 2 | // 3 | // Utility mixins and functions for evalutating source code across our variables, maps, and mixins. 4 | 5 | // Ascending 6 | // Used to evaluate Sass maps like our grid breakpoints. 7 | =_assert-ascending($map, $map-name) 8 | $prev-key: null 9 | $prev-num: null 10 | 11 | @each $key, $num in $map 12 | @if $prev-num == null 13 | // Do nothing 14 | @else if not comparable($prev-num, $num) 15 | @warn "Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !" 16 | @else if $prev-num >= $num 17 | @warn "Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !" 18 | 19 | $prev-key: $key 20 | $prev-num: $num 21 | 22 | // Starts at zero 23 | // Another grid mixin that ensures the min-width of the lowest breakpoint starts at 0. 24 | =_assert-starts-at-zero($map) 25 | $values: map-values($map) 26 | $first-value: nth($values, 1) 27 | 28 | @if $first-value != 0 29 | @warn "First breakpoint in `$grid-breakpoints` must start at 0, but starts at #{$first-value}." 30 | 31 | // Replace `$search` with `$replace` in `$string` 32 | // Used on our SVG icon backgrounds for custom forms. 33 | // 34 | // @author Hugo Giraudel 35 | // @param {String} $string - Initial string 36 | // @param {String} $search - Substring to replace 37 | // @param {String} $replace ('') - New value 38 | // @return {String} - Updated string 39 | @function str-replace($string, $search, $replace: "") 40 | $index: str-index($string, $search) 41 | 42 | @if $index 43 | @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace) 44 | 45 | @return $string 46 | 47 | // Color contrast 48 | @function color-yiq($color) 49 | $r: red($color) 50 | $g: green($color) 51 | $b: blue($color) 52 | 53 | $yiq: ($r * 299 + $g * 587 + $b * 114) / 1000 54 | 55 | @if $yiq >= $yiq-contrasted-threshold 56 | @return $yiq-text-dark 57 | @else 58 | @return $yiq-text-light 59 | 60 | // Retrieve color Sass maps 61 | @function color($key: "blue") 62 | @return map-get($colors, $key) 63 | 64 | @function theme-color($key: "primary") 65 | @return map-get($theme-colors, $key) 66 | 67 | @function gray($key: "100") 68 | @return map-get($grays, $key) 69 | 70 | // Request a theme color level 71 | @function theme-color-level($color-name: "primary", $level: 0) 72 | $color: theme-color($color-name) 73 | $color-base: if($level > 0, $black, $white) 74 | $level: abs($level) 75 | 76 | @return mix($color-base, $color, $level * $theme-color-interval) 77 | -------------------------------------------------------------------------------- /frontend/src/page/checkout/review.pug: -------------------------------------------------------------------------------- 1 | extends /template/base/base 2 | include /organism/cart/cart 3 | 4 | block maincontent 5 | main.mt-5.pt-4 6 | div.container 7 | //+debug(decoratedCart.cart) 8 | h2.my-5.h2.text-center Checkout 9 | if errorInfos 10 | if errorInfos.hasError 11 | if errorInfos.hasPaymentError 12 | div.alert.alert-error(role="alert") Payment Error 13 | div.alert.alert-warning(role="alert")=__("checkout.error."+errorInfos.errorMessage) 14 | div.row 15 | div.col-md-8.mb-4 16 | h4.d-flex.justify-content-between.align-items-center.mb-3 17 | span.text-muted Review your data 18 | div.card 19 | .card-body 20 | h5.mt-1.mb-2 21 | span.text-muted Billing 22 | +renderAddress(decoratedCart.cart.billingAddress) 23 | each delivery in decoratedCart.cart.deliveries 24 | - var deliveryCode = delivery.deliveryInfo.code 25 | h5(data-deliverycode=delivery.deliveryInfo.code).mt-5.mb-2 26 | span.text-muted=__(delivery.deliveryInfo.code) 27 | 28 | if deliveryCode == "delivery" 29 | if delivery.deliveryInfo.deliveryLocation.useBillingAddress 30 | p 31 | strong same as billing 32 | else 33 | +renderAddress(delivery.deliveryInfo.deliveryLocation.address) 34 | h5.mt-5.mb-2 35 | span.text-muted Payment 36 | p Gateway: #{decoratedCart.cart.paymentSelection.gateway} 37 | each chargeSplit in decoratedCart.cart.paymentSelection.chargeSplits 38 | p #{commercePriceFormat(chargeSplit.charge.price)} with Method: #{chargeSplit.method} 39 | form(action=url("checkout.review")) 40 | div.custom-control.custom-checkbox.mt-3.mb-1 41 | input.custom-control-input(type="checkbox", id="termsAndConditions", name="termsAndConditions", value="1") 42 | label.custom-control-label(for="termsAndConditions") I accept terms and conditions 43 | input(type='hidden' name='proceed' value='1') 44 | button.btn.btn-primary.btn-lg.btn-block.waves-effect.waves-light(type="submit") Pay and place order 45 | div.col-md-4.mb-4 46 | if cartValidationResult 47 | if cartValidationResult.hasCommonError 48 | div.alert.alert-warning(role="alert")=cartValidationResult.commonErrorMessageKey 49 | each itemResult in cartValidationResult.itemResults 50 | div.alert.alert-warning(role="alert")=itemResult.errorMessageKey 51 | +cart(decoratedCart,cartValidationResult,false) 52 | 53 | 54 | mixin renderAddress(address) 55 | p #{address.firstname} #{address.lastname} 56 | p #{address.email} 57 | p #{address.street} #{address.streetNr} 58 | p #{address.postCode} #{address.city} -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/free/_buttons.sass: -------------------------------------------------------------------------------- 1 | // Buttons 2 | .btn 3 | box-shadow: $z-depth-1 4 | 5 | +button-size($btn-padding-y-basic, $btn-padding-x-basic, $btn-font-size-basic) 6 | 7 | transition: $btn-transition 8 | margin: $btn-margin-basic 9 | border: 0 10 | border-radius: $border-radius-base 11 | cursor: pointer 12 | text-transform: uppercase 13 | white-space: normal 14 | word-wrap: break-word 15 | color: $btn-color-basic 16 | 17 | &:hover, 18 | &:active, 19 | &:focus 20 | box-shadow: $z-depth-1-half 21 | outline: 0 22 | 23 | &:not([disabled]):not(.disabled):active, 24 | &:not([disabled]):not(.disabled).active 25 | box-shadow: $z-depth-1-half 26 | 27 | .fa 28 | position: relative 29 | font-size: $btn-icon-basic 30 | 31 | &.right 32 | margin-left: $btn-icon-margin 33 | 34 | &.left 35 | margin-right: $btn-icon-margin 36 | 37 | &.btn-lg 38 | +button-size($btn-padding-y-large, $btn-padding-x-large, $btn-font-size-large) 39 | 40 | .fa 41 | font-size: $btn-icon-large 42 | 43 | &.btn-md 44 | +button-size($btn-padding-y-medium, $btn-padding-x-medium, $btn-font-size-medium) 45 | 46 | .fa 47 | font-size: $btn-icon-medium 48 | 49 | &.btn-sm 50 | +button-size($btn-padding-y-small, $btn-padding-x-small, $btn-font-size-small) 51 | 52 | .fa 53 | font-size: $btn-icon-small 54 | 55 | &.btn-tb 56 | padding: $btn-tb-padding-y $btn-tb-padding-x 57 | 58 | &.disabled, 59 | &:disabled 60 | &:active, 61 | &:focus, 62 | &:hover 63 | box-shadow: $z-depth-1 64 | 65 | &.btn-block 66 | margin: inherit 67 | 68 | &.btn-link 69 | @extend .black-text 70 | 71 | box-shadow: none 72 | background-color: transparent 73 | 74 | &:active, 75 | &:focus, 76 | &:hover 77 | box-shadow: none !important 78 | background-color: transparent 79 | 80 | &[class*="btn-outline-"] 81 | padding-top: $btn-outline-padding-y-basic 82 | padding-bottom: $btn-outline-padding-y-basic 83 | 84 | &.btn-lg 85 | padding-top: $btn-outline-padding-y-large 86 | padding-bottom: $btn-outline-padding-y-large 87 | 88 | &.btn-md 89 | padding-top: $btn-outline-padding-y-medium 90 | padding-bottom: $btn-outline-padding-y-medium 91 | 92 | &.btn-sm 93 | padding-top: $btn-outline-padding-y-small 94 | padding-bottom: $btn-outline-padding-y-small 95 | 96 | .btn-group 97 | .btn 98 | margin: 0 99 | 100 | // Overwrite default button icon size 101 | .btn 102 | .fa-lg 103 | font-size: 1.33333333em !important 104 | 105 | .fa-2x 106 | font-size: 2em !important 107 | 108 | .fa-3x 109 | font-size: 3em !important 110 | 111 | .fa-4x 112 | font-size: 4em !important 113 | 114 | .fa-5x 115 | font-size: 5em !important 116 | 117 | @each $btn_name, $color_value in $mdb-colors 118 | +make-button($btn_name, $color_value) 119 | +make-outline-button($btn_name, $color_value) 120 | -------------------------------------------------------------------------------- /translations/merged/de-de.all.yaml: -------------------------------------------------------------------------------- 1 | cart.button.continueShopping: 2 | other: "" 3 | cart.button.reserveAndCollect: 4 | other: "" 5 | cart.column.price: 6 | other: "" 7 | cart.column.quantity: 8 | other: "" 9 | cart.column.sum: 10 | other: "" 11 | cart.group.title: 12 | other: "" 13 | cart.item.detail: 14 | other: "" 15 | cart.item.remove: 16 | other: "" 17 | cart.loyalty.label: 18 | other: "" 19 | cart.reserveInfo.collectedAtShop: 20 | other: "" 21 | cart.reserveInfo.individualStorePolicy: 22 | other: "" 23 | cart.reserveInfo.noPayment: 24 | other: "" 25 | cart.total.label: 26 | other: "" 27 | checkout.back_to_cart: 28 | other: "" 29 | checkout.cart_item_error_hint: 30 | other: "" 31 | checkout.error.terms_and_conditions_required: 32 | other: "" 33 | checkout.legalConfirmation.termsAndConditions: 34 | other: "" 35 | checkout.no_items_in_cart: 36 | other: "" 37 | checkout.success_message1: 38 | other: "" 39 | checkout.success_message2: 40 | other: "" 41 | delivery: 42 | other: "" 43 | error.404.headline: 44 | other: "" 45 | error.503.headline: 46 | other: "" 47 | error.common.headline: 48 | other: "" 49 | error.homeButton: 50 | other: "" 51 | facet.header.brandCode: 52 | other: "" 53 | header.welcome.subtitle: 54 | other: Standart demo shop mit carotene templates 55 | miniCart.buttonCartView: 56 | other: "" 57 | miniCart.buttonReserveAndCollect: 58 | other: "" 59 | miniCart.empty: 60 | other: "" 61 | miniCart.hiddenProduct: 62 | other: "" 63 | miniCart.hiddenProducts: 64 | other: "" 65 | miniCart.removeItem: 66 | other: "" 67 | miniCart.total: 68 | other: "" 69 | pickup_store: 70 | other: "" 71 | product.attribute.__group_packageSizes: 72 | other: "" 73 | product.attribute.baseColor: 74 | other: "" 75 | product.attribute.manufacturerColor: 76 | other: "" 77 | product.attribute.washingInstructions: 78 | other: "" 79 | search.footer.callNow: 80 | other: "" 81 | search.footer.description: 82 | other: "" 83 | search.footer.headline: 84 | other: "" 85 | search.found.brands: 86 | other: "" 87 | search.found.other: 88 | other: "" 89 | search.found.products: 90 | other: "" 91 | search.live.brands: 92 | other: "" 93 | search.live.contentPages: 94 | other: "" 95 | search.live.inRetailers: 96 | other: "" 97 | search.live.input.aria: 98 | other: "" 99 | search.live.input.placeholder: 100 | other: "" 101 | search.live.label: 102 | other: "" 103 | search.live.noResults: 104 | other: "" 105 | search.live.popular: 106 | other: "" 107 | search.live.products: 108 | other: "" 109 | search.live.reset: 110 | other: "" 111 | search.live.results: 112 | other: "" 113 | search.live.retailers: 114 | other: "" 115 | search.live.showAll: 116 | other: "" 117 | search.live.submit.aria: 118 | other: "" 119 | search.live.totalResults: 120 | other: "" 121 | search.noresult.titleWithQuery: 122 | other: "" 123 | search.noresult.widgetHeadline: 124 | other: "" 125 | search.result.title: 126 | other: "" 127 | search.result.titleWithQuery: 128 | other: "" 129 | search.suggestion.title: 130 | other: "" 131 | searchNoResultsHeader.buttonLabel: 132 | other: "" 133 | searchNoResultsHeader.text: 134 | other: "" 135 | searchNoResultsHeader.title: 136 | other: "" 137 | -------------------------------------------------------------------------------- /config/config.yml: -------------------------------------------------------------------------------- 1 | # Flamingo core related configurations: 2 | flamingo: 3 | web: 4 | filter: 5 | cachestrategy: 6 | default: 7 | # disable http caching by default 8 | revalidateEachTime: true 9 | isReusable: false 10 | debug: 11 | mode: false 12 | session: 13 | backend: memory # in prod you will use something like redis 14 | zap: 15 | loglevel: Warn 16 | prefixrouter: 17 | rootRedirectHandler: 18 | enabled: true 19 | redirectTarget: "/en/" 20 | opencensus: 21 | tracing: 22 | sample: 23 | blacklist: 24 | - "/image" 25 | - "/static" 26 | 27 | core: 28 | oauth: 29 | server: 'https://accounts.google.com' 30 | secret: "%%ENV:OAUTH_SECRET%%" 31 | clientid: flamingo 32 | myhost: '%%ENV:FLAMINGO_HOSTNAME%%' 33 | disableOfflineToken: true 34 | mapping.idToken: 35 | groups: "UserType" 36 | locale: 37 | locale: en-gb 38 | translationFiles: 39 | - translations/merged/en-gb.all.yaml 40 | accounting: 41 | default: 42 | thousand: ',' 43 | decimal: '.' 44 | formatZero: '%s -.-' 45 | format: "%s %v" 46 | EUR: 47 | thousand: '.' 48 | decimal: ',' 49 | formatZero: '-,- %s' 50 | format: "%v %s" 51 | numbers: 52 | decimal: '.' 53 | thousand: ',' 54 | precision: 1 55 | date: 56 | dateFormat: 02 Jan 2006 57 | timeFormat: 15:04 58 | dateTimeFormat: 02 Jan 2006 15:04:05 59 | location: Europe/London 60 | 61 | # By convention "template" is the namespace of configs just used in the template 62 | template: 63 | defaultTitle: "Flamingo Commerce Demo" 64 | product: 65 | descriptionAttributes: 66 | - size 67 | - colour 68 | - clothing_size 69 | 70 | # Configs for flamingo-commerce modules 71 | commerce: 72 | pagination: 73 | defaultPageSize: 8 74 | showAroundActivePageAmount: 2 75 | cart: 76 | defaultCartAdapter: 77 | enabled: true 78 | defaultTaxRate: 19 79 | placeOrderLogger: 80 | enabled: true 81 | useFlamingoLog: true 82 | logAsFile: true 83 | logDirectory: "./orders/" 84 | defaultDeliveryCode: delivery 85 | enableCartCache: false 86 | checkout: 87 | showEmptyCartPageIfNoItems: true 88 | payment: 89 | enableOfflinePaymentGateway: true 90 | customer: 91 | useNilCustomerAdapter: true 92 | category: 93 | useCategoryFixedAdapter: false 94 | 95 | graphql: 96 | introspectionEnabled: true # should be turned off in prod env 97 | 98 | 99 | flamingoCommerceAdapterStandalone: 100 | csvindexing: 101 | products: 102 | file: 103 | path: "resources/products/products_en.csv" 104 | delimiter: "," 105 | categories: 106 | file: 107 | path: "resources/products/categories.csv" 108 | delimiter: "," 109 | locale: "en_GB" 110 | currency: "GBP" 111 | commercesearch: 112 | enableIndexing: true 113 | repositoryAdapter: bleve 114 | bleveAdapter: 115 | enableCategoryFacet: true 116 | facetConfig: 117 | - attributeCode: brandCode 118 | amount: 10 119 | emailplaceorder: 120 | emailAddress: "flamingo@flamingo.me" 121 | fromMail: "flamingo@flamingo.me" 122 | fromName: "Flamingo Webstore" 123 | -------------------------------------------------------------------------------- /translations/src/en-gb.search.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id":"facet.header.brandCode", 4 | "translation":"Brand" 5 | }, 6 | { 7 | "id":"search.result.titleWithQuery", 8 | "translation":"Search results for \"{{ .query }}\"" 9 | }, 10 | { 11 | "id":"search.result.title", 12 | "translation":"Search results" 13 | }, 14 | { 15 | "id":"search.noresult.titleWithQuery", 16 | "translation":"No results for \"{{ .query }}\"" 17 | }, 18 | { 19 | "id":"search.noresult.widgetHeadline", 20 | "translation":"Trending Results" 21 | }, 22 | { 23 | "id":"search.suggestion.title", 24 | "translation":"Here are some results for \"{{ .query }}\"" 25 | }, 26 | { 27 | "id":"search.found.brands", 28 | "translation":"Found in Brands" 29 | }, 30 | { 31 | "id":"search.found.products", 32 | "translation":"Found in Products ({{ .numResults }})" 33 | }, 34 | { 35 | "id":"search.found.other", 36 | "translation":"Other results (%s)" 37 | }, 38 | { 39 | "id":"search.footer.headline", 40 | "translation":"Can’t see what you want?" 41 | }, 42 | { 43 | "id":"search.footer.description", 44 | "translation":"Our Shopping Services team are available to answer any questions that you have about brands, products or services at Heathrow." 45 | }, 46 | { 47 | "id":"search.footer.callNow", 48 | "translation":"Call now +44 (0)800 678 5324" 49 | }, 50 | { 51 | "id":"searchNoResultsHeader.title", 52 | "translation":"We couldn't find any results
that match your search" 53 | }, 54 | { 55 | "id":"searchNoResultsHeader.text", 56 | "translation":"Please check for misspellings or broaden your search by using fewer keywords.
Alternatively, browse our products by selecting a category from the menu." 57 | }, 58 | { 59 | "id":"searchNoResultsHeader.buttonLabel", 60 | "translation":"Search again" 61 | }, 62 | { 63 | "id": "search.live.label", 64 | "translation": "Search" 65 | }, 66 | { 67 | "id": "search.live.input.placeholder", 68 | "translation": "Search" 69 | }, 70 | { 71 | "id": "search.live.input.aria", 72 | "translation": "Search website" 73 | }, 74 | { 75 | "id": "search.live.submit.aria", 76 | "translation": "Submit search" 77 | }, 78 | { 79 | "id": "search.live.showAll", 80 | "translation": "Show all results" 81 | }, 82 | { 83 | "id": "search.live.popular", 84 | "translation": "Popular searches" 85 | }, 86 | { 87 | "id": "search.live.products", 88 | "translation": "Found products" 89 | }, 90 | { 91 | "id": "search.live.results", 92 | "translation": "Search results" 93 | }, 94 | { 95 | "id": "search.live.brands", 96 | "translation": "Brands" 97 | }, 98 | { 99 | "id": "search.live.retailers", 100 | "translation": "Retailers" 101 | }, 102 | { 103 | "id": "search.live.contentPages", 104 | "translation": "Content pages" 105 | }, 106 | { 107 | "id": "search.live.inRetailers", 108 | "translation": "in retailers" 109 | }, 110 | { 111 | "id": "search.live.reset", 112 | "translation": "Reset search" 113 | }, 114 | { 115 | "id": "search.live.noResults", 116 | "translation": "Sorry, there are no results matching your query." 117 | }, 118 | { 119 | "id": "search.live.totalResults", 120 | "translation": "Total results" 121 | } 122 | ] 123 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/core/_waves.sass: -------------------------------------------------------------------------------- 1 | /*! 2 | * Waves v0.7.5 3 | * http://fian.my.id/Waves 4 | * 5 | * Copyright 2014-2016 Alfiana E. Sibuea and other contributors 6 | * Released under the MIT license 7 | * https://github.com/fians/Waves/blob/master/LICENSE 8 | 9 | =waves-transition($transition) 10 | transition: $transition 11 | 12 | =waves-transform($string) 13 | transform: $string 14 | 15 | =waves-box-shadow($shadow) 16 | box-shadow: $shadow 17 | 18 | .waves-effect 19 | position: relative 20 | cursor: pointer 21 | overflow: hidden 22 | user-select: none 23 | -webkit-tap-highlight-color: transparent 24 | z-index: 1 25 | 26 | .waves-ripple 27 | position: absolute 28 | border-radius: 50% 29 | width: 100px 30 | height: 100px 31 | margin-top: -50px 32 | margin-left: -50px 33 | opacity: 0 34 | background: rgba(0, 0, 0, 0.2) 35 | 36 | $gradient: rgba(0, 0, 0, 0.2) 0, rgba(0, 0, 0, 0.3) 40%, rgba(0, 0, 0, 0.4) 50%, rgba(0, 0, 0, 0.5) 60%, rgba(255, 255, 255, 0) 70% 37 | 38 | background: -webkit-radial-gradient($gradient) 39 | background: -o-radial-gradient($gradient) 40 | background: -moz-radial-gradient($gradient) 41 | background: radial-gradient($gradient) 42 | 43 | +waves-transition(all 0.5s ease-out) 44 | 45 | transition-property: transform, opacity 46 | 47 | +waves-transform(scale(0) translate(0, 0)) 48 | 49 | pointer-events: none 50 | 51 | &.waves-light .waves-ripple 52 | background: rgba(255, 255, 255, 0.4) 53 | 54 | $gradient: rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0) 70% 55 | 56 | background: radial-gradient($gradient) 57 | 58 | &.waves-classic .waves-ripple 59 | background: rgba(0, 0, 0, 0.2) 60 | 61 | &.waves-classic.waves-light .waves-ripple 62 | background: rgba(255, 255, 255, 0.4) 63 | 64 | .waves-notransition 65 | +waves-transition(none #{"!important"}) 66 | 67 | .waves-button, 68 | .waves-circle 69 | +waves-transform(translateZ(0)) 70 | 71 | -webkit-mask-image: -webkit-radial-gradient(circle, white 100%, black 100%) 72 | 73 | .waves-button, 74 | .waves-button:hover, 75 | .waves-button:visited, 76 | .waves-button-input 77 | white-space: nowrap 78 | vertical-align: middle 79 | cursor: pointer 80 | border: none 81 | outline: none 82 | color: inherit 83 | background-color: rgba(0, 0, 0, 0) 84 | font-size: 1em 85 | line-height: 1em 86 | text-align: center 87 | text-decoration: none 88 | z-index: 1 89 | 90 | .waves-button 91 | padding: 0.85em 1.1em 92 | border-radius: 0.2em 93 | 94 | .waves-button-input 95 | margin: 0 96 | padding: 0.85em 1.1em 97 | 98 | .waves-input-wrapper 99 | border-radius: 0.2em 100 | vertical-align: middle 101 | display: inline-block 102 | 103 | &.waves-button 104 | padding: 0 105 | 106 | .waves-button-input 107 | position: relative 108 | top: 0 109 | left: 0 110 | z-index: 1 111 | 112 | .waves-circle 113 | text-align: center 114 | width: 2.5em 115 | height: 2.5em 116 | line-height: 2.5em 117 | border-radius: 50% 118 | 119 | .waves-float 120 | -webkit-mask-image: none 121 | 122 | +waves-box-shadow(0px 1px 1.5px 1px rgba(0, 0, 0, 0.12)) 123 | +waves-transition(all 300ms) 124 | 125 | &:active 126 | +waves-box-shadow(0px 8px 20px 1px rgba(0, 0, 0, 0.3)) 127 | 128 | .waves-block 129 | display: block 130 | 131 | a 132 | &.waves-effect, 133 | &.waves-light 134 | display: inline-block 135 | -------------------------------------------------------------------------------- /frontend/src/atom/price/price.sass: -------------------------------------------------------------------------------- 1 | $priceStrikeColor: $colorMonotoneMid1 2 | $priceTaxAndDutyFreeColor: $colorMonotoneMid2 3 | $priceDiscountedPromoColor: $colorPrimaryRegular 4 | $priceMobileCenterBorderColor: $colorMonotoneLight 5 | $priceAdditionalBreakpoint: 375px 6 | 7 | .price 8 | display: flex 9 | justify-content: center 10 | flex-wrap: wrap 11 | 12 | &.priceHasPromoDiscountContainer:not(.priceTypeTileView) 13 | justify-content: flex-start 14 | 15 | &.priceTypeTileView 16 | display: flex 17 | justify-content: center 18 | 19 | +respondFrom(s) 20 | display: block 21 | 22 | 23 | .priceRegular 24 | font-size: 18px 25 | 26 | +respondFrom(s) 27 | padding-bottom: 15px 28 | font-size: 22px 29 | 30 | .priceTypeTileView & 31 | font-size: 14px 32 | line-height: 22px 33 | padding: 0 6px 34 | 35 | .priceShowDiscounted & 36 | color: $priceStrikeColor 37 | 38 | .priceHasPromoDiscountContainer:not(.priceTypeTileView) & 39 | border-left: 1px solid $priceMobileCenterBorderColor 40 | padding-left: 16px 41 | 42 | +respondFrom($priceAdditionalBreakpoint) 43 | padding-left: 30px 44 | 45 | +respondFrom(s) 46 | border-left: 0 47 | padding-left: 0 48 | 49 | 50 | .priceTaxAndDutyFree 51 | color: $priceTaxAndDutyFreeColor 52 | letter-spacing: .2px 53 | font-size: 14px 54 | line-height: 18px 55 | width: 100% 56 | margin-top: 15px 57 | 58 | +respondFrom(s) 59 | font-size: 16px 60 | line-height: 24px 61 | 62 | 63 | .pricePromoDiscount 64 | width: 50% 65 | border-right: 1px solid $priceMobileCenterBorderColor 66 | padding-right: 16px 67 | display: flex 68 | justify-content: flex-end 69 | 70 | .priceTypeTileView & 71 | width: auto 72 | border-right: 0 73 | display: block 74 | padding-right: 0 75 | margin-bottom: 0 76 | 77 | +respondFrom($priceAdditionalBreakpoint) 78 | padding-right: 30px 79 | 80 | +respondFrom(s) 81 | width: auto 82 | border-right: 0 83 | padding: 0 84 | display: block 85 | margin-bottom: 30px 86 | 87 | .pricePromoDiscountInner 88 | text-align: center 89 | 90 | +respondFrom(s) 91 | text-align: left 92 | 93 | .pricePromoDiscountLabel, 94 | .priceLabel 95 | +caps 96 | line-height: 16px 97 | padding-bottom: 2px 98 | font-size: 12px 99 | text-decoration: none 100 | 101 | +respondFrom(s) 102 | padding-bottom: 10px 103 | 104 | .pricePromoDiscountLabel 105 | color: $priceDiscountedPromoColor 106 | 107 | .pricePromo, 108 | .priceDiscounted 109 | color: $priceDiscountedPromoColor 110 | font-size: 18px 111 | font-weight: bold 112 | display: block 113 | 114 | +respondFrom(s) 115 | font-size: 22px 116 | 117 | .priceTypeTileView & 118 | font-size: 14px 119 | line-height: 22px 120 | padding: 0 6px 121 | 122 | .pricePromoComponent 123 | display: block 124 | 125 | .priceTypeTileView & 126 | display: inline 127 | 128 | .pricePromoComponentSecondary 129 | margin-top: 5px 130 | font-weight: normal 131 | font-size: 14px 132 | 133 | +respondFrom(s) 134 | margin-top: 10px 135 | font-size: 16px 136 | 137 | .priceTypeTileView & 138 | font-weight: inherit 139 | font-size: inherit 140 | 141 | 142 | .priceValue 143 | .priceShowDiscounted & 144 | text-decoration: line-through 145 | 146 | 147 | .priceTermsConditionLink 148 | display: inline-block 149 | margin-top: 5px 150 | color: $priceDiscountedPromoColor 151 | text-decoration: underline 152 | font-size: 14px 153 | 154 | +respondFrom(s) 155 | margin-top: 10px 156 | font-size: 16px 157 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/core/_typography.sass: -------------------------------------------------------------------------------- 1 | // Typography 2 | // ROBOTO FONT 3 | @font-face 4 | font-family: "Roboto" 5 | src: local(Roboto Thin), url("#{$roboto-font-path}Roboto-Thin.eot") 6 | src: url("#{$roboto-font-path}Roboto-Thin.eot?#iefix") format("embedded-opentype"), url("#{$roboto-font-path}Roboto-Thin.woff2") format("woff2"), url("#{$roboto-font-path}Roboto-Thin.woff") format("woff"), url("#{$roboto-font-path}Roboto-Thin.ttf") format("truetype") 7 | font-weight: 200 8 | 9 | @font-face 10 | font-family: "Roboto" 11 | src: local(Roboto Light), url("#{$roboto-font-path}Roboto-Light.eot") 12 | src: url("#{$roboto-font-path}Roboto-Light.eot?#iefix") format("embedded-opentype"), url("#{$roboto-font-path}Roboto-Light.woff2") format("woff2"), url("#{$roboto-font-path}Roboto-Light.woff") format("woff"), url("#{$roboto-font-path}Roboto-Light.ttf") format("truetype") 13 | font-weight: 300 14 | 15 | @font-face 16 | font-family: "Roboto" 17 | src: local(Roboto Regular), url("#{$roboto-font-path}Roboto-Regular.eot") 18 | src: url("#{$roboto-font-path}Roboto-Regular.eot?#iefix") format("embedded-opentype"), url("#{$roboto-font-path}Roboto-Regular.woff2") format("woff2"), url("#{$roboto-font-path}Roboto-Regular.woff") format("woff"), url("#{$roboto-font-path}Roboto-Regular.ttf") format("truetype") 19 | font-weight: 400 20 | 21 | @font-face 22 | font-family: "Roboto" 23 | src: url("#{$roboto-font-path}Roboto-Medium.eot") 24 | src: url("#{$roboto-font-path}Roboto-Medium.eot?#iefix") format("embedded-opentype"), url("#{$roboto-font-path}Roboto-Medium.woff2") format("woff2"), url("#{$roboto-font-path}Roboto-Medium.woff") format("woff"), url("#{$roboto-font-path}Roboto-Medium.ttf") format("truetype") 25 | font-weight: 500 26 | 27 | @font-face 28 | font-family: "Roboto" 29 | src: url("#{$roboto-font-path}Roboto-Bold.eot") 30 | src: url("#{$roboto-font-path}Roboto-Bold.eot?#iefix") format("embedded-opentype"), url("#{$roboto-font-path}Roboto-Bold.woff2") format("woff2"), url("#{$roboto-font-path}Roboto-Bold.woff") format("woff"), url("#{$roboto-font-path}Roboto-Bold.ttf") format("truetype") 31 | font-weight: 700 32 | 33 | body 34 | font-family: "Roboto", sans-serif 35 | font-weight: 300 36 | 37 | h1, h2, h3, h4, h5, h6 38 | font-weight: 300 39 | 40 | // Responsive headings 41 | @each $key, $val in $grid-breakpoints 42 | +media-breakpoint-up($key) 43 | $y: map-get($responsive-headings, $key) 44 | 45 | @each $name, $value in $y 46 | .#{$name}-responsive 47 | font-size: $value 48 | 49 | // Divider 50 | .divider-new 51 | flex-direction: row 52 | justify-content: center 53 | align-items: center 54 | display: flex 55 | margin-top: $divider-margin-y 56 | margin-bottom: $divider-margin-y 57 | 58 | > h1, h2, h3, h4, h5, h6 59 | margin-bottom: 0 60 | 61 | &:before, 62 | &:after 63 | content: "" 64 | height: 1.5px 65 | flex: 1 66 | height: $divider-height 67 | background: #c6c6c6 68 | 69 | &:before 70 | margin: 0 $divider-margin-x 0 0 71 | 72 | &:after 73 | margin: 0 0 0 $divider-margin-x 74 | 75 | // Blockquote 76 | .blockquote 77 | padding: $blockquote-padding-y $blockquote-padding-x 78 | border-left: .25rem solid #eceeef 79 | 80 | .bq-title 81 | margin-bottom: 0 82 | font-size: $font-size-large 83 | font-weight: 400 84 | 85 | p 86 | padding: $blockquote-p-padding-t 0 $blockquote-p-padding-b $blockquote-p-padding-l 87 | font-size: $blockquote-p-font-size 88 | 89 | @each $name, $color in $basic 90 | .bq-#{$name} 91 | border-left: 3px solid $color !important 92 | 93 | .bq-title 94 | color: $color !important 95 | 96 | @each $name, $color in $basic-mdb-colors 97 | +text-emphasis-variant(".text-#{$name}", $color) 98 | 99 | .font-small 100 | font-size: $font-small 101 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Official Commerce Flamingo Demo 2 | 3 | Watch online: https://demoshop.flamingo.me/en/ 4 | 5 | Or try the powerful Flamingo-Commerce graphql console: https://demoshop.flamingo.me/en/graphql-console 6 | 7 | ## What's inside: 8 | 9 | The demo shop comes with: 10 | 11 | * Using the Flamingo Commerce Standalone Adapter: Products and Categories are indexed from a plain CSV file into an embedded indexed search (bleve). Once an order is placed Flamingo logs the order and sends an E-Mail. 12 | 13 | * The multi context feature of Flamingo is used to have 2 different locales (de and en) 14 | 15 | * An example template using pug and Flamingo Carotene is used. 16 | 17 | 18 | ## Getting Started 19 | 20 | ### Preconditions 21 | 22 | This demo uses Flamingo Carotene, so you should have `npm` installed. (https://www.npmjs.com/get-npm) 23 | Also you need Go installed. (https://golang.org/) 24 | 25 | ### Run the demo shop 26 | 27 | #### Try out with docker: 28 | 29 | ``` 30 | docker run --rm -p 3210:3210 iloveflamingo/flamingo-commerce-demo-carotene:latest 31 | ``` 32 | Now open http://localhost:3210/ 33 | 34 | #### Try the GraphQL API 35 | open http://localhost:3210/en/graphql-console/ 36 | 37 | #### Run local from source code: 38 | ``` 39 | # clone the repo: 40 | git clone https://github.com/i-love-flamingo/commerce-demo-carotene.git 41 | cd commerce-demo-carotene 42 | 43 | # Download the test catalog - you only need to do it once - it includes products.csv and images: 44 | make download-product-data 45 | 46 | # Prepare translation files: 47 | make translation 48 | 49 | # Build the flamingo-carotene bases templates: 50 | make frontend-build 51 | 52 | # Run flamingo with flamingo-commerce 53 | make serve 54 | 55 | ``` 56 | 57 | Now open http://localhost:3210/ 58 | 59 | ## About the Demo Frontend - Template 60 | The demo comes with a simple demo template in "frontend/src" that is using carotene-cli 61 | 62 | The template is based on: https://github.com/mdbootstrap/Ecommerce-Template-Bootstrap 63 | 64 | The following things have been changed: 65 | - Markup was transformed to pug and split according to atomic design 66 | - SASS is used instead of scss (`docker run -it -v "$(pwd)":/workdir unibeautify/sass-convert -R . --from scss --to sass`) 67 | 68 | You can start watch mode with rebuilding the frontend after changes with this command: 69 | ``` 70 | make frontend 71 | ``` 72 | ### License MDBootstrap 73 | 74 | Copyright (c) 2017 MDBootstrap.com 75 | 76 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 77 | 78 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 79 | 80 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 81 | 82 | 83 | ## Production ready? 84 | 85 | This demo project is **not** production ready - at least the following things need to be considered: 86 | 87 | * The template is not optimized and just for demo reasons, in a production template we would probably not use this bootstrap, material design demo as a start. Rather we would start a clean template based on the screen design. 88 | * The Secondary Adapters used in the demo are not full featured. 89 | -------------------------------------------------------------------------------- /frontend/src/page/home/molecule/carousel/carousel.pug: -------------------------------------------------------------------------------- 1 | #carousel-example-1z.carousel.slide.carousel-fade.pt-4(data-ride='carousel') 2 | // Indicators 3 | ol.carousel-indicators 4 | li.active(data-target='#carousel-example-1z', data-slide-to='0') 5 | li(data-target='#carousel-example-1z', data-slide-to='1') 6 | //- li(data-target='#carousel-example-1z', data-slide-to='2') 7 | // /.Indicators 8 | // Slides 9 | .carousel-inner(role='listbox') 10 | // First slide 11 | .carousel-item.active 12 | // https://pixabay.com/de/flamingo-valentin-herz-valentinstag-600205/ 13 | - var imageStyle = "background-image: url('"+asset("asset/img/visuals/flamingo-scetch.jpg")+"'); background-repeat: no-repeat; background-size: cover;" 14 | .view(style=imageStyle) 15 | // Mask & flexbox options 16 | .mask.d-flex.justify-content-center.align-items-center 17 | // Content 18 | .text-center.black-text.mx-5.wow.fadeIn 19 | h1.mb-4 20 | strong Flamingo commerce 21 | //p Blazing fast modern eCommerce frontend framework ideally for your microservice architecture. 22 | p.mb-4.d-none.d-md-block= __("header.welcome.subtitle") 23 | a.btn.btn-dark.btn-lg(target='_blank', href='https://flamingo.me/') 24 | | Learn more 25 | i.fa.fa-graduation-cap.ml-2 26 | // Content 27 | // Mask & flexbox options 28 | // /First slide 29 | // Second slide 30 | //- .carousel-item 31 | // https://pixabay.com/de/digitale-kunst-digital-art-flamingo-3054735/ 32 | - var imageStyle = "background-image: url('"+asset("asset/img/visuals/digital-art-3054735_1280.jpg")+"'); background-repeat: no-repeat; background-size: cover;" 33 | .view(style=imageStyle) 34 | // Mask & flexbox options 35 | .mask.d-flex.justify-content-center.align-items-center 36 | // Content 37 | .text-center.white-text.mx-5.wow.fadeIn 38 | h1.mb-4 39 | strong Flamingo eCommerce 40 | p 41 | strong The head for our eCommerce architecture 42 | p.mb-4.d-none.d-md-block 43 | strong 44 | | Blazing fast modern eCommerce frontend framework ideally for your microservice architecture. 45 | a.btn.btn-outline-white.btn-lg(target='_blank', href='https://flamingo.me/') 46 | | Read more 47 | i.fa.fa-graduation-cap.ml-2 48 | // Content 49 | // Mask & flexbox options 50 | // /Second slide 51 | // Third slide 52 | .carousel-item 53 | - var imageStyle = "background-image: url('"+asset("asset/img/visuals/digital-art-3054735_1280.jpg")+"'); background-repeat: no-repeat; background-size: cover;" 54 | .view(style=imageStyle) 55 | // Mask & flexbox options 56 | .mask.rgba-black-strong.d-flex.justify-content-center.align-items-center 57 | // Content 58 | .white-text.mx-5.wow.fadeIn 59 | h1.mb-4 60 | strong Highlights 61 | p.mb-4.d-none.d-md-block 62 | ul 63 | li golang powered high performance rendering 64 | li build with developer happiness in mind. 65 | li ports and adapters - easy to connect to microservices 66 | li flexible commerce domain models 67 | // Content 68 | // Mask & flexbox options 69 | // /Third slide 70 | // /.Slides 71 | // Controls 72 | a.carousel-control-prev(href='#carousel-example-1z', role='button', data-slide='prev') 73 | span.carousel-control-prev-icon(aria-hidden='true') 74 | span.sr-only Previous 75 | a.carousel-control-next(href='#carousel-example-1z', role='button', data-slide='next') 76 | span.carousel-control-next-icon(aria-hidden='true') 77 | span.sr-only Next 78 | // /.Controls 79 | // /.Carousel Wrapper 80 | // Main layout 81 | -------------------------------------------------------------------------------- /graphql/schema/flamingo.me_flamingo-commerce_v3_search_interfaces_graphql-Service.graphql: -------------------------------------------------------------------------------- 1 | input Commerce_Search_KeyValueFilter { 2 | k: String! 3 | v: [String!] 4 | } 5 | 6 | input Commerce_Search_Request { 7 | pageSize: Int 8 | page: Int 9 | sortBy: String 10 | keyValueFilters: [Commerce_Search_KeyValueFilter!] 11 | query: String 12 | } 13 | 14 | #input Commerce_Search_LiveSearchRequest { 15 | # query: String 16 | #} 17 | 18 | type Commerce_Search_Meta { 19 | query: String! 20 | originalQuery: String! 21 | page: Int! 22 | numPages: Int! 23 | numResults: Int! 24 | sortOptions: [Commerce_Search_SortOption!] 25 | } 26 | 27 | type Commerce_Search_SortOption { 28 | label: String! 29 | field: String! 30 | selected: Boolean! 31 | } 32 | 33 | interface Commerce_Search_Facet { 34 | name: String! 35 | label: String! 36 | position: Int! 37 | items: [Commerce_Search_FacetItem!]! 38 | hasSelectedItem: Boolean! 39 | } 40 | 41 | interface Commerce_Search_FacetItem { 42 | label: String! 43 | value: String! 44 | selected: Boolean! 45 | count: Int! 46 | } 47 | 48 | type Commerce_Search_ListFacet implements Commerce_Search_Facet { 49 | name: String! 50 | label: String! 51 | position: Int! 52 | items: [Commerce_Search_ListFacetItem!]! 53 | hasSelectedItem: Boolean! 54 | } 55 | 56 | type Commerce_Search_ListFacetItem implements Commerce_Search_FacetItem { 57 | label: String! 58 | value: String! 59 | selected: Boolean! 60 | count: Int! 61 | } 62 | 63 | type Commerce_Search_TreeFacet implements Commerce_Search_Facet { 64 | name: String! 65 | label: String! 66 | position: Int! 67 | items: [Commerce_Search_TreeFacetItem!]! 68 | hasSelectedItem: Boolean! 69 | } 70 | 71 | type Commerce_Search_TreeFacetItem implements Commerce_Search_FacetItem { 72 | label: String! 73 | value: String! 74 | selected: Boolean! 75 | count: Int! 76 | active: Boolean! 77 | items: [Commerce_Search_TreeFacetItem!] 78 | } 79 | 80 | type Commerce_Search_RangeFacet implements Commerce_Search_Facet { 81 | name: String! 82 | label: String! 83 | position: Int! 84 | items: [Commerce_Search_RangeFacetItem!]! 85 | hasSelectedItem: Boolean! 86 | } 87 | 88 | type Commerce_Search_RangeFacetItem implements Commerce_Search_FacetItem { 89 | label: String! 90 | value: String! 91 | selected: Boolean! 92 | count: Int! 93 | min: Int! 94 | max: Int! 95 | selectedMin: Int! 96 | selectedMax: Int! 97 | } 98 | 99 | type Commerce_Search_Suggestion { 100 | text: String! 101 | highlight: String! 102 | } 103 | 104 | type Commerce_Search_Action { 105 | type: String! 106 | content: String! 107 | } 108 | 109 | type Commerce_Search_Promotion { 110 | title: String! 111 | content: String! 112 | url: String! 113 | media: Commerce_Search_PromotionMedia 114 | } 115 | 116 | type Commerce_Search_PromotionMedia { 117 | type: String! 118 | mimeType: String! 119 | usage: String! 120 | title: String! 121 | reference: String! 122 | } 123 | 124 | #type Commerce_Search_Result { 125 | # hits: []Commerce_Search_Document / Or maybe we dont need hits and the modules need to add a edge to this object... we will see 126 | # searchMeta: Commerce_Search_Meta! 127 | # Facets: domain.FacetCollection 128 | # suggestions: [Commerce_Search_Suggestion] 129 | #} 130 | 131 | 132 | #extend type Query { 133 | # Commerce_Search(searchRequest: Commerce_Search_Request): Commerce_Search_Result 134 | # Commerce_Search_LiveSearch(searchRequest: Commerce_Search_LiveSearchRequest): Commerce_Search_ResultCommerce_Search_LiveSearchRequest! 135 | #} 136 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/free/_forms.sass: -------------------------------------------------------------------------------- 1 | // Forms basic 2 | // Input + label wrapper styles 3 | .md-form 4 | // Text inputs 5 | input[type=text], 6 | input[type=password], 7 | input[type=email], 8 | input[type=url], 9 | input[type=time], 10 | input[type=date], 11 | input[type=datetime-local], 12 | input[type=tel], 13 | input[type=number], 14 | input[type=search-md], 15 | input[type=search], 16 | textarea.md-textarea 17 | // General Styles 18 | transition: $input-transition 19 | outline: none 20 | box-shadow: none 21 | border: none 22 | border-bottom: 1px solid $input-border-color 23 | border-radius: 0 24 | box-sizing: content-box 25 | background-color: transparent 26 | 27 | // Focused input style 28 | &:focus:not([readonly]) 29 | box-shadow: 0 1px 0 0 $input-md-focus-color 30 | border-bottom: 1px solid $input-md-focus-color 31 | 32 | // Focused label style 33 | + label 34 | color: $input-md-focus-color 35 | 36 | // Form message shared styles 37 | + label:after 38 | content: "" 39 | position: absolute 40 | top: $input-label-after-top 41 | display: block 42 | opacity: 0 43 | transition: $input-label-after-transition 44 | 45 | // Valid input style 46 | &.valid, &:focus.valid 47 | border-bottom: 1px solid $input-success-color 48 | box-shadow: 0 1px 0 0 $input-success-color 49 | 50 | &.valid + label:after, &:focus.valid + label:after 51 | content: attr(data-success) 52 | color: $input-success-color 53 | opacity: 1 54 | 55 | // Invalid input style 56 | &.invalid, &:focus.invalid 57 | border-bottom: 1px solid $input-error-color 58 | box-shadow: 0 1px 0 0 $input-error-color 59 | 60 | &.invalid + label:after, &:focus.invalid + label:after 61 | content: attr(data-error) 62 | color: $input-error-color 63 | opacity: 1 64 | 65 | .was-validated 66 | input[type=text] 67 | &:valid 68 | + label 69 | color: $input-success-color !important 70 | 71 | &:invalid 72 | + label 73 | color: $input-error-color !important 74 | 75 | .form-control 76 | &:valid:focus 77 | box-shadow: 0 1px 0 0 $input-success-color !important 78 | 79 | &:valid 80 | border-color: $input-success-color !important 81 | 82 | &:invalid:focus 83 | box-shadow: 0 1px 0 0 $input-error-color !important 84 | 85 | &:invalid 86 | border-color: $input-error-color !important 87 | 88 | // Input with label 89 | .form-control 90 | margin: 0 0 $input-form-control-margin-bottom 0 91 | border-radius: 0 92 | padding: $input-form-control-padding-top 0 $input-form-control-padding-bottom 0 93 | background-image: none 94 | background-color: transparent 95 | 96 | &:focus 97 | box-shadow: none 98 | background: transparent 99 | 100 | &:disabled, 101 | &[readonly] 102 | border-bottom: 1px solid $grey-lighten-1 103 | background-color: transparent 104 | 105 | +make-input($input-label-font-size, $input-label-active-font-size, $input-prefix-top, $input-prefix-font-size, $input-prefix-margin-left, $input-prefix-width, $input-form-text-ml) 106 | 107 | position: relative 108 | margin-top: $input-md-form-margin-top 109 | margin-bottom: $input-md-form-margin-bottom 110 | 111 | label 112 | position: absolute 113 | top: $input-label-top 114 | left: 0 115 | transition: $input-label-transition 116 | cursor: text 117 | color: $input-label-color 118 | 119 | &.active 120 | transform: $input-label-active-transform 121 | 122 | .prefix 123 | position: absolute 124 | transition: $input-prefix-transition 125 | 126 | &.active 127 | color: $input-md-focus-color 128 | 129 | &.form-lg 130 | +make-input($input-label-font-size-lg, $input-label-active-font-size-lg, $input-prefix-top-lg, $input-prefix-font-size-lg, $input-prefix-margin-left-lg, $input-prefix-width-lg, $input-form-text-ml-lg) 131 | 132 | &.form-sm 133 | +make-input($input-label-font-size-sm, $input-label-active-font-size-sm, $input-prefix-top-sm, $input-prefix-font-size-sm, $input-prefix-margin-left-sm, $input-prefix-width-sm, $input-form-text-ml-sm) 134 | 135 | // Textarea 136 | textarea 137 | &.md-textarea 138 | overflow-y: hidden 139 | padding: $textarea-padding 0 140 | resize: none 141 | 142 | &.md-textarea-auto 143 | padding: 0 144 | padding-top: $textarea-padding 145 | -------------------------------------------------------------------------------- /frontend/src/page/product/product.pug: -------------------------------------------------------------------------------- 1 | extends /template/base/base 2 | 3 | include /atom/price/price 4 | include /molecule/productMedia/productMedia 5 | include /atom/dropdown/dropdown 6 | include /organism/productList/productList 7 | 8 | block maincontent 9 | //- Detect the baseData of the product depending on its context 10 | - var baseData = product.baseData 11 | 12 | //+debug(baseData) 13 | //+debug(product.saleableData) 14 | main.mt-5.pt-4 15 | .container.dark-grey-text.mt-5 16 | // Grid row 17 | .row.wow.fadeIn 18 | // Grid column 19 | .col-md-6.mb-4 20 | each mediaItem in baseData.media 21 | if mediaItem.usage === 'detail' || mediaItem.usage === 'gallery' 22 | +productMedia(mediaItem, '700x').media.img-fluid 23 | // Grid column 24 | // Grid column 25 | .col-md-6.mb-4 26 | // Content 27 | .p-4 28 | .mb-3 29 | - var i = 1 30 | each categoryTeaser in product.baseData.categories 31 | - var i = i + 1 32 | if i<4 33 | a(href='') 34 | span.badge.purple.mr-1=categoryTeaser.name 35 | 36 | p.lead 37 | +price(product) 38 | p.lead.font-weight-bold=baseData.title 39 | p !{baseData.description} 40 | if product.baseData.hasAttribute("colour") 41 | p Colour: #{product.baseData.attribute("colour").value} 42 | 43 | if product.type() == "configurable" || product.type() == "configurable_with_activevariant" 44 | .row.p-3 45 | span.col-small=__("select_variant").setDefaultLabel("select a variant:") 46 | .col 47 | +dropdown()(name="variant-selector" id="variant-selector" data-qa="productVariants") 48 | each variant in product.variants 49 | - var configurableActiveVariant = product.getConfigurableWithActiveVariant(variant.baseData.marketPlaceCode) 50 | - var configurableActiveVariantUrl = getProductUrl(configurableActiveVariant) 51 | - var selected = false 52 | if product.type() == "configurable_with_activevariant" 53 | if product.activeVariant.baseData.marketPlaceCode == variant.baseData.marketPlaceCode 54 | - var selected = true 55 | if selected 56 | option(value=variant.baseData.marketPlaceCode data-url=configurableActiveVariantUrl selected="selected")= variant.baseData.title 57 | else 58 | option(value=variant.baseData.marketPlaceCode data-url=configurableActiveVariantUrl)= variant.baseData.title 59 | 60 | if product.isSaleable 61 | form.d-flex.justify-content-left(action=url('cart.add',{marketplaceCode:baseData.marketPlaceCode})) 62 | // Default input 63 | input.form-control(type='number', value='1', aria-label='Search', style='width: 100px', name="qty") 64 | button.btn.btn-primary.btn-md.my-0.p(type='submit') 65 | | Add for home delivery 66 | i.fa.fa-shopping-cart.ml-1 67 | button.btn.btn-primary.btn-md.my-0.p(type='submit', name="deliveryCode", value="pickup_store") 68 | | Add for pickup 69 | i.fa.fa-shopping-cart.ml-1 70 | else 71 | p=__("not saleable") 72 | // Content 73 | // Grid column 74 | // Grid row 75 | hr 76 | // Grid row 77 | .row.d-flex.justify-content-center.wow.fadeIn 78 | // Grid column 79 | .col-md-6.text-center 80 | h4.my-4.h4=__("Additional information") 81 | - var attributeKeysForDisplay = config('template.product.descriptionAttributes') 82 | each attributeKey in attributeKeysForDisplay 83 | if baseData.hasAttribute(attributeKey) && baseData.attributes[attributeKey].value !== '' 84 | dt.productDetailsAttribute 85 | strong= __('attribute.' + attributeKey, attributeKey) + ':' 86 | dd.productDetailsAttributeData 87 | - var formattedValue = stripTags(baseData.attributes[attributeKey].value) 88 | = __('attribute.' + attributeKey + '.value.' + baseData.attributes[attributeKey].value, formattedValue) 89 | // Grid column 90 | // Grid row 91 | // Grid row 92 | .row.wow.fadeIn 93 | h4.my-4.h4=__("Other products") 94 | - var filterByCategory = "headphone_accessories" 95 | if baseData.mainCategory.code != "" 96 | - var filterByCategory = baseData.mainCategory.code 97 | +productListByProductSearchResult(findProducts("homepagewidget",{"query":"","pageSize": "4","sortDirection":"A","sortBy":'random'},{"categories":[filterByCategory]})) -------------------------------------------------------------------------------- /translations/merged/de-de.untranslated.yaml: -------------------------------------------------------------------------------- 1 | cart.button.continueShopping: 2 | other: Continue Shopping 3 | cart.button.reserveAndCollect: 4 | other: Reserve & Collect 5 | cart.column.price: 6 | other: Price 7 | cart.column.quantity: 8 | other: Quantity 9 | cart.column.sum: 10 | other: Sum 11 | cart.group.title: 12 | other: products 13 | cart.item.detail: 14 | other: 'SKU: {{ .SKU }}' 15 | cart.item.remove: 16 | other: remove item 17 | cart.loyalty.label: 18 | other: Heathrow Reward points 19 | cart.reserveInfo.collectedAtShop: 20 | other: The items must be paid for and collected at the shop you have made the purchase from on your day of travel, prior to flying. 21 | cart.reserveInfo.individualStorePolicy: 22 | other: Reservations will be confirmed in accordance with individual store policy, which our customer service team will verify to you. 23 | cart.reserveInfo.noPayment: 24 | other: No payment is taken and you have no obligation to purchase your reserved shopping requests if you change your mind. 25 | cart.total.label: 26 | other: Total 27 | checkout.back_to_cart: 28 | other: Back to cart 29 | checkout.cart_item_error_hint: 30 | other: There are invalid items in your cart. Please check below and resolve the issue. 31 | checkout.error.terms_and_conditions_required: 32 | other: Please accept the terms and conditions. 33 | checkout.legalConfirmation.termsAndConditions: 34 | other: Check here to indicate that you have read and agree to the privacy policies and terms and conditions of the Heathrow Boutique. 35 | checkout.no_items_in_cart: 36 | other: No Items in your cart 37 | checkout.success_message1: 38 | other: 'Your order has been received. Your order number is: {{.OrderId}}' 39 | checkout.success_message2: 40 | other: An confirmation email will be send to {{.Email}}. 41 | delivery: 42 | other: Home delivery 43 | error.404.headline: 44 | other: Error 404 45 | error.503.headline: 46 | other: Error 503 47 | error.common.headline: 48 | other: Error occured 49 | error.homeButton: 50 | other: Back to home 51 | facet.header.brandCode: 52 | other: Brand 53 | miniCart.buttonCartView: 54 | other: Shopping Bag 55 | miniCart.buttonReserveAndCollect: 56 | other: Reserve & Collect 57 | miniCart.empty: 58 | other: Your cart is empty 59 | miniCart.hiddenProduct: 60 | other: 1 more product 61 | miniCart.hiddenProducts: 62 | other: '{{.qty}} more products' 63 | miniCart.removeItem: 64 | other: Remove {{.title}} 65 | miniCart.total: 66 | other: 'Total: {{.total}}' 67 | pickup_store: 68 | other: Instore pickup 69 | product.attribute.__group_packageSizes: 70 | other: Package size 71 | product.attribute.baseColor: 72 | other: Base color 73 | product.attribute.manufacturerColor: 74 | other: Manufacturer color 75 | product.attribute.washingInstructions: 76 | other: Washing Instruction 77 | search.footer.callNow: 78 | other: Call now +44 (0)800 678 5324 79 | search.footer.description: 80 | other: Our Shopping Services team are available to answer any questions that you have about brands, products or services at Heathrow. 81 | search.footer.headline: 82 | other: Can’t see what you want? 83 | search.found.brands: 84 | other: Found in Brands 85 | search.found.other: 86 | other: Other results (%s) 87 | search.found.products: 88 | other: Found in Products ({{ .numResults }}) 89 | search.live.brands: 90 | other: Brands 91 | search.live.contentPages: 92 | other: Content pages 93 | search.live.inRetailers: 94 | other: in retailers 95 | search.live.input.aria: 96 | other: Search website 97 | search.live.input.placeholder: 98 | other: Search 99 | search.live.label: 100 | other: Search 101 | search.live.noResults: 102 | other: Sorry, there are no results matching your query. 103 | search.live.popular: 104 | other: Popular searches 105 | search.live.products: 106 | other: Found products 107 | search.live.reset: 108 | other: Reset search 109 | search.live.results: 110 | other: Search results 111 | search.live.retailers: 112 | other: Retailers 113 | search.live.showAll: 114 | other: Show all results 115 | search.live.submit.aria: 116 | other: Submit search 117 | search.live.totalResults: 118 | other: Total results 119 | search.noresult.titleWithQuery: 120 | other: No results for "{{ .query }}" 121 | search.noresult.widgetHeadline: 122 | other: Trending Results 123 | search.result.title: 124 | other: Search results 125 | search.result.titleWithQuery: 126 | other: Search results for "{{ .query }}" 127 | search.suggestion.title: 128 | other: Here are some results for "{{ .query }}" 129 | searchNoResultsHeader.buttonLabel: 130 | other: Search again 131 | searchNoResultsHeader.text: 132 | other: Please check for misspellings or broaden your search by using fewer keywords.
Alternatively, browse our products by selecting a category from the menu. 133 | searchNoResultsHeader.title: 134 | other: We couldn't find any results
that match your search 135 | -------------------------------------------------------------------------------- /translations/merged/en-gb.all.yaml: -------------------------------------------------------------------------------- 1 | cart.button.continueShopping: 2 | other: Continue Shopping 3 | cart.button.reserveAndCollect: 4 | other: Reserve & Collect 5 | cart.column.price: 6 | other: Price 7 | cart.column.quantity: 8 | other: Quantity 9 | cart.column.sum: 10 | other: Sum 11 | cart.group.title: 12 | other: products 13 | cart.item.detail: 14 | other: 'SKU: {{ .SKU }}' 15 | cart.item.remove: 16 | other: remove item 17 | cart.loyalty.label: 18 | other: Heathrow Reward points 19 | cart.reserveInfo.collectedAtShop: 20 | other: The items must be paid for and collected at the shop you have made the purchase from on your day of travel, prior to flying. 21 | cart.reserveInfo.individualStorePolicy: 22 | other: Reservations will be confirmed in accordance with individual store policy, which our customer service team will verify to you. 23 | cart.reserveInfo.noPayment: 24 | other: No payment is taken and you have no obligation to purchase your reserved shopping requests if you change your mind. 25 | cart.total.label: 26 | other: Total 27 | checkout.back_to_cart: 28 | other: Back to cart 29 | checkout.cart_item_error_hint: 30 | other: There are invalid items in your cart. Please check below and resolve the issue. 31 | checkout.error.terms_and_conditions_required: 32 | other: Please accept the terms and conditions. 33 | checkout.legalConfirmation.termsAndConditions: 34 | other: Check here to indicate that you have read and agree to the privacy policies and terms and conditions of the Heathrow Boutique. 35 | checkout.no_items_in_cart: 36 | other: No Items in your cart 37 | checkout.success_message1: 38 | other: 'Your order has been received. Your order number is: {{.OrderId}}' 39 | checkout.success_message2: 40 | other: An confirmation email will be send to {{.Email}}. 41 | delivery: 42 | other: Home delivery 43 | error.404.headline: 44 | other: Error 404 45 | error.503.headline: 46 | other: Error 503 47 | error.common.headline: 48 | other: Error occured 49 | error.homeButton: 50 | other: Back to home 51 | facet.header.brandCode: 52 | other: Brand 53 | header.welcome.subtitle: 54 | other: Standard demo shop with carotene templates 55 | miniCart.buttonCartView: 56 | other: Shopping Bag 57 | miniCart.buttonReserveAndCollect: 58 | other: Reserve & Collect 59 | miniCart.empty: 60 | other: Your cart is empty 61 | miniCart.hiddenProduct: 62 | other: 1 more product 63 | miniCart.hiddenProducts: 64 | other: '{{.qty}} more products' 65 | miniCart.removeItem: 66 | other: Remove {{.title}} 67 | miniCart.total: 68 | other: 'Total: {{.total}}' 69 | pickup_store: 70 | other: Instore pickup 71 | product.attribute.__group_packageSizes: 72 | other: Package size 73 | product.attribute.baseColor: 74 | other: Base color 75 | product.attribute.manufacturerColor: 76 | other: Manufacturer color 77 | product.attribute.washingInstructions: 78 | other: Washing Instruction 79 | search.footer.callNow: 80 | other: Call now +44 (0)800 678 5324 81 | search.footer.description: 82 | other: Our Shopping Services team are available to answer any questions that you have about brands, products or services at Heathrow. 83 | search.footer.headline: 84 | other: Can’t see what you want? 85 | search.found.brands: 86 | other: Found in Brands 87 | search.found.other: 88 | other: Other results (%s) 89 | search.found.products: 90 | other: Found in Products ({{ .numResults }}) 91 | search.live.brands: 92 | other: Brands 93 | search.live.contentPages: 94 | other: Content pages 95 | search.live.inRetailers: 96 | other: in retailers 97 | search.live.input.aria: 98 | other: Search website 99 | search.live.input.placeholder: 100 | other: Search 101 | search.live.label: 102 | other: Search 103 | search.live.noResults: 104 | other: Sorry, there are no results matching your query. 105 | search.live.popular: 106 | other: Popular searches 107 | search.live.products: 108 | other: Found products 109 | search.live.reset: 110 | other: Reset search 111 | search.live.results: 112 | other: Search results 113 | search.live.retailers: 114 | other: Retailers 115 | search.live.showAll: 116 | other: Show all results 117 | search.live.submit.aria: 118 | other: Submit search 119 | search.live.totalResults: 120 | other: Total results 121 | search.noresult.titleWithQuery: 122 | other: No results for "{{ .query }}" 123 | search.noresult.widgetHeadline: 124 | other: Trending Results 125 | search.result.title: 126 | other: Search results 127 | search.result.titleWithQuery: 128 | other: Search results for "{{ .query }}" 129 | search.suggestion.title: 130 | other: Here are some results for "{{ .query }}" 131 | searchNoResultsHeader.buttonLabel: 132 | other: Search again 133 | searchNoResultsHeader.text: 134 | other: Please check for misspellings or broaden your search by using fewer keywords.
Alternatively, browse our products by selecting a category from the menu. 135 | searchNoResultsHeader.title: 136 | other: We couldn't find any results
that match your search 137 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/free/_animations-basic.sass: -------------------------------------------------------------------------------- 1 | /*! 2 | * animate.css -http://daneden.me/animate 3 | * Version - 3.6.0 4 | * Licensed under the MIT license - http://opensource.org/licenses/MIT 5 | * 6 | * Copyright (c) 2018 Daniel Eden 7 | 8 | .animated 9 | -webkit-animation-duration: 1s 10 | animation-duration: 1s 11 | -webkit-animation-fill-mode: both 12 | animation-fill-mode: both 13 | 14 | .animated.infinite 15 | -webkit-animation-iteration-count: infinite 16 | animation-iteration-count: infinite 17 | 18 | @-webkit-keyframes fadeIn 19 | from 20 | opacity: 0 21 | 22 | to 23 | opacity: 1 24 | 25 | @keyframes fadeIn 26 | from 27 | opacity: 0 28 | 29 | to 30 | opacity: 1 31 | 32 | .fadeIn 33 | -webkit-animation-name: fadeIn 34 | animation-name: fadeIn 35 | 36 | @-webkit-keyframes fadeInDown 37 | from 38 | opacity: 0 39 | -webkit-transform: translate3d(0, -100%, 0) 40 | transform: translate3d(0, -100%, 0) 41 | 42 | to 43 | opacity: 1 44 | -webkit-transform: translate3d(0, 0, 0) 45 | transform: translate3d(0, 0, 0) 46 | 47 | @keyframes fadeInDown 48 | from 49 | opacity: 0 50 | -webkit-transform: translate3d(0, -100%, 0) 51 | transform: translate3d(0, -100%, 0) 52 | 53 | to 54 | opacity: 1 55 | -webkit-transform: translate3d(0, 0, 0) 56 | transform: translate3d(0, 0, 0) 57 | 58 | .fadeInDown 59 | -webkit-animation-name: fadeInDown 60 | animation-name: fadeInDown 61 | 62 | @-webkit-keyframes fadeInLeft 63 | from 64 | opacity: 0 65 | -webkit-transform: translate3d(-100%, 0, 0) 66 | transform: translate3d(-100%, 0, 0) 67 | 68 | to 69 | opacity: 1 70 | -webkit-transform: translate3d(0, 0, 0) 71 | transform: translate3d(0, 0, 0) 72 | 73 | @keyframes fadeInLeft 74 | from 75 | opacity: 0 76 | -webkit-transform: translate3d(-100%, 0, 0) 77 | transform: translate3d(-100%, 0, 0) 78 | 79 | to 80 | opacity: 1 81 | -webkit-transform: translate3d(0, 0, 0) 82 | transform: translate3d(0, 0, 0) 83 | 84 | .fadeInLeft 85 | -webkit-animation-name: fadeInLeft 86 | animation-name: fadeInLeft 87 | 88 | @-webkit-keyframes fadeInRight 89 | from 90 | opacity: 0 91 | -webkit-transform: translate3d(100%, 0, 0) 92 | transform: translate3d(100%, 0, 0) 93 | 94 | to 95 | opacity: 1 96 | -webkit-transform: translate3d(0, 0, 0) 97 | transform: translate3d(0, 0, 0) 98 | 99 | @keyframes fadeInRight 100 | from 101 | opacity: 0 102 | -webkit-transform: translate3d(100%, 0, 0) 103 | transform: translate3d(100%, 0, 0) 104 | 105 | to 106 | opacity: 1 107 | -webkit-transform: translate3d(0, 0, 0) 108 | transform: translate3d(0, 0, 0) 109 | 110 | .fadeInRight 111 | -webkit-animation-name: fadeInRight 112 | animation-name: fadeInRight 113 | 114 | @-webkit-keyframes fadeInUp 115 | from 116 | opacity: 0 117 | -webkit-transform: translate3d(0, 100%, 0) 118 | transform: translate3d(0, 100%, 0) 119 | 120 | to 121 | opacity: 1 122 | -webkit-transform: translate3d(0, 0, 0) 123 | transform: translate3d(0, 0, 0) 124 | 125 | @keyframes fadeInUp 126 | from 127 | opacity: 0 128 | -webkit-transform: translate3d(0, 100%, 0) 129 | transform: translate3d(0, 100%, 0) 130 | 131 | to 132 | opacity: 1 133 | -webkit-transform: translate3d(0, 0, 0) 134 | transform: translate3d(0, 0, 0) 135 | 136 | .fadeInUp 137 | -webkit-animation-name: fadeInUp 138 | animation-name: fadeInUp 139 | 140 | @-webkit-keyframes fadeOut 141 | from 142 | opacity: 1 143 | 144 | to 145 | opacity: 0 146 | 147 | @keyframes fadeOut 148 | from 149 | opacity: 1 150 | 151 | to 152 | opacity: 0 153 | 154 | .fadeOut 155 | -webkit-animation-name: fadeOut 156 | animation-name: fadeOut 157 | 158 | @-webkit-keyframes fadeOutDown 159 | from 160 | opacity: 1 161 | 162 | to 163 | opacity: 0 164 | -webkit-transform: translate3d(0, 100%, 0) 165 | transform: translate3d(0, 100%, 0) 166 | 167 | @keyframes fadeOutDown 168 | from 169 | opacity: 1 170 | 171 | to 172 | opacity: 0 173 | -webkit-transform: translate3d(0, 100%, 0) 174 | transform: translate3d(0, 100%, 0) 175 | 176 | .fadeOutDown 177 | -webkit-animation-name: fadeOutDown 178 | animation-name: fadeOutDown 179 | 180 | @keyframes fadeOutLeft 181 | from 182 | opacity: 1 183 | 184 | to 185 | opacity: 0 186 | -webkit-transform: translate3d(-100%, 0, 0) 187 | transform: translate3d(-100%, 0, 0) 188 | 189 | .fadeOutLeft 190 | -webkit-animation-name: fadeOutLeft 191 | animation-name: fadeOutLeft 192 | 193 | @-webkit-keyframes fadeOutRight 194 | from 195 | opacity: 1 196 | 197 | to 198 | opacity: 0 199 | -webkit-transform: translate3d(100%, 0, 0) 200 | transform: translate3d(100%, 0, 0) 201 | 202 | @keyframes fadeOutRight 203 | from 204 | opacity: 1 205 | 206 | to 207 | opacity: 0 208 | -webkit-transform: translate3d(100%, 0, 0) 209 | transform: translate3d(100%, 0, 0) 210 | 211 | .fadeOutRight 212 | -webkit-animation-name: fadeOutRight 213 | animation-name: fadeOutRight 214 | 215 | @-webkit-keyframes fadeOutUp 216 | from 217 | opacity: 1 218 | 219 | to 220 | opacity: 0 221 | -webkit-transform: translate3d(0, -100%, 0) 222 | transform: translate3d(0, -100%, 0) 223 | 224 | @keyframes fadeOutUp 225 | from 226 | opacity: 1 227 | 228 | to 229 | opacity: 0 230 | -webkit-transform: translate3d(0, -100%, 0) 231 | transform: translate3d(0, -100%, 0) 232 | 233 | .fadeOutUp 234 | -webkit-animation-name: fadeOutUp 235 | animation-name: fadeOutUp 236 | -------------------------------------------------------------------------------- /graphql/schema/flamingo.me_flamingo-commerce_v3_checkout_interfaces_graphql-Service.graphql: -------------------------------------------------------------------------------- 1 | type Commerce_Checkout_StartPlaceOrder_Result { 2 | uuid: String! 3 | } 4 | # Commerce_Checkout_PlaceOrderContext represents the result of the current (running) place order mutation 5 | type Commerce_Checkout_PlaceOrderContext { 6 | # The Cart that is going to be placed 7 | cart: Commerce_Cart_DecoratedCart 8 | # The placed order in case order is already placed 9 | orderInfos: Commerce_Checkout_PlacedOrderInfos 10 | # State depending on the state of payment and place order - state may contain additional infos 11 | state: Commerce_Checkout_PlaceOrderState_State! 12 | # A unique id for the process 13 | uuid: String! 14 | } 15 | 16 | 17 | # Commerce_Checkout_PlacedOrderInfos - infos about the placed orders - typically shown on a suceess page 18 | type Commerce_Checkout_PlacedOrderInfos { 19 | paymentInfos: [Commerce_Checkout_PlaceOrderPaymentInfo!] 20 | placedOrderInfos: [Commerce_Cart_PlacedOrderInfo!] 21 | email: String! 22 | } 23 | 24 | type Commerce_Checkout_PlaceOrderPaymentInfo { 25 | gateway: String! 26 | paymentProvider: String! 27 | method: String! 28 | amount: Commerce_Price! 29 | title: String! 30 | } 31 | 32 | 33 | interface Commerce_Checkout_PlaceOrderState_State { 34 | name: String! 35 | } 36 | 37 | type Commerce_Checkout_PlaceOrderState_State_Wait implements Commerce_Checkout_PlaceOrderState_State { 38 | name: String! 39 | } 40 | 41 | type Commerce_Checkout_PlaceOrderState_State_WaitForCustomer implements Commerce_Checkout_PlaceOrderState_State { 42 | name: String! 43 | } 44 | 45 | type Commerce_Checkout_PlaceOrderState_State_Success implements Commerce_Checkout_PlaceOrderState_State { 46 | name: String! 47 | } 48 | 49 | type Commerce_Checkout_PlaceOrderState_State_Failed implements Commerce_Checkout_PlaceOrderState_State { 50 | name: String! 51 | reason: Commerce_Checkout_PlaceOrderState_State_FailedReason! 52 | } 53 | 54 | type Commerce_Checkout_PlaceOrderState_State_ShowIframe implements Commerce_Checkout_PlaceOrderState_State { 55 | name: String! 56 | URL: String! 57 | } 58 | 59 | type Commerce_Checkout_PlaceOrderState_State_ShowHTML implements Commerce_Checkout_PlaceOrderState_State { 60 | name: String! 61 | HTML: String! 62 | } 63 | 64 | type Commerce_Checkout_PlaceOrderState_State_Redirect implements Commerce_Checkout_PlaceOrderState_State { 65 | name: String! 66 | URL: String! 67 | } 68 | 69 | type Commerce_Checkout_PlaceOrderState_State_TriggerClientSDK implements Commerce_Checkout_PlaceOrderState_State { 70 | name: String! 71 | URL: String! 72 | data: String! 73 | } 74 | 75 | type Commerce_Checkout_PlaceOrderState_State_ShowWalletPayment implements Commerce_Checkout_PlaceOrderState_State { 76 | name: String! 77 | "Wallet payment method that was chosen previously" 78 | paymentMethod: String! 79 | "Information needed to create a payment using the PaymentRequest API" 80 | paymentRequestAPI: Commerce_Checkout_PlaceOrderState_PaymentRequestAPI! 81 | } 82 | 83 | type Commerce_Checkout_PlaceOrderState_PaymentRequestAPI { 84 | "Contains the JSON encoded method data for the PaymentRequest API" 85 | methodData: String! 86 | "Contains the JSON encoded details for the PaymentRequest API" 87 | details: String! 88 | "Contains the JSON encoded options for the PaymentRequest API" 89 | options: String! 90 | "Optional endpoint used for obtaining a merchant session, not set if the wallet payment doesn't require a merchant validation" 91 | merchantValidationURL: String 92 | "Endpoint to sent completed payment to" 93 | completeURL: String! 94 | } 95 | 96 | type Commerce_Checkout_PlaceOrderState_State_PostRedirect implements Commerce_Checkout_PlaceOrderState_State { 97 | name: String! 98 | URL: String! 99 | Parameters: [Commerce_Checkout_PlaceOrderState_Form_Parameter!] 100 | } 101 | 102 | interface Commerce_Checkout_PlaceOrderState_State_FailedReason { 103 | reason: String 104 | } 105 | 106 | 107 | type Commerce_Checkout_PlaceOrderState_State_FailedReason_Error implements Commerce_Checkout_PlaceOrderState_State_FailedReason { 108 | reason: String 109 | } 110 | 111 | type Commerce_Checkout_PlaceOrderState_State_FailedReason_PaymentError implements Commerce_Checkout_PlaceOrderState_State_FailedReason { 112 | reason: String 113 | } 114 | 115 | type Commerce_Checkout_PlaceOrderState_State_FailedReason_CanceledByCustomer implements Commerce_Checkout_PlaceOrderState_State_FailedReason { 116 | reason: String 117 | } 118 | 119 | type Commerce_Checkout_PlaceOrderState_State_FailedReason_PaymentCanceledByCustomer implements Commerce_Checkout_PlaceOrderState_State_FailedReason { 120 | reason: String 121 | } 122 | 123 | type Commerce_Checkout_PlaceOrderState_State_FailedReason_CartValidationError implements Commerce_Checkout_PlaceOrderState_State_FailedReason { 124 | reason: String 125 | validationResult: Commerce_Cart_ValidationResult! 126 | } 127 | 128 | type Commerce_Checkout_PlaceOrderState_Form_Parameter { 129 | key: String! 130 | value: [String!] 131 | } 132 | 133 | extend type Query { 134 | # Is there a active place order process 135 | Commerce_Checkout_ActivePlaceOrder: Boolean! 136 | Commerce_Checkout_CurrentContext: Commerce_Checkout_PlaceOrderContext! 137 | } 138 | 139 | extend type Mutation { 140 | # Starts a new process and will replace existing ones 141 | Commerce_Checkout_StartPlaceOrder(returnUrl: String!): Commerce_Checkout_StartPlaceOrder_Result! 142 | # Cancels to current running place order process, possible if state is not final 143 | Commerce_Checkout_CancelPlaceOrder: Boolean! 144 | # Clears the last stored place order process 145 | Commerce_Checkout_ClearPlaceOrder: Boolean! 146 | # Gets the last stored place order state and ensures that the state machine proceeds, non blocking 147 | Commerce_Checkout_RefreshPlaceOrder: Commerce_Checkout_PlaceOrderContext! 148 | # Gets the most recent place order state by waiting for the state machine to proceed, therefore blocking 149 | Commerce_Checkout_RefreshPlaceOrderBlocking: Commerce_Checkout_PlaceOrderContext! 150 | } 151 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module flamingo.me/commerce-demo-carotene 2 | 3 | go 1.21 4 | 5 | toolchain go1.21.7 6 | 7 | require ( 8 | flamingo.me/dingo v0.2.10 9 | flamingo.me/flamingo-commerce-adapter-standalone v0.0.5-beta 10 | flamingo.me/flamingo-commerce/v3 v3.9.0 11 | flamingo.me/flamingo/v3 v3.8.0 12 | flamingo.me/form v1.1.2 13 | flamingo.me/graphql v1.11.1 14 | flamingo.me/pugtemplate v1.3.1 15 | flamingo.me/swagger v0.0.0-20200904191647-041b9dd247c7 16 | github.com/99designs/gqlgen v0.17.43 17 | github.com/spf13/cobra v1.8.0 18 | github.com/swaggo/swag v1.16.3 19 | github.com/vektah/gqlparser/v2 v2.5.11 20 | ) 21 | 22 | require ( 23 | contrib.go.opencensus.io/exporter/jaeger v0.2.1 // indirect 24 | contrib.go.opencensus.io/exporter/prometheus v0.4.2 // indirect 25 | contrib.go.opencensus.io/exporter/zipkin v0.1.2 // indirect 26 | cuelang.org/go v0.0.15 // indirect 27 | github.com/KyleBanks/depth v1.2.1 // indirect 28 | github.com/RoaringBitmap/roaring v0.4.23 // indirect 29 | github.com/agnivade/levenshtein v1.1.1 // indirect 30 | github.com/beorn7/perks v1.0.1 // indirect 31 | github.com/blevesearch/bleve v1.0.12 // indirect 32 | github.com/blevesearch/go-porterstemmer v1.0.3 // indirect 33 | github.com/blevesearch/mmap-go v1.0.2 // indirect 34 | github.com/blevesearch/segment v0.9.0 // indirect 35 | github.com/blevesearch/snowballstem v0.9.0 // indirect 36 | github.com/blevesearch/zap/v11 v11.0.12 // indirect 37 | github.com/blevesearch/zap/v12 v12.0.12 // indirect 38 | github.com/blevesearch/zap/v13 v13.0.4 // indirect 39 | github.com/blevesearch/zap/v14 v14.0.3 // indirect 40 | github.com/blevesearch/zap/v15 v15.0.1 // indirect 41 | github.com/cespare/xxhash/v2 v2.2.0 // indirect 42 | github.com/cockroachdb/apd v1.1.0 // indirect 43 | github.com/cockroachdb/apd/v2 v2.0.1 // indirect 44 | github.com/couchbase/vellum v1.0.2 // indirect 45 | github.com/davecgh/go-spew v1.1.1 // indirect 46 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect 47 | github.com/disintegration/imaging v1.6.2 // indirect 48 | github.com/etgryphon/stringUp v0.0.0-20121020160746-31534ccd8cac // indirect 49 | github.com/gabriel-vasile/mimetype v1.4.2 // indirect 50 | github.com/ghodss/yaml v1.0.0 // indirect 51 | github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 // indirect 52 | github.com/go-kit/log v0.2.1 // indirect 53 | github.com/go-logfmt/logfmt v0.5.1 // indirect 54 | github.com/go-openapi/jsonpointer v0.19.5 // indirect 55 | github.com/go-openapi/jsonreference v0.20.0 // indirect 56 | github.com/go-openapi/spec v0.20.4 // indirect 57 | github.com/go-openapi/swag v0.19.15 // indirect 58 | github.com/go-playground/form v3.1.4+incompatible // indirect 59 | github.com/go-playground/form/v4 v4.2.1 // indirect 60 | github.com/go-playground/locales v0.14.1 // indirect 61 | github.com/go-playground/universal-translator v0.18.1 // indirect 62 | github.com/go-playground/validator/v10 v10.17.0 // indirect 63 | github.com/go-redsync/redsync/v4 v4.11.0 // indirect 64 | github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect 65 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 66 | github.com/golang/protobuf v1.5.3 // indirect 67 | github.com/golang/snappy v0.0.4 // indirect 68 | github.com/gomodule/redigo v2.0.0+incompatible // indirect 69 | github.com/google/go-cmp v0.6.0 // indirect 70 | github.com/google/uuid v1.6.0 // indirect 71 | github.com/gorilla/securecookie v1.1.2 // indirect 72 | github.com/gorilla/sessions v1.2.2 // indirect 73 | github.com/gorilla/websocket v1.5.0 // indirect 74 | github.com/hashicorp/errwrap v1.1.0 // indirect 75 | github.com/hashicorp/go-multierror v1.1.1 // indirect 76 | github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect 77 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 78 | github.com/josharian/intern v1.0.0 // indirect 79 | github.com/kr/pretty v0.3.1 // indirect 80 | github.com/leebenson/conform v1.2.2 // indirect 81 | github.com/leekchan/accounting v0.3.1 // indirect 82 | github.com/leodido/go-urn v1.2.4 // indirect 83 | github.com/mailru/easyjson v0.7.6 // indirect 84 | github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect 85 | github.com/mitchellh/mapstructure v1.5.0 // indirect 86 | github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de // indirect 87 | github.com/mschoch/smat v0.2.0 // indirect 88 | github.com/nicksnyder/go-i18n v0.0.0-20180814031359-04f547cc50da // indirect 89 | github.com/openzipkin/zipkin-go v0.4.2 // indirect 90 | github.com/pelletier/go-toml v1.9.5 // indirect 91 | github.com/philhofer/fwd v1.0.0 // indirect 92 | github.com/pkg/errors v0.9.1 // indirect 93 | github.com/pmezard/go-difflib v1.0.0 // indirect 94 | github.com/prometheus/client_golang v1.14.0 // indirect 95 | github.com/prometheus/client_model v0.4.0 // indirect 96 | github.com/prometheus/common v0.37.0 // indirect 97 | github.com/prometheus/procfs v0.8.0 // indirect 98 | github.com/prometheus/statsd_exporter v0.22.7 // indirect 99 | github.com/rbcervilla/redisstore/v9 v9.0.0 // indirect 100 | github.com/redis/go-redis/v9 v9.4.0 // indirect 101 | github.com/rogpeppe/go-internal v1.10.0 // indirect 102 | github.com/shopspring/decimal v1.2.0 // indirect 103 | github.com/sosodev/duration v1.1.0 // indirect 104 | github.com/spf13/pflag v1.0.5 // indirect 105 | github.com/steveyen/gtreap v0.1.0 // indirect 106 | github.com/stretchr/objx v0.5.0 // indirect 107 | github.com/stretchr/testify v1.8.4 // indirect 108 | github.com/tinylib/msgp v1.1.0 // indirect 109 | github.com/uber/jaeger-client-go v2.25.0+incompatible // indirect 110 | github.com/willf/bitset v1.1.11 // indirect 111 | github.com/zemirco/memorystore v0.0.0-20160308183530-ecd57e5134f6 // indirect 112 | go.etcd.io/bbolt v1.3.7 // indirect 113 | go.opencensus.io v0.24.0 // indirect 114 | go.uber.org/automaxprocs v1.5.3 // indirect 115 | go.uber.org/multierr v1.10.0 // indirect 116 | go.uber.org/zap v1.26.0 // indirect 117 | golang.org/x/crypto v0.19.0 // indirect 118 | golang.org/x/image v0.0.0-20220302094943-723b81ca9867 // indirect 119 | golang.org/x/mod v0.15.0 // indirect 120 | golang.org/x/net v0.21.0 // indirect 121 | golang.org/x/sync v0.6.0 // indirect 122 | golang.org/x/sys v0.17.0 // indirect 123 | golang.org/x/text v0.14.0 // indirect 124 | golang.org/x/tools v0.13.0 // indirect 125 | golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect 126 | google.golang.org/api v0.126.0 // indirect 127 | google.golang.org/protobuf v1.31.0 // indirect 128 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect 129 | gopkg.in/yaml.v2 v2.4.0 // indirect 130 | gopkg.in/yaml.v3 v3.0.1 // indirect 131 | ) 132 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/free/_modals.sass: -------------------------------------------------------------------------------- 1 | // Modals 2 | // Styles for body 3 | body 4 | &.modal-open 5 | overflow: auto 6 | padding-right: 0 !important 7 | 8 | &.scrollable 9 | overflow-y: auto 10 | 11 | // *** ENHANCED BOOTSTRAP MODALS ***/// 12 | // General styles 13 | .modal-dialog 14 | .modal-content 15 | box-shadow: $z-depth-1-half 16 | border: 0 17 | border-radius: $border-radius-base 18 | 19 | .modal-header 20 | border-top-left-radius: $border-radius-base 21 | border-top-right-radius: $border-radius-base 22 | 23 | // Cascading modals 24 | &.cascading-modal 25 | margin-top: 10% 26 | 27 | .close 28 | opacity: 1 29 | text-shadow: none 30 | color: $white-base 31 | outline: 0 32 | 33 | // Cascading header 34 | .modal-header 35 | box-shadow: $z-depth-1-half 36 | margin: $cascading-modal-margin-top $cascading-modal-margin-right $cascading-modal-margin-bottom $cascading-modal-margin-left 37 | border: none 38 | border-radius: $border-radius-base 39 | padding: $cascading-modal-padding 40 | text-align: center 41 | 42 | .close 43 | margin-right: $cascading-modal-close-margin-right 44 | 45 | .title 46 | margin-bottom: 0 47 | width: 100% 48 | font-size: $cascading-modal-font-size 49 | 50 | .fa 51 | margin-right: $cascading-modal-fa-margin-right 52 | 53 | .social-buttons 54 | margin-top: $cascading-modal-social-margin-top 55 | 56 | a 57 | font-size: $cascading-modal-a-font-size 58 | 59 | // Cascading tabs nav 60 | .modal-c-tabs 61 | .nav-tabs 62 | box-shadow: $z-depth-1 63 | margin: $cascading-modal-tabs-margin-top $cascading-modal-tabs-margin-x 0 $cascading-modal-tabs-margin-x 64 | 65 | .tab-content 66 | padding: $cascading-modal-tabs-padding-top 0 0 0 67 | 68 | .nav-tabs 69 | display: flex 70 | 71 | li 72 | flex: 1 73 | 74 | a 75 | text-align: center 76 | 77 | // Footer customization 78 | .modal-body, 79 | .modal-footer 80 | padding-left: $modal-body-padding-left 81 | padding-right: $modal-body-padding-right 82 | color: $grey-darken-2 83 | 84 | .additional-option 85 | margin-top: $modal-body-margin-top 86 | text-align: center 87 | 88 | // Cascading avatar 89 | &.modal-avatar 90 | margin-top: $modal-avatar-margin-top 91 | 92 | .modal-header 93 | box-shadow: none 94 | 95 | @extend .img-fluid 96 | 97 | margin: $modal-avatar-header-margin-top 0 $modal-avatar-header-margin-bottom 98 | 99 | img 100 | width: $modal-avatar-img-width 101 | box-shadow: $z-depth-2 102 | margin-left: auto 103 | margin-right: auto 104 | 105 | // Modal notify 106 | &.modal-notify 107 | .heading 108 | margin: 0 109 | padding: $modal-notify-heading-padding 110 | font-size: $modal-notify-font-size 111 | color: $white-base 112 | 113 | .modal-header 114 | box-shadow: $z-depth-1 115 | border: 0 116 | 117 | .close 118 | opacity: 1 119 | 120 | .modal-body 121 | padding: $modal-notify-body-padding 122 | color: $grey-darken-2 123 | 124 | @each $name, $color in $basic 125 | &.modal-#{$name} 126 | .modal-header 127 | background-color: $color 128 | 129 | .fa 130 | color: $color 131 | 132 | .badge 133 | background-color: $color 134 | 135 | // Position & Size 136 | .modal 137 | padding-right: 0 !important 138 | 139 | .modal-dialog 140 | @media (min-width: 768px) 141 | &.modal-top 142 | top: 0 143 | 144 | &.modal-left 145 | left: 0 146 | 147 | &.modal-right 148 | right: 0 149 | 150 | &.modal-bottom 151 | bottom: 0 152 | 153 | &.modal-top-left 154 | top: $modal-distance 155 | left: $modal-distance 156 | 157 | &.modal-top-right 158 | top: $modal-distance 159 | right: $modal-distance 160 | 161 | &.modal-bottom-left 162 | bottom: $modal-distance 163 | left: $modal-distance 164 | 165 | &.modal-bottom-right 166 | bottom: $modal-distance 167 | right: $modal-distance 168 | 169 | &.fade 170 | &.top:not(.show) .modal-dialog 171 | transform: $modal-fade-top-transform 172 | 173 | &.left:not(.show) .modal-dialog 174 | transform: $modal-fade-left-transform 175 | 176 | &.right:not(.show) .modal-dialog 177 | transform: $modal-fade-right-transform 178 | 179 | &.bottom:not(.show) .modal-dialog 180 | transform: $modal-fade-bottom-transform 181 | 182 | @media (min-width: $medium-screen) 183 | &.modal-scrolling 184 | position: relative 185 | 186 | .modal-dialog 187 | position: fixed 188 | z-index: 1050 189 | 190 | &.modal-content-clickable 191 | top: auto 192 | bottom: auto 193 | 194 | .modal-dialog 195 | position: fixed 196 | 197 | .modal-fluid 198 | width: 100% 199 | max-width: 100% 200 | 201 | .modal-content 202 | width: 100% 203 | 204 | .modal-frame 205 | position: absolute 206 | margin: 0 207 | width: 100% 208 | max-width: 100% 209 | 210 | &.modal-bottom 211 | bottom: 0 212 | 213 | .modal-full-height 214 | position: absolute 215 | display: flex 216 | margin: 0 217 | width: $modal-width 218 | height: 100% 219 | top: 0 220 | right: 0 221 | 222 | &.modal-top, 223 | &.modal-bottom 224 | display: block 225 | width: 100% 226 | max-width: 100% 227 | height: auto 228 | 229 | &.modal-top 230 | bottom: auto 231 | 232 | &.modal-bottom 233 | top: auto 234 | 235 | .modal-content 236 | width: 100% 237 | 238 | &.modal-lg 239 | width: 90% 240 | max-width: 90% 241 | 242 | @media (min-width: $medium-screen) 243 | width: $modal-full-height-medium-screen 244 | max-width: $modal-full-height-medium-screen 245 | 246 | @media (min-width: $large-screen) 247 | width: $modal-full-height-large-screen 248 | max-width: $modal-full-height-large-screen 249 | 250 | .modal-side 251 | position: absolute 252 | bottom: $modal-distance 253 | right: $modal-distance 254 | margin: 0 255 | width: $modal-width 256 | 257 | .nav-tabs 258 | border-radius: $md-card-border-radius 259 | 260 | .nav-item 261 | .nav-link 262 | border-radius: $md-card-border-radius 263 | background-color: inherit 264 | color: $white-base 265 | -------------------------------------------------------------------------------- /frontend/src/page/checkout/organism/checkoutform.pug: -------------------------------------------------------------------------------- 1 | form(method="post") 2 | h4.d-flex.justify-content-between.align-items-center.mb-3 3 | span.text-muted Billing Address #{form.hasGeneralErrors} 4 | 5 | if form.hasAnyGeneralErrors 6 | each error in form.getAllGeneralErrors 7 | div.alert.alert-error(role="alert", data-error=error.messageKey)=error.defaultLabel 8 | div.card 9 | - var billingForm = form.billingAddressForm 10 | .card-body 11 | div.row 12 | div.col-md-6.mb-2 13 | div.md-form 14 | +inputField("billingAddress","firstname","First Name", billingForm, billingForm.data.firstname) 15 | +fieldError("firstname",billingForm) 16 | div.col-md-6.mb-2 17 | div.md-form 18 | +inputField("billingAddress","lastname","Last Name", billingForm,billingForm.data.lastname) 19 | +fieldError("lastname",billingForm) 20 | div.row 21 | div.col-md-10.mb-2 22 | div.md-form 23 | +inputField("billingAddress","street","Street", billingForm,billingForm.data.street) 24 | +fieldError("street",billingForm) 25 | div.col-md-2.mb-2 26 | div.md-form 27 | +inputField("billingAddress","streetNr","Nr", billingForm,billingForm.data.streetNr) 28 | +fieldError("streetNr",billingForm) 29 | div.row 30 | div.col-md-4.mb-2 31 | div.md-form 32 | +inputField("billingAddress","postCode","Post code", billingForm,billingForm.data.postCode) 33 | +fieldError("postCode",billingForm) 34 | div.col-md-8.mb-2 35 | div.md-form 36 | +inputField("billingAddress","city","City", billingForm,billingForm.data.city) 37 | +fieldError("city",billingForm) 38 | div.md-form.mb-5 39 | +inputField("billingAddress","email","E-Mail", billingForm,billingForm.data.email) 40 | +fieldError("email",billingForm) 41 | 42 | 43 | each delivery in decoratedCart.cart.deliveries 44 | - var deliveryCode = delivery.deliveryInfo.code 45 | - var deliveryForm = form.deliveryForms[deliveryCode] 46 | - var formFieldNameSpace = "deliveries."+deliveryCode 47 | h4(data-deliverycode=delivery.deliveryInfo.code).d-flex.justify-content-between.align-items-center.m-3 48 | span.text-muted=__(delivery.deliveryInfo.code) 49 | 50 | if deliveryCode == "delivery" 51 | div.card(class=deliveryCode) 52 | .card-body 53 | div.custom-control.custom-checkbox 54 | if deliveryForm.data.useBillingAddress == true 55 | input.custom-control-input(name=formFieldNameSpace+".useBillingAddress", type="checkbox", id="useBillingAddress", checked="checked") 56 | else 57 | input.custom-control-input(name=formFieldNameSpace+".useBillingAddress", type="checkbox", id="useBillingAddress") 58 | label.custom-control-label(for="useBillingAddress") Use billing address as shipping address 59 | div(id="useBillingAddressToggle", class="collapse show") 60 | div.row 61 | div.col-md-6.mb-2 62 | div.md-form 63 | +inputField(formFieldNameSpace,"deliveryAddress.firstname","First Name", deliveryForm,deliveryForm.data.deliveryAddress.firstname) 64 | +fieldError("deliveryAddress.firstname",deliveryForm) 65 | div.col-md-6.mb-2 66 | div.md-form 67 | +inputField(formFieldNameSpace,"deliveryAddress.lastname","Last Name", deliveryForm, deliveryForm.data.deliveryAddress.lastname) 68 | +fieldError("deliveryAddress.lastname",deliveryForm) 69 | div.row 70 | div.col-md-10.mb-2 71 | div.md-form 72 | +inputField(formFieldNameSpace,"deliveryAddress.street","Street", deliveryForm,deliveryForm.data.deliveryAddress.street) 73 | +fieldError("deliveryAddress.street",deliveryForm) 74 | div.col-md-2.mb-2 75 | div.md-form 76 | +inputField(formFieldNameSpace,"deliveryAddress.streetNr","Nr", deliveryForm,deliveryForm.data.deliveryAddress.streetNr) 77 | +fieldError("deliveryAddress.streetNr",deliveryForm) 78 | div.row 79 | div.col-md-4.mb-2 80 | div.md-form 81 | +inputField(formFieldNameSpace,"deliveryAddress.postCode","Post code", deliveryForm,deliveryForm.data.deliveryAddress.postCode) 82 | +fieldError("deliveryAddress.postCode",deliveryForm) 83 | div.col-md-8.mb-2 84 | div.md-form 85 | +inputField(formFieldNameSpace,"deliveryAddress.city","City", billingForm,deliveryForm.data.deliveryAddress.city) 86 | +fieldError("deliveryAddress.city",deliveryForm) 87 | div.md-form.mb-5 88 | +inputField(formFieldNameSpace,"deliveryAddress.email","E-Mail", billingForm,deliveryForm.data.deliveryAddress.email) 89 | +fieldError("deliveryAddress.email",deliveryForm) 90 | hr.mb-4 91 | 92 | if deliveryCode == "pickup_store" 93 | div.card 94 | .card-body 95 | p You can pick your products directly in the store. 96 | input(name=formFieldNameSpace + ".useBillingAddress", type="hidden", value="1") 97 | hr.mb-4 98 | h4(data-deliverycode=decoratedDelivery.delivery.deliveryInfo.code).d-flex.justify-content-between.align-items-center.m-3 99 | span.text-muted Payment 100 | div.card 101 | .card-body 102 | each methods, gateway in availablePayments 103 | div.d-block.my-3 104 | h5=gateway 105 | input(type="hidden", name="payment.gateway", value=gateway) 106 | +fieldError("method", form.simplePaymentForm) 107 | each method in methods 108 | .custom-control.custom-radio 109 | if form.simplePaymentForm.data.method == method.code 110 | input.custom-control-input(id=method.code, name="payment.method", value=method.code, type="radio", checked="checked", required="1") 111 | else 112 | input.custom-control-input(id=method.code, name="payment.method", value=method.code, type="radio", required="1") 113 | label.custom-control-label(for=method.code)=method.title 114 | button.btn.btn-primary.btn-lg.btn-block.waves-effect.waves-light.mt-2(type="submit") Continue to review 115 | 116 | 117 | mixin inputField(formNameSpace, fieldNameInForm, label, form, currentValue) 118 | - var nameSpacedFieldName = formNameSpace+"."+fieldNameInForm 119 | if form.hasErrorForField(fieldNameInForm) 120 | input(type="text", id=nameSpacedFieldName, name=nameSpacedFieldName, class="form-control is-invalid", value=currentValue) 121 | label(for=nameSpacedFieldName)=label 122 | else 123 | input(type="text", id=nameSpacedFieldName, name=nameSpacedFieldName, class="form-control", value=currentValue) 124 | label(for=nameSpacedFieldName)=label 125 | 126 | 127 | mixin fieldError(fieldNameInForm, form) 128 | if form.hasErrorForField(fieldNameInForm) 129 | div.invalid-feedback 130 | each fieldError in form.getErrorsForField(fieldNameInForm) 131 | span=fieldError.defaultLabel 132 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/core/_mixins.sass: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // Bootstrap Mixins 3 | @function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) 4 | $n: index($breakpoint-names, $name) 5 | 6 | @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null) 7 | 8 | @function breakpoint-min($name, $breakpoints: $grid-breakpoints) 9 | $min: map-get($breakpoints, $name) 10 | 11 | @return if($min != 0, $min, null) 12 | 13 | @function breakpoint-max($name, $breakpoints: $grid-breakpoints) 14 | $next: breakpoint-next($name, $breakpoints) 15 | 16 | @return if($next, breakpoint-min($next, $breakpoints) - 0.02px, null) 17 | 18 | // Media of at least the minimum breakpoint width. No query for the smallest breakpoint. 19 | // Makes the @content apply to the given breakpoint and wider. 20 | =media-breakpoint-up($name, $breakpoints: $grid-breakpoints) 21 | $min: breakpoint-min($name, $breakpoints) 22 | 23 | @if $min 24 | @media (min-width: $min) 25 | @content 26 | @else 27 | @content 28 | 29 | // Media of at most the maximum breakpoint width. No query for the largest breakpoint. 30 | // Makes the @content apply to the given breakpoint and narrower. 31 | =media-breakpoint-down($name, $breakpoints: $grid-breakpoints) 32 | $max: breakpoint-max($name, $breakpoints) 33 | 34 | @if $max 35 | @media (max-width: $max) 36 | @content 37 | @else 38 | @content 39 | 40 | // Media that spans multiple breakpoint widths. 41 | // Makes the @content apply between the min and max breakpoints 42 | =media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) 43 | $min: breakpoint-min($lower, $breakpoints) 44 | $max: breakpoint-max($upper, $breakpoints) 45 | 46 | @if $min != null and $max != null 47 | @media (min-width: $min) and (max-width: $max) 48 | @content 49 | @else if $max == null 50 | +media-breakpoint-up($lower, $breakpoints) 51 | @content 52 | @else if $min == null 53 | +media-breakpoint-down($upper, $breakpoints) 54 | @content 55 | 56 | // Media between the breakpoint's minimum and maximum widths. 57 | // No minimum for the smallest breakpoint, and no maximum for the largest one. 58 | // Makes the @content apply only to the given breakpoint, not viewports any wider or narrower. 59 | =media-breakpoint-only($name, $breakpoints: $grid-breakpoints) 60 | $min: breakpoint-min($name, $breakpoints) 61 | $max: breakpoint-max($name, $breakpoints) 62 | 63 | @if $min != null and $max != null 64 | @media (min-width: $min) and (max-width: $max) 65 | @content 66 | @else if $max == null 67 | +media-breakpoint-up($name, $breakpoints) 68 | @content 69 | @else if $min == null 70 | +media-breakpoint-down($name, $breakpoints) 71 | @content 72 | 73 | @function breakpoint-infix($name, $breakpoints: $grid-breakpoints) 74 | @return if(breakpoint-min($name, $breakpoints) == null, "", "-#{$name}") 75 | 76 | =hover-focus 77 | &:hover, 78 | &:focus 79 | @content 80 | 81 | // Background color 82 | =bg-variant($parent, $color) 83 | #{$parent} 84 | background-color: $color !important 85 | 86 | a#{$parent}, 87 | button#{$parent} 88 | +hover-focus 89 | background-color: darken($color, 10%) !important 90 | 91 | // Typography 92 | =text-emphasis-variant($parent, $color) 93 | #{$parent} 94 | color: $color !important 95 | 96 | a#{$parent} 97 | +hover-focus 98 | color: darken($color, 10%) !important 99 | 100 | // Placeholder 101 | =placeholder 102 | &::placeholder 103 | @content 104 | 105 | // MDB Mixins 106 | // Set the color of the button and badge 107 | @function set-notification-text-color($color) 108 | @if lightness($color) > 80 109 | @return $black-base 110 | 111 | // Lighter backgorund, return dark color 112 | @else 113 | @return $white-base 114 | 115 | // Darker background, return light color 116 | 117 | // Make button 118 | =make-button($name, $color) 119 | .btn-#{$name} 120 | background-color: $color !important 121 | color: set-notification-text-color($color) !important 122 | 123 | &:hover 124 | background-color: lighten($color, 5%) 125 | 126 | &:focus, 127 | &.focus 128 | box-shadow: $z-depth-1-half 129 | 130 | &:focus, 131 | &:active, 132 | &.active 133 | background-color: darken($color, 20%) 134 | 135 | &.dropdown-toggle 136 | background-color: $color !important 137 | 138 | &:hover, 139 | &:focus 140 | background-color: lighten($color, 5%) !important 141 | 142 | &:not([disabled]):not(.disabled):active, 143 | &:not([disabled]):not(.disabled).active, 144 | .show > &.dropdown-toggle 145 | box-shadow: $z-depth-1-half 146 | background-color: darken($color, 20%) !important 147 | 148 | &:not([disabled]):not(.disabled):active:focus, 149 | &:not([disabled]):not(.disabled).active:focus, 150 | .show > &.dropdown-toggle:focus 151 | box-shadow: $z-depth-1-half 152 | 153 | .#{$name}-ic 154 | color: $color !important 155 | 156 | &:hover, 157 | &:focus 158 | color: $color 159 | 160 | // Make outline button 161 | =make-outline-button($name, $color) 162 | .btn-outline-#{$name} 163 | border: 2px solid $color !important 164 | background-color: transparent !important 165 | color: $color !important 166 | 167 | &:hover, 168 | &:focus, 169 | &:active, 170 | &:active:focus, 171 | &.active 172 | border-color: $color !important 173 | background-color: transparent !important 174 | color: $color !important 175 | 176 | &:not([disabled]):not(.disabled):active, 177 | &:not([disabled]):not(.disabled).active, 178 | .show > &.dropdown-toggle 179 | box-shadow: $z-depth-1-half 180 | background-color: transparent !important 181 | border-color: $color !important 182 | 183 | &:not([disabled]):not(.disabled):active:focus, 184 | &:not([disabled]):not(.disabled).active:focus, 185 | .show > &.dropdown-toggle:focus 186 | box-shadow: $z-depth-1-half 187 | 188 | // Make gradient 189 | =make-gradient($name, $value) 190 | .#{$name}-gradient 191 | background: linear-gradient(40deg, map-get($value, start), map-get($value, end)) !important 192 | 193 | // Make gradient button 194 | =make-gradient-button($name, $value) 195 | .btn 196 | &.#{$name}-gradient 197 | transition: .5s ease 198 | color: $white-base 199 | 200 | &:hover, 201 | &:focus, 202 | &:active, 203 | &:active:focus &.active 204 | background: linear-gradient(40deg, lighten(map-get($value, start), 5%), lighten(map-get($value, end), 5%)) 205 | 206 | // Button size 207 | =button-size($padding-y, $padding-x, $font-size) 208 | padding: $padding-y $padding-x 209 | font-size: $font-size 210 | 211 | =make-badge($name, $color) 212 | .badge-#{$name} 213 | background-color: $color !important 214 | color: set-notification-text-color($color) !important 215 | 216 | // Make input 217 | =make-input($label-font-size, $label-active-font-size, $top, $prefix-font-size, $margin-left, $width, $margin-left-2) 218 | label 219 | font-size: $label-font-size 220 | 221 | &.active 222 | font-size: $label-active-font-size 223 | 224 | .prefix 225 | top: $top 226 | font-size: $prefix-font-size 227 | 228 | ~ input, ~ textarea 229 | margin-left: $margin-left 230 | width: $width 231 | 232 | ~ label 233 | margin-left: $margin-left 234 | 235 | ~ .form-text 236 | margin-left: $margin-left-2 237 | 238 | // Make navbar 239 | =make-navbar($color-0, $background-image, $color, $color-2, $color-3) 240 | .navbar-nav 241 | .nav-item 242 | .nav-link 243 | &.disbled 244 | color: $color-0 245 | 246 | &:hover 247 | color: $color-0 248 | 249 | .navbar-toggler-icon 250 | background-image: $background-image 251 | cursor: pointer 252 | 253 | .breadcrumb, 254 | .navbar-nav 255 | .nav-item 256 | .nav-link 257 | color: $color 258 | transition: $navbar-nav-transition 259 | 260 | &:hover 261 | color: $color-2 262 | 263 | &.active > .nav-link 264 | background-color: $color-3 265 | 266 | &:hover 267 | color: $color 268 | 269 | .navbar-toggler 270 | color: $color 271 | 272 | form 273 | .md-form 274 | input 275 | border-bottom: 1px solid $color 276 | 277 | &:focus:not([readonly]) 278 | border-color: $input-md-focus-color 279 | 280 | .form-control 281 | color: $color 282 | 283 | +placeholder 284 | color: $color 285 | font-weight: $navbar-font-weight 286 | 287 | // Make floating button 288 | =make-btn-floating($width, $height, $font-size, $line-height) 289 | width: $width 290 | height: $height 291 | 292 | i 293 | font-size: $font-size 294 | line-height: $line-height 295 | 296 | // Keyframes 297 | =keyframes($animation-name) 298 | @keyframes #{$animation-name} 299 | @content 300 | -------------------------------------------------------------------------------- /graphql/schema/flamingo.me_flamingo-commerce_v3_product_interfaces_graphql-Service.graphql: -------------------------------------------------------------------------------- 1 | interface Commerce_Product { 2 | type: String! 3 | marketPlaceCode: String! 4 | identifier: String! 5 | media: Commerce_Product_Media!, 6 | price: Commerce_Product_PriceInfo!, 7 | availablePrices: [Commerce_Product_PriceInfo!], 8 | title: String! 9 | categories: Commerce_Product_Categories! 10 | description: String! 11 | shortDescription: String! 12 | meta: Commerce_Product_Meta! 13 | loyalty: Commerce_Product_Loyalty! 14 | attributes: Commerce_Product_Attributes! 15 | badges: Commerce_Product_Badges! 16 | } 17 | 18 | """ 19 | A simple product, that has no variable attributes and therefore no relation to other products 20 | """ 21 | type Commerce_Product_SimpleProduct implements Commerce_Product { 22 | type: String! 23 | marketPlaceCode: String! 24 | identifier: String! 25 | media: Commerce_Product_Media!, 26 | price: Commerce_Product_PriceInfo!, 27 | availablePrices: [Commerce_Product_PriceInfo!], 28 | title: String! 29 | categories: Commerce_Product_Categories! 30 | description: String! 31 | shortDescription: String! 32 | meta: Commerce_Product_Meta! 33 | loyalty: Commerce_Product_Loyalty! 34 | attributes: Commerce_Product_Attributes! 35 | badges: Commerce_Product_Badges! 36 | } 37 | 38 | """ 39 | A configurable product defines the possible variations of a product. It only contains 40 | information about product variants but has no active variant itself. 41 | """ 42 | type Commerce_Product_ConfigurableProduct implements Commerce_Product { 43 | type: String! 44 | marketPlaceCode: String! 45 | identifier: String! 46 | media: Commerce_Product_Media!, 47 | price: Commerce_Product_PriceInfo!, 48 | availablePrices: [Commerce_Product_PriceInfo!], 49 | title: String! 50 | categories: Commerce_Product_Categories! 51 | description: String! 52 | shortDescription: String! 53 | meta: Commerce_Product_Meta! 54 | loyalty: Commerce_Product_Loyalty! 55 | attributes: Commerce_Product_Attributes! 56 | """ 57 | Contains all possible combinations of variation attributes that point to a variant, 58 | as well as all possible variations to render in the frontend. 59 | """ 60 | variantSelection: Commerce_Product_VariantSelection! 61 | badges: Commerce_Product_Badges! 62 | } 63 | 64 | type Commerce_Product_VariantSelection { 65 | variants: [Commerce_Product_VariantSelection_Match!]! 66 | attributes: [Commerce_Product_VariantSelection_Attribute!]! 67 | } 68 | 69 | type Commerce_Product_VariantSelection_Attribute { 70 | label: String! 71 | code: String! 72 | options: [Commerce_Product_VariantSelection_Attribute_Option!]! 73 | } 74 | 75 | type Commerce_Product_VariantSelection_Attribute_Option { 76 | label: String! 77 | unitCode: String 78 | otherAttributesRestrictions: [Commerce_Product_VariantSelection_Option_OtherAttributesRestriction!]! 79 | } 80 | 81 | type Commerce_Product_VariantSelection_Option_OtherAttributesRestriction { 82 | code: String! 83 | availableOptions: [String!]! 84 | } 85 | 86 | type Commerce_Product_VariantSelection_Match { 87 | attributes: [Commerce_Product_VariantSelection_Match_Attributes!] 88 | variant: Commerce_Product_VariantSelection_Match_Variant! 89 | } 90 | 91 | type Commerce_Product_VariantSelection_Match_Attributes { 92 | key: String! 93 | value: String! 94 | } 95 | 96 | type Commerce_Product_VariantSelection_Match_Variant { 97 | marketplaceCode: String! 98 | } 99 | 100 | """ 101 | An active variant is one of many concrete variants that a configurable provides. All data relates to one active variant 102 | and not the the configurable. It also contains information about it´s siblings (other variants on the same configurable) 103 | """ 104 | type Commerce_Product_ActiveVariantProduct implements Commerce_Product { 105 | type: String! 106 | "The marketPlaceCode of the 'configurable' product. See also 'variantMarketPlaceCode' for the variant marketPlaceCode" 107 | marketPlaceCode: String! 108 | identifier: String! 109 | media: Commerce_Product_Media!, 110 | price: Commerce_Product_PriceInfo!, 111 | availablePrices: [Commerce_Product_PriceInfo!], 112 | title: String! 113 | categories: Commerce_Product_Categories! 114 | description: String! 115 | shortDescription: String! 116 | meta: Commerce_Product_Meta! 117 | loyalty: Commerce_Product_Loyalty! 118 | attributes: Commerce_Product_Attributes! 119 | "The marketPlaceCode of the actual variant" 120 | variantMarketPlaceCode: String! 121 | "Contains information about other available product variations" 122 | variationSelections: [Commerce_Product_VariationSelection!] 123 | "Convenience property to access the active variant labels easily" 124 | activeVariationSelections: [Commerce_Product_ActiveVariationSelection!] 125 | badges: Commerce_Product_Badges! 126 | } 127 | 128 | """ 129 | A bundle product, that consists of basic products. 130 | """ 131 | type Commerce_Product_BundleProduct implements Commerce_Product { 132 | type: String! 133 | marketPlaceCode: String! 134 | identifier: String! 135 | media: Commerce_Product_Media!, 136 | price: Commerce_Product_PriceInfo!, 137 | availablePrices: [Commerce_Product_PriceInfo!], 138 | title: String! 139 | categories: Commerce_Product_Categories! 140 | description: String! 141 | shortDescription: String! 142 | meta: Commerce_Product_Meta! 143 | loyalty: Commerce_Product_Loyalty! 144 | attributes: Commerce_Product_Attributes! 145 | badges: Commerce_Product_Badges! 146 | choices: [Commerce_Product_Choice!] 147 | } 148 | 149 | 150 | "A group of attributes. E.g. 'size'" 151 | type Commerce_Product_VariationSelection { 152 | code: String! 153 | label: String! 154 | "All possible variations for that attribute. E.g. 'M', 'L', 'XL'" 155 | options: [Commerce_Product_VariationSelection_Option] 156 | } 157 | 158 | "Easy-to-access property to display attribute information about an active variant" 159 | type Commerce_Product_ActiveVariationSelection { 160 | code: String! 161 | label: String! 162 | value: String! 163 | unitCode: String! 164 | } 165 | 166 | "An option for a group of attributes" 167 | type Commerce_Product_VariationSelection_Option { 168 | label: String! 169 | unitCode: String! 170 | state: Commerce_Product_VariationSelection_OptionState! 171 | """ 172 | Contains information about a product that matches this option. 173 | Depending on if there is an active variant or not, it tries to include the variant, 174 | that best matches the current option. 175 | """ 176 | variant: Commerce_Product_VariationSelection_OptionVariant!, 177 | } 178 | 179 | "Information about the underlying variant" 180 | type Commerce_Product_VariationSelection_OptionVariant { 181 | marketPlaceCode: String! 182 | } 183 | 184 | "The state of an option related to the currently active variant" 185 | enum Commerce_Product_VariationSelection_OptionState { 186 | "The currently active variant has this exact attribute + all other active variant attributes" 187 | ACTIVE 188 | "A variant (other than the active variant) exists, that matches this exact attribute + all other active variant attributes" 189 | MATCH 190 | "No variant exists, that matches this exact attribute + all other active variant attributes." 191 | NO_MATCH 192 | } 193 | 194 | "Wrapper that includes main category and all categories" 195 | type Commerce_Product_Categories { 196 | main: Commerce_Product_CategoryTeaser! 197 | all: [Commerce_Product_CategoryTeaser!] 198 | } 199 | 200 | "Meta information about the product" 201 | type Commerce_Product_Meta { 202 | keywords: [String!] 203 | } 204 | 205 | "Loyalty information about this product" 206 | type Commerce_Product_Loyalty { 207 | price: Commerce_Product_Loyalty_PriceInfo 208 | earning: Commerce_Product_Loyalty_EarningInfo 209 | } 210 | 211 | type Commerce_Product_Loyalty_PriceInfo { 212 | type: String! 213 | default: Commerce_Price! 214 | isDiscounted: Boolean! 215 | discounted: Commerce_Price! 216 | discountText: String! 217 | minPointsToSpent: Float! 218 | maxPointsToSpent: Float! 219 | context: Commerce_Product_PriceContext! 220 | } 221 | 222 | "Shows the type and the points earned" 223 | type Commerce_Product_Loyalty_EarningInfo { 224 | "The type of the LoyaltyEarningInfo, e.g. MilesAndMore" 225 | type: String! 226 | "The value of the LoyaltyEarningInfo, currency can be e.g. points or miles" 227 | default: Commerce_Price! 228 | } 229 | 230 | type Commerce_Product_PriceContext { 231 | customerGroup: String! 232 | deliveryCode: String! 233 | channelCode: String! 234 | locale: String! 235 | } 236 | 237 | type Commerce_Product_Media { 238 | all: [Commerce_Product_MediaItem!] 239 | getMedia(usage: String!): Commerce_Product_MediaItem! 240 | } 241 | 242 | type Commerce_Product_MediaItem { 243 | type: String! 244 | mimeType: String! 245 | usage: String! 246 | title: String! 247 | reference: String! 248 | } 249 | 250 | type Commerce_Product_Attributes { 251 | attributeKeys: [String!] 252 | attributes: [Commerce_Product_Attribute!] 253 | hasAttribute(key: String!): Boolean 254 | getAttribute(key: String!): Commerce_Product_Attribute 255 | getAttributesByKey(keys: [String!]): [Commerce_Product_Attribute!] 256 | } 257 | 258 | type Commerce_Product_Attribute { 259 | "Code of the attribute e.g. `productWeight`" 260 | code: String! 261 | "Human-readable code e.g. `The Product Weight`" 262 | codeLabel: String! 263 | "Human-readable label of a single value" 264 | label: String! 265 | "Value of the selected attribute" 266 | value: String! 267 | "Unit of the attribute e.g. `kg`" 268 | unitCode: String! 269 | "Values of a multi value attribute" 270 | values: [String!] 271 | "Human-readable labels of a multi value attribute" 272 | labels: [String!] 273 | } 274 | 275 | type Commerce_Product_CategoryTeaser { 276 | code: String! 277 | path: String! 278 | name: String! 279 | parent: Commerce_Product_CategoryTeaser 280 | } 281 | 282 | type Commerce_Product_PriceInfo { 283 | default: Commerce_Price! 284 | discounted: Commerce_Price! 285 | discountText: String! 286 | activeBase: Commerce_Price! 287 | activeBaseAmount: Float! 288 | activeBaseUnit: String! 289 | isDiscounted: Boolean! 290 | campaignRules: [String!] 291 | denyMoreDiscounts: Boolean! 292 | context: Commerce_Product_PriceContext! 293 | taxClass: String! 294 | } 295 | 296 | 297 | type Commerce_Product_SearchResult { 298 | products: [Commerce_Product!] 299 | facets: [Commerce_Search_Facet!]! 300 | suggestions: [Commerce_Search_Suggestion!] 301 | searchMeta: Commerce_Search_Meta! 302 | hasSelectedFacet: Boolean! 303 | promotion: Commerce_Search_Promotion 304 | actions: [Commerce_Search_Action!] 305 | } 306 | 307 | type Commerce_Product_Badges { 308 | all: [Commerce_Product_Badge!] 309 | first: Commerce_Product_Badge 310 | } 311 | 312 | type Commerce_Product_Badge { 313 | code: String! 314 | label: String! 315 | } 316 | 317 | type Commerce_Product_Choice { 318 | identifier: String! 319 | required: Boolean! 320 | label: String! 321 | options: [Commerce_Product_Option!] 322 | active: Commerce_Product @deprecated(reason: "use activeOption instead") 323 | activeOption: Commerce_Product_Option 324 | } 325 | 326 | type Commerce_Product_Option { 327 | product: Commerce_Product! 328 | qty: Int! 329 | } 330 | 331 | input Commerce_Product_ChoiceConfigurationInput { 332 | identifier: String! 333 | marketplaceCode: String! 334 | variantMarketplaceCode: String 335 | qty: Int! 336 | } 337 | 338 | extend type Query { 339 | Commerce_Product(marketPlaceCode: String!, variantMarketPlaceCode: String, bundleConfiguration: [Commerce_Product_ChoiceConfigurationInput!]): Commerce_Product 340 | Commerce_Product_Search(searchRequest: Commerce_Search_Request!): Commerce_Product_SearchResult! 341 | } 342 | -------------------------------------------------------------------------------- /frontend/src/base/style/mdp-ecom-base/core/_variables.sass: -------------------------------------------------------------------------------- 1 | // Variables 2 | // Fonts 3 | $roboto-font-path: "asset/font/roboto/" !default 4 | 5 | $font-size-large: 1.5rem !default 6 | $font-bold: 500 !default 7 | $font-small: 0.9rem !default 8 | 9 | $line-height-small: 1 !default 10 | $line-height-extra-large: 2.5 !default 11 | 12 | // Reponsive Headings 13 | $responsive-headings: () !default 14 | $responsive-headings: map-merge(("xs": ("h1": 150%, "h2": 145%, "h3": 135%, "h4": 135%, "h5": 135%), "sm": ("h1": 170%, "h2": 140%, "h3": 125%, "h4": 125%, "h5": 125%), "md": ("h1": 200%, "h2": 170%, "h3": 140%, "h4": 125%, "h5": 125%), "lg": ("h1": 200%, "h2": 170%, "h3": 140%, "h4": 125%, "h5": 125%), "xl": ("h1": 250%, "h2": 200%, "h3": 170%, "h4": 140%, "h5": 125%)), $responsive-headings) 15 | 16 | // Blockquote 17 | $blockquote-padding-y: 0.5rem !default 18 | $blockquote-padding-x: 1rem !default 19 | $blockquote-p-padding-t: $blockquote-padding-x !default 20 | $blockquote-p-padding-b: $blockquote-padding-x !default 21 | $blockquote-p-padding-l: 2rem !default 22 | $blockquote-p-font-size: 1.1rem !default 23 | 24 | // Shadows 25 | $z-depth-1: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12) !default 26 | $z-depth-1-half: 0 5px 11px 0 rgba(0, 0, 0, 0.18), 0 4px 15px 0 rgba(0, 0, 0, 0.15) !default 27 | $z-depth-2: 0 8px 17px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19) !default 28 | $z-depth-3: 0 12px 15px 0 rgba(0, 0, 0, 0.24), 0 17px 50px 0 rgba(0, 0, 0, 0.19) !default 29 | $z-depth-4: 0 16px 28px 0 rgba(0, 0, 0, 0.22), 0 25px 55px 0 rgba(0, 0, 0, 0.21) !default 30 | $z-depth-5: 0 27px 24px 0 rgba(0, 0, 0, 0.2), 0 40px 77px 0 rgba(0, 0, 0, 0.22) !default 31 | 32 | // Transitions 33 | $transition-basic: all 0.2s ease-in-out !default 34 | $transition-hoverable: all 0.55s ease-in-out !default 35 | 36 | // Border radius 37 | $border-radius-base: 0.125rem !default 38 | $border-radius-circle: 50% !default 39 | 40 | // Buttons 41 | $btn-color-basic: $white-base !default 42 | $btn-margin-basic: 0.375rem !default 43 | $btn-padding-y-basic: 0.84rem !default 44 | $btn-padding-x-basic: 2.14rem !default 45 | $btn-font-size-basic: 0.81rem !default 46 | 47 | $btn-padding-y-large: 1rem !default 48 | $btn-padding-x-large: 2.4rem !default 49 | $btn-font-size-large: 0.94rem !default 50 | 51 | $btn-padding-y-medium: 0.7rem !default 52 | $btn-padding-x-medium: 1.6rem !default 53 | $btn-font-size-medium: 0.7rem !default 54 | 55 | $btn-padding-y-small: 0.5rem !default 56 | $btn-padding-x-small: 1.6rem !default 57 | $btn-font-size-small: 0.64rem !default 58 | 59 | $btn-outline-padding-y-basic: 0.7rem !default 60 | $btn-outline-padding-y-large: 0.88rem !default 61 | $btn-outline-padding-y-medium: 0.58rem !default 62 | $btn-outline-padding-y-small: 0.38rem !default 63 | 64 | $btn-tb-padding-y: 0.3rem !default 65 | $btn-tb-padding-x: 1rem !default 66 | 67 | $btn-transition: $transition-basic !default 68 | 69 | $btn-icon-basic: 0.9rem !default 70 | $btn-icon-large: 1rem !default 71 | $btn-icon-medium: 0.8rem !default 72 | $btn-icon-small: 0.7rem !default 73 | $btn-icon-margin: 0.3rem !default 74 | 75 | /*** Global ** 76 | // Media Query Ranges 77 | $small-screen-up: 601px !default 78 | $medium-screen-up: 993px !default 79 | $large-screen-up: 1201px !default 80 | $small-screen: 600px !default 81 | $medium-screen: 992px !default 82 | $large-screen: 1200px !default 83 | $sidenav-breakpoint: 1440px !default 84 | 85 | $medium-and-up: "only screen and (min-width : #{$small-screen-up})" !default 86 | $large-and-up: "only screen and (min-width : #{$medium-screen-up})" !default 87 | $small-and-down: "only screen and (max-width : #{$small-screen})" !default 88 | $medium-and-down: "only screen and (max-width : #{$medium-screen})" !default 89 | $medium-only: "only screen and (min-width : #{$small-screen-up}) and (max-width : #{$medium-screen})" !default 90 | $hide-sidenav: "only screen and (max-width : #{$sidenav-breakpoint})" !default 91 | 92 | // Link color 93 | $link-color: #0275d8 !default 94 | 95 | // Dividers colors 96 | $hr-light: $white-base !default 97 | $hr-dark: #666 !default 98 | $flex-center-ul-mb: 1rem !default 99 | 100 | // Divider 101 | $divider-margin-y: 2.8rem !default 102 | $divider-margin-x: 0.5rem !default 103 | $divider-height: 2px !default 104 | 105 | // Masks 106 | $mask-overlay-transition: all 0.4s ease-in-out !default 107 | $mask-zoom-transition: all 0.2s linear !default 108 | $mask-zoom-transform: scale(1.1) !default 109 | $intro-video-transform: translateX(-50%) translateY(-50%) !default 110 | $intro-video-transition: 1s !default 111 | 112 | // Cards 113 | $md-card-border-radius: 0.25rem !default 114 | $md-card-link-transition: 0.2s ease-in-out !default 115 | $md-card-font-size: 0.9rem !default 116 | $md-card-text-color: #747373 !default 117 | 118 | // Images 119 | $image-path: "asset/img/" !default 120 | $avatar-img-max-width: 100px !default 121 | 122 | // Carousels 123 | $carousel-control-icon-width: 2.25rem !default 124 | $carousel-control-icon-height: $carousel-control-icon-width !default 125 | $carousel-control-prev-icon: url(#{$image-path}/svg/arrow_left.svg) !default 126 | $carousel-control-next-icon: url(#{$image-path}/svg/arrow_right.svg) !default 127 | $carousel-indicators-width: 0.625rem !default 128 | $carousel-indicators-height: $carousel-indicators-width !default 129 | $carousel-indicators-border-radius: $border-radius-circle !default 130 | $carousel-transition-duration: 0.6s !default 131 | $carousel-item-transform: translateX(0) !default 132 | $carousel-item-transform-2: translate3d(0, 0, 0) !default 133 | 134 | // Badges 135 | $badge-pill-padding-x: 0.6rem !default 136 | $badge-pill-border-radius: 10rem !default 137 | 138 | // Footers 139 | $footer-copyright-color: rgba($white-base, 0.6) !default 140 | $footer-copyright-bg-color: rgba($black-base, 0.2) !default 141 | $footer-font-size: 0.9rem !default 142 | 143 | // Forms 144 | $input-bg-color: $white-base !default 145 | $label-font-size: 0.8rem !default 146 | $input-transition: all 0.3s !default 147 | $input-disabled-color: rgba(0, 0, 0, 0.46) !default 148 | $input-md-focus-color: $primary-color !default 149 | $input-error-color: $error-color !default 150 | $input-success-color: $success-color !default 151 | $input-label-after-top: 65px !default 152 | $input-label-after-transition: 0.2s opacity ease-out, 0.2s color ease-out !default 153 | $input-border-color: #ced4da !default 154 | 155 | $input-label-transition: 0.2s ease-out !default 156 | $input-label-color: #757575 !default 157 | $input-label-top: 0.65rem !default 158 | $input-label-active-transform: translateY(-140%) !default 159 | $input-prefix-transition: color 0.2s !default 160 | 161 | $input-md-form-margin-top: 1.5rem !default 162 | $input-md-form-margin-bottom: $input-md-form-margin-top !default 163 | $input-label-font-size: 1rem !default 164 | $input-label-active-font-size: 0.8rem !default 165 | $input-prefix-top: 0.25rem !default 166 | $input-prefix-font-size: 1.75rem !default 167 | $input-prefix-margin-left: 2.5rem !default 168 | $input-prefix-width: calc(100% - 2.5rem) !default 169 | $input-group-addon-font-size: 1.4rem !default 170 | $input-form-text-ml: 2.6rem !default 171 | 172 | $input-label-font-size-lg: 1.25rem !default 173 | $input-label-active-font-size-lg: 0.95rem !default 174 | $input-prefix-top-lg: 0.4rem !default 175 | $input-prefix-font-size-lg: 2rem !default 176 | $input-prefix-margin-left-lg: 3rem !default 177 | $input-prefix-width-lg: calc(100% - 3rem) !default 178 | $input-group-addon-font-size-lg: 1.65rem !default 179 | $input-form-text-ml-lg: 3.1rem !default 180 | 181 | $input-label-font-size-sm: 0.875rem !default 182 | $input-label-active-font-size-sm: 0.75rem !default 183 | $input-prefix-top-sm: 0.35rem !default 184 | $input-prefix-font-size-sm: 1.5rem !default 185 | $input-prefix-margin-left-sm: 2rem !default 186 | $input-prefix-width-sm: calc(100% - 2rem) !default 187 | $input-group-addon-font-size-sm: 1.15rem !default 188 | $input-form-text-ml-sm: 2rem !default 189 | 190 | $textarea-padding: 1.5rem !default 191 | 192 | $input-form-control-margin-bottom: 0.5rem !default 193 | $input-form-control-padding-top: 0.3rem !default 194 | $input-form-control-padding-bottom: 0.55rem !default 195 | $input-disabled-solid-color: #BDBDBD !default 196 | 197 | // Input group 198 | $input-group-text-bgc: #e0e0e0 !default 199 | $input-group-form-control-px: 0.75rem !default 200 | $input-group-form-control-py: 0.375rem !default 201 | 202 | // List group 203 | $list-group-padding: 0 10px 10px 0 !default 204 | $list-group-transition: 0.5s !default 205 | 206 | // Modals 207 | $modal-distance: 10px !default 208 | $modal-width: 400px !default 209 | $modal-full-height-medium-screen: 800px !default 210 | $modal-full-height-large-screen: 1000px !default 211 | $modal-fade-top-transform: translate3d(0, -25%, 0) !default 212 | $modal-fade-bottom-transform: translate3d(0, 25%, 0) !default 213 | $modal-fade-right-transform: translate3d(25%, 0, 0) !default 214 | $modal-fade-left-transform: translate3d(-25%, 0, 0) !default 215 | $modal-notify-body-padding: 1.5rem !default 216 | $modal-notify-heading-padding: 0.3rem !default 217 | $modal-notify-font-size: 1.15rem !default 218 | $modal-avatar-margin-top: 6rem !default 219 | $modal-avatar-header-margin-top: -6rem !default 220 | $modal-avatar-header-margin-bottom: -1rem !default 221 | $modal-avatar-img-width: 130px !default 222 | $modal-body-padding-right: 2rem !default 223 | $modal-body-padding-left: $modal-body-padding-right !default 224 | $modal-body-margin-top: 1rem !default 225 | $cascading-modal-margin-top: -2rem !default 226 | $cascading-modal-margin-right: 1rem !default 227 | $cascading-modal-margin-bottom: $cascading-modal-margin-right !default 228 | $cascading-modal-margin-left: $cascading-modal-margin-right !default 229 | $cascading-modal-padding: 1.5rem !default 230 | $cascading-modal-close-margin-right: $cascading-modal-margin-right !default 231 | $cascading-modal-font-size: 1.25rem !default 232 | $cascading-modal-fa-margin-right: 9px !default 233 | $cascading-modal-social-margin-top: $cascading-modal-padding !default 234 | $cascading-modal-a-font-size: 1rem !default 235 | $cascading-modal-tabs-margin-x: 1rem !default 236 | $cascading-modal-tabs-margin-top: -1.5rem !default 237 | $cascading-modal-tabs-padding-top: 1.7rem !default 238 | 239 | // Miscellaneous 240 | $edge-header-height: 278px !default 241 | $edge-header-background-color: #ccc !default 242 | $edge-header-margin-top: -100px !default 243 | 244 | // Navbars 245 | $navbar-font-weight: 300 !default 246 | $navbar-double-font-size: 15px !default 247 | 248 | $navbar-light-toggler-icon: url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.9)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 8h24M4 16h24M4 24h24'/%3E%3C/svg%3E") !default 249 | $navbar-light-bg-active-color: rgba($black-base, 0.1) !default 250 | $navbar-light-hover-color: rgba($black-base, 0.75) !default 251 | $navbar-light-disabled-color: rgba(0, 0, 0, 0.5) !default 252 | 253 | $navbar-dark-toggler-icon: url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.9)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 8h24M4 16h24M4 24h24'/%3E%3C/svg%3E") !default 254 | $navbar-dark-bg-active-color: rgba($white-base, 0.1) !default 255 | $navbar-dark-hover-color: rgba($white-base, 0.75) !default 256 | $navbar-dark-disabled-color: rgba(255, 255, 255, 0.5) !default 257 | 258 | $navbar-scrolling-transition: background 0.5s ease-in-out, padding 0.5s ease-in-out !default 259 | $navbar-scrolling-transition-duration: 1s !default 260 | $navbar-scrolling-padding: 12px !default 261 | $navbar-top-collapse-padding: 5px !default 262 | $navbar-nav-transition: 0.35s !default 263 | $navbar-dropdown-font-size: 0.9375rem !default 264 | $navbar-dropdown-menu-padding: 10px !default 265 | $navbar-flex-icons-padding-md: 6px !default 266 | $navbar-flex-icons-padding-lg: 3px !default 267 | $navbar-form-input-mr: 5px !default 268 | $navbar-form-input-mb: 1px !default 269 | $navbar-form-input-ml: 8px !default 270 | $navbar-form-input-height: 1rem !default 271 | $navbar-breadcrumb-padding-top: 0.3rem !default 272 | $navbar-breadcrumb-padding-left: 1rem !default 273 | $navbar-breadcrumb-color: rgba(255, 255, 255, 0.65) !default 274 | 275 | // Pagination 276 | $pagination-active-transition: all 0.2s linear !default 277 | $pagination-page-link-transition: all 0.3s linear !default 278 | $pagination-page-link-font-size: 0.9rem !default 279 | $pagination-page-link-font-size-lg: 1rem !default 280 | $pagination-page-link-font-size-sm: 0.8rem !default 281 | $pagination-page-item-disabled-color: #868e96 !default 282 | $pagination-page-link-color: #212529 !default 283 | $pagination-page-link-hover-bg-color: #eee !default 284 | $pagination-circle-margin-x: 2px !default 285 | $pagination-circle-border-radius: $border-radius-circle !default 286 | 287 | // Tables 288 | $table-th-font-size: 0.9rem !default 289 | $table-td-font-size: $table-th-font-size !default 290 | $table-th-padding-top: 1.1rem !default 291 | $table-td-padding-bottom: 1rem !default 292 | $table-a-color: #212529 !default 293 | $table-hover-transition: 0.5s !default 294 | $table-hover-background-color: rgba(0, 0, 0, 0.075) !default 295 | $table-sm-padding-y: 0.6rem !default 296 | $table-inverse-color-border: $white-base !default 297 | $product-table-img-max-height: 150px !default 298 | $product-table-img-min-width: 50px !default 299 | --------------------------------------------------------------------------------