diff --git a/.htaccess b/.htaccess
new file mode 100644
index 0000000..fa05289
--- /dev/null
+++ b/.htaccess
@@ -0,0 +1,109 @@
+Header set X-Content-Security-Policy "allow 'self'; media-src *; img-src *; script-src 'self' https://ajax.googleapis.com; style-src 'self';"
+Header always append X-Frame-Options SAMEORIGIN
+ServerSignature Off
+
+mod_gzip_on Yes
+mod_gzip_dechunk Yes
+mod_gzip_item_include file .(html?|txt|css|js|php|pl)$
+mod_gzip_item_include handler ^cgi-script$
+mod_gzip_item_include mime ^text/.*
+mod_gzip_item_include mime ^application/x-javascript.*
+mod_gzip_item_exclude mime ^image/.*
+mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
+
+
+ExpiresActive On
+ExpiresByType image/jpg "access 1 year"
+ExpiresByType image/jpeg "access 1 year"
+ExpiresByType image/gif "access 1 year"
+ExpiresByType image/png "access 1 year"
+ExpiresByType text/css "access 1 month"
+ExpiresByType text/html "access 1 month"
+ExpiresByType application/pdf "access 1 month"
+ExpiresByType text/x-javascript "access 1 month"
+ExpiresByType application/x-shockwave-flash "access 1 month"
+ExpiresByType image/x-icon "access 1 year"
+ExpiresDefault "access 1 month"
+
+
+RewriteEngine On
+RewriteCond %{HTTPS} off
+RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
+RewriteCond %{HTTP_HOST} !^www\.
+RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]
+
+### SILVERSTRIPE START ###
+# Deny access to templates (but allow from localhost)
+
+ Order deny,allow
+ Deny from all
+ Allow from 127.0.0.1
+
+
+# Deny access to IIS configuration
+
+ Order deny,allow
+ Deny from all
+
+
+# Deny access to YAML configuration files which might include sensitive information
+
+ Order allow,deny
+ Deny from all
+
+
+# Route errors to static pages automatically generated by SilverStripe
+ErrorDocument 404 /assets/error-404.html
+ErrorDocument 500 /assets/error-500.html
+
+
+ SetEnv HTTP_MOD_REWRITE On
+ RewriteEngine On
+ RewriteBase '/'
+
+ # Deny access to potentially sensitive files and folders
+RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
+RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
+RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
+ RewriteRule ^vendor(/|$) - [F,L,NC]
+RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
+RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
+RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
+ RewriteRule silverstripe-cache(/|$) - [F,L,NC]
+RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
+RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
+RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
+ RewriteRule composer\.(json|lock) - [F,L,NC]
+
+ # Process through SilverStripe if no file with the requested name exists.
+ # Pass through the original path as a query parameter, and retain the existing parameters.
+ RewriteCond %{REQUEST_URI} ^(.*)$
+ RewriteCond %{REQUEST_FILENAME} !-f
+RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
+RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
+RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
+ RewriteRule .* framework/main.php?url=%1 [QSA]
+
+### SILVERSTRIPE END ###
+
+RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
+RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
+RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
+RewriteRule ^\.git - [F,L,NC]
+RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
+RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
+RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
+RewriteRule \.sql$ - [F,L,NC]
+RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
+RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
+RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
+RewriteRule \.editorconfig - [F,L,NC]
+RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
+RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
+RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
+RewriteRule error_log - [F,L,NC]
+RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
+RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
+RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
+RewriteRule Envoy\.blade\.php - [F,L,NC]
+
diff --git a/app/_config/config.yml b/app/_config/config.yml
index 7cd246e..4b2ce51 100644
--- a/app/_config/config.yml
+++ b/app/_config/config.yml
@@ -21,9 +21,5 @@ SilverStripe\Forms\HTMLEditor\TinyMCEConfig:
editor_css:
- 'app/client/dist/css/editor.css'
-SilverStripe\Assets\File:
- allowed_extensions:
- - svg
- app_categories:
- image:
- - svg
+SilverShop\Extension\ShopConfigExtension:
+ base_currency: USD
diff --git a/app/_config/elements.yml b/app/_config/elements.yml
index a2ebbad..56772db 100644
--- a/app/_config/elements.yml
+++ b/app/_config/elements.yml
@@ -25,6 +25,8 @@ SilverStripe\CMS\Model\SiteTree:
- Dynamic\Elements\Elements\ElementTestimonials
- Site\Elements\TeamMembersElement
- Site\Elements\SliderElement
+ - Site\Elements\PromotionElement
+ - Site\Elements\StoreElement
DNADesign\ElementalList\Model\ElementList:
default_global_elements: false
diff --git a/app/_config/extensions.yml b/app/_config/extensions.yml
index d1b6168..6fcd4bd 100644
--- a/app/_config/extensions.yml
+++ b/app/_config/extensions.yml
@@ -14,3 +14,9 @@ SilverStripe\Blog\Model\BlogPost:
SilverStripe\Core\Injector\Injector:
SilverStripe\UserForms\Model\UserDefinedForm:
class: Site\Extensions\CMSMain_HiddenClass
+ SilverShop\Checkout\SinglePageCheckoutComponentConfig:
+ class: Site\Models\CheckoutNoDeliveryConfig
+
+#SilverShop\Model\Address:
+# extensions:
+# - Site\Extensions\AddressExtension
\ No newline at end of file
diff --git a/app/_config/googlemapfield.yml b/app/_config/googlemapfield.yml
new file mode 100644
index 0000000..16f16b4
--- /dev/null
+++ b/app/_config/googlemapfield.yml
@@ -0,0 +1,3 @@
+BetterBrief\GoogleMapField:
+ default_options:
+ api_key: 'YOUR_API_KEY'
diff --git a/app/_config/payment.yml b/app/_config/payment.yml
new file mode 100644
index 0000000..6bc6630
--- /dev/null
+++ b/app/_config/payment.yml
@@ -0,0 +1,6 @@
+---
+Name: payment
+---
+SilverStripe\Omnipay\Model\Payment:
+ allowed_gateways:
+ - 'Manual'
diff --git a/app/_config/requirements.yml b/app/_config/requirements.yml
index 64c0467..275e978 100644
--- a/app/_config/requirements.yml
+++ b/app/_config/requirements.yml
@@ -3,4 +3,8 @@ Site\Templates\DeferedRequirements:
nofontawesome: false
version: false
static_domain: false
+ custom_requirements:
+ SilverShop\Page\AccountPageController:
+ - SilverShop.Page.CheckoutPageController.js
+ - SilverShop.Page.CheckoutPageController.css
diff --git a/app/client/src/js/_components/_ui.map.api.js b/app/client/src/js/_components/_ui.map.api.js
index 12d40b5..cdf501b 100644
--- a/app/client/src/js/_components/_ui.map.api.js
+++ b/app/client/src/js/_components/_ui.map.api.js
@@ -5,162 +5,182 @@ import Events from "../_events";
import mapBoxGL from "mapbox-gl";
//import "./mapStorage";
-import "../../scss/types/MapPage.scss";
+import "../../scss/_components/_ui.map.scss";
const W = window;
const MapAPI = (($) => {
- const STORAGE = W.localStorage;
+ const STORAGE = W.localStorage;
- // Constants
- const NAME = 'jsMapAPI';
- const DATA_KEY = NAME;
- const $BODY = $('body');
- let Map;
- let currentStyle;
+ // Constants
+ const NAME = 'jsMapAPI';
+ const DATA_KEY = NAME;
+ const $BODY = $('body');
+ let Map;
+ let currentStyle;
- class MapAPI {
- // Constructor
- constructor(element) {
- this._element = element;
- const $element = $(this._element);
- currentStyle = this.getStyle();
+ class MapAPI {
+ // Constructor
+ constructor(element) {
+ this._element = element;
+ const $element = $(this._element);
+ const geojson = $element.data('geojson');
+ const center = [
+ ($element.data('lng') ? $element.data('lng') : $BODY.data('default-lng')),
+ ($element.data('lat') ? $element.data('lat') : $BODY.data('default-lat')),
+ ];
+ const popup = new mapboxgl.Popup({
+ closeOnClick: false,
+ className: 'popup'
+ });
+ currentStyle = this.getStyle();
+ mapBoxGL.accessToken = $element.data('key');
- mapBoxGL.accessToken = 'pk.eyJ1IjoidG9ueS1haXIiLCJhIjoiY2l1OHoxZGp4MDAxZzJ0cHl0Y25jOWFpMCJ9.BC-YvTC2hUKhNbae4iAPCA';
+ Map = new mapBoxGL.Map({
+ 'container': $element.find('.mapAPI-map')[0],
+ 'center': center,
+ //hash: true,
+ 'style': currentStyle,
+ //localIdeographFontFamily: $BODY.css('font-family'),
+ 'zoom': ($element.data('map-zoom') ? $element.data('map-zoom') : 10),
+ 'attributionControl': false
+ /*transformRequest: (url, resourceType)=> {
+ if(resourceType === 'Source' && url.startsWith('http://myHost')) {
+ return {
+ url: url.replace('http', 'https'),
+ headers: { 'my-custom-header': true},
+ credentials: 'include' // Include cookies for cross-origin requests
+ }
+ }
+ }*/
+ })
+ .addControl(new mapBoxGL.AttributionControl({
+ compact: true
+ }))
+ .addControl(new mapBoxGL.NavigationControl(), 'top-right')
+ .addControl(new mapBoxGL.GeolocateControl({
+ positionOptions: {
+ enableHighAccuracy: true,
+ },
+ trackUserLocation: true,
+ }), 'bottom-right')
+ .addControl(new mapboxgl.ScaleControl({
+ maxWidth: 80,
+ unit: 'metric'
+ }), 'top-left');
- Map = new mapBoxGL.Map({
- container: $element.find('.mapAPI-map')[0],
- center: [$BODY.data('default-lng'), $BODY.data('default-lat')],
- //hash: true,
- style: currentStyle,
- //localIdeographFontFamily: $BODY.css('font-family'),
- zoom: $element.data('map-zoom'),
- attributionControl: false
- /*transformRequest: (url, resourceType)=> {
- if(resourceType === 'Source' && url.startsWith('http://myHost')) {
- return {
- url: url.replace('http', 'https'),
- headers: { 'my-custom-header': true},
- credentials: 'include' // Include cookies for cross-origin requests
- }
- }
- }*/
- })
- .addControl(new mapBoxGL.AttributionControl({
- compact: true
- }))
- .addControl(new mapBoxGL.NavigationControl(), 'top-right')
- .addControl(new mapBoxGL.GeolocateControl({
- positionOptions: {
- enableHighAccuracy: true,
- },
- trackUserLocation: true,
- }),'bottom-right')
- .addControl(new mapboxgl.ScaleControl({
- maxWidth: 80,
- unit: 'metric'
- }),'top-left');
+ // event.target
+ Map.on('load', (e) => {
+ // add markers to map
+ geojson.features.forEach(function(marker) {
+ // create a DOM element for the marker
+ const $el = $('
' + marker.icon + '
');
- // event.target
- Map.on('load',(e) => {
- console.log('Map is loaded');
- /*Map.addSource('dem', {
- "type": "raster-dem",
- "url": "mapbox://mapbox.terrain-rgb"
- });
- Map.addLayer({
- "id": "hillshading",
- "source": "dem",
- "type": "hillshade"
- });*/
- });
+ $el.on('click', function() {
+ console.log('Marker click');
+ const coordinates = marker.geometry.coordinates;
+ const content = marker.properties.content;
+ console.log(popup);
+ popup.setLngLat(coordinates)
+ .setHTML(content)
+ .addTo(Map);
+ });
- /*Map.on('render',function(event){
- console.log('map moved');
- console.log(event);
- });
+ // add marker to map
+ new mapboxgl.Marker($el[0])
+ .setLngLat(marker.geometry.coordinates)
+ .addTo(Map);
+ });
- // event: MapDataEvent
- Map.on('dataloading',() => {
- console.log('Loading map data');
- //console.log(event);
- });
+ console.log('Map is loaded');
+ });
- // event: MapDataEvent
- Map.on('data',(event) => {
- console.log('Map data updated');
- //console.log(event);
- });*/
+ /*Map.on('render',function(event){
+ console.log('map moved');
+ console.log(event);
+ });
- // check time every 60 mins and change to night style
- const api = this;
- setInterval(() => {
- const newStyle = api.getStyle();
- if(newStyle !== currentStyle){
- Map.setStyle(api.getStyle());
+ // event: MapDataEvent
+ Map.on('dataloading',() => {
+ console.log('Loading map data');
+ //console.log(event);
+ });
+
+ // event: MapDataEvent
+ Map.on('data',(event) => {
+ console.log('Map data updated');
+ //console.log(event);
+ });*/
+
+ // check time every 60 mins and change to night style
+ const api = this;
+ setInterval(() => {
+ const newStyle = api.getStyle();
+ if (newStyle !== currentStyle) {
+ Map.setStyle(api.getStyle());
+ }
+ }, 36000);
+
+
+ $element.addClass(`${NAME}-active`);
}
- },36000);
+ // Public methods
+ getMap() {
+ return Map;
+ }
- $element.addClass(`${NAME}-active`);
+ getStyle() {
+ return 'mapbox://styles/mapbox/streets-v9';
+ const hour = new Date().getHours();
+ if (hour < 6 || hour > 18) {
+ // night
+ //return 'mapbox://styles/mapbox/streets-v7';
+ return 'mapbox://styles/tony-air/cjeacwih92iu42rpd8tcmuyb2';
+ } else {
+ // day
+ return 'mapbox://styles/mapbox/streets-v9';
+ }
+ }
+
+ dispose() {
+ const $element = $(this._element);
+
+ $element.removeClass(`${NAME}-active`);
+ $.removeData(this._element, DATA_KEY);
+ this._element = null;
+ }
+
+ static _jQueryInterface() {
+ if (typeof W.localStorage !== 'undefined') {
+ return this.each(function() {
+ // attach functionality to element
+ const $element = $(this);
+ let data = $element.data(DATA_KEY);
+
+ if (!data) {
+ data = new MapAPI(this);
+ $element.data(DATA_KEY, data);
+ }
+ });
+ }
+ }
}
- // Public methods
- getMap() {
- return Map;
- }
+ // jQuery interface
+ $.fn[NAME] = MapAPI._jQueryInterface;
+ $.fn[NAME].Constructor = MapAPI;
+ $.fn[NAME].noConflict = function() {
+ $.fn[NAME] = JQUERY_NO_CONFLICT;
+ return MapAPI._jQueryInterface;
+ };
- getStyle() {
- return 'mapbox://styles/mapbox/streets-v9';
- const hour = new Date().getHours();
- if(hour < 6 || hour > 18) {
- // night
- //return 'mapbox://styles/mapbox/streets-v7';
- return 'mapbox://styles/tony-air/cjeacwih92iu42rpd8tcmuyb2';
- }else{
- // day
- return 'mapbox://styles/mapbox/streets-v9';
- }
- }
+ // auto-apply
+ $(W).on(`${Events.AJAX} ${Events.LOADED}`, () => {
+ $('.mapAPI-map-container').jsMapAPI();
+ });
- dispose() {
- const $element = $(this._element);
-
- $element.removeClass(`${NAME}-active`);
- $.removeData(this._element, DATA_KEY);
- this._element = null;
- }
-
- static _jQueryInterface() {
- if (typeof W.localStorage !== 'undefined') {
- return this.each(function () {
- // attach functionality to element
- const $element = $(this);
- let data = $element.data(DATA_KEY);
-
- if (!data) {
- data = new MapAPI(this);
- $element.data(DATA_KEY, data);
- }
- });
- }
- }
- }
-
- // jQuery interface
- $.fn[NAME] = MapAPI._jQueryInterface;
- $.fn[NAME].Constructor = MapAPI;
- $.fn[NAME].noConflict = function () {
- $.fn[NAME] = JQUERY_NO_CONFLICT;
- return MapAPI._jQueryInterface;
- };
-
- // auto-apply
- $(W).on(`${Events.AJAX} ${Events.LOADED}`, () => {
- $('.mapAPI-map-container').jsMapAPI();
- });
-
- return MapAPI;
+ return MapAPI;
})($);
export default MapAPI;
diff --git a/app/client/src/js/types/SilverShop.Page.CheckoutPageController.js b/app/client/src/js/types/SilverShop.Page.CheckoutPageController.js
new file mode 100644
index 0000000..c4d5780
--- /dev/null
+++ b/app/client/src/js/types/SilverShop.Page.CheckoutPageController.js
@@ -0,0 +1 @@
+import '../_components/_ui.map.api';
diff --git a/app/client/src/scss/_components/_ui.carousel.scss b/app/client/src/scss/_components/_ui.carousel.scss
index 4f8be2b..3d3c1f2 100644
--- a/app/client/src/scss/_components/_ui.carousel.scss
+++ b/app/client/src/scss/_components/_ui.carousel.scss
@@ -16,10 +16,6 @@
.carousel-indicators li {
box-shadow: 1px 1px #000;
-
- &.active {
- background: $blue;
- }
}
.carousel-title,
diff --git a/app/client/src/scss/_components/_ui.elemental.scss b/app/client/src/scss/_components/_ui.elemental.scss
index a9da826..e33600e 100644
--- a/app/client/src/scss/_components/_ui.elemental.scss
+++ b/app/client/src/scss/_components/_ui.elemental.scss
@@ -3,8 +3,12 @@
*/
// hide default page title cuz elemental object will be used to display titles
-h1 {
+h1.page-header {
display: none;
+
+ &.no-elements {
+ display: block;
+ }
}
// add top/bottom paddings for basic elements
diff --git a/app/client/src/scss/_components/_ui.main.scss b/app/client/src/scss/_components/_ui.main.scss
index a077118..2fd2c15 100644
--- a/app/client/src/scss/_components/_ui.main.scss
+++ b/app/client/src/scss/_components/_ui.main.scss
@@ -37,6 +37,14 @@ button, input, optgroup, select, textarea,
transition: all 0.4s ease;
}
+.btn-toolbar {
+ margin-top: $grid-gutter-height / 2;
+}
+
+.field {
+ margin: ($grid-gutter-height / 4) 0;
+}
+
// stick navbar to top using mobile layout
#Header {
position: relative;
diff --git a/app/client/src/scss/_components/_ui.map.scss b/app/client/src/scss/_components/_ui.map.scss
new file mode 100644
index 0000000..8b24d61
--- /dev/null
+++ b/app/client/src/scss/_components/_ui.map.scss
@@ -0,0 +1,15 @@
+@import "../variables";
+@import "~mapbox-gl/dist/mapbox-gl.css";
+
+.mapAPI-map {
+ height: 30rem;
+ margin-bottom: 1rem;
+}
+
+.mapboxgl-marker {
+ width: 30px;
+ height: 30px;
+ font-size: 30px;
+ cursor: pointer;
+ text-align: center;
+}
diff --git a/app/client/src/scss/_components/_ui.shop.scss b/app/client/src/scss/_components/_ui.shop.scss
new file mode 100644
index 0000000..ada7ca5
--- /dev/null
+++ b/app/client/src/scss/_components/_ui.shop.scss
@@ -0,0 +1,8 @@
+.cart-footer {
+ margin-top: $grid-gutter-height / 2;
+}
+
+.address-panel,
+.account-nav {
+ margin-bottom: $grid-gutter-height / 2;
+}
diff --git a/app/client/src/scss/types/HomePage.scss b/app/client/src/scss/types/HomePage.scss
deleted file mode 100644
index 916afb4..0000000
--- a/app/client/src/scss/types/HomePage.scss
+++ /dev/null
@@ -1 +0,0 @@
-@import "../variables";
\ No newline at end of file
diff --git a/app/client/src/scss/types/order.scss b/app/client/src/scss/types/order.scss
new file mode 100644
index 0000000..fe673b1
--- /dev/null
+++ b/app/client/src/scss/types/order.scss
@@ -0,0 +1,163 @@
+@import "../_variables";
+
+h1.title {
+ display: block;
+ text-align: right;
+ border-bottom: 1px solid $border-color;
+ text-transform: uppercase;
+ line-height: 1.5em;
+}
+
+.warningMessage {
+ position: relative;
+ padding: $alert-padding-y $alert-padding-x;
+ margin-bottom: $alert-margin-bottom;
+ border: $alert-border-width solid transparent;
+
+ @include border-radius($alert-border-radius);
+
+ color: #856404;
+ background-color: #fff3cd;
+ border-color: #ffeeba;
+}
+
+#Content {
+ text-align: left;
+ margin: auto;
+ padding-left: 20px;
+}
+
+#Content td {}
+
+#Content .emailTitle {
+ font-family: $font-family-base;
+ font-weight: normal;
+ font-size: $h1-font-size;
+}
+
+#Content .PageTitle {
+ padding: 5px;
+ color: $body-color;
+ font-size: 14px;
+ font-family: $font-family-base;
+}
+
+#Content .footer td {
+ padding: 10px;
+}
+
+#Content .footer td.right {
+ text-align: right;
+}
+
+#Content .typography {
+ padding: 0px 10px;
+}
+
+#Content .typography a {
+ font-size: 1em;
+ text-decoration: underline;
+}
+
+#Content .typography a:hover {
+ text-decoration: none;
+}
+
+#Content .typography ul {
+ padding: 2px 15px;
+}
+
+#Content .typography ul li {
+ padding: 2px 5px;
+}
+
+#Content .typography p {
+ margin: 0.75em 0em;
+ color: $body-color;
+}
+
+table#SenderTable .sender,
+table#SenderTable .meta {
+ width: 50%;
+}
+
+table#MetaTable {
+ margin-left: auto;
+}
+
+table#MetaTable .label {
+ font-weight: bold;
+}
+
+#ShippingTable td,
+#ShippingTable th {
+ width: 50%;
+}
+
+table.infotable {
+ border: 1px solid $border-color;
+ border-collapse: collapse;
+ width: 100%;
+ border-top: 1px solid $border-color;
+ border-bottom: 1px solid $border-color;
+ background: $body-bg;
+ margin-top: 10px;
+}
+
+table.infotable td.product.title {
+ color: $link-color;
+ font-size: $h3-font-size;
+ font-weight: normal;
+ font-family: $font-family-base;
+}
+
+table.infotable tr td,
+table.infotable tr th {
+ padding: 5px;
+ color: $body-color;
+ border: 1px solid $border-color;
+}
+
+table.infotable td {
+ vertical-align: middle;
+}
+
+table.infotable tr.summary {
+ font-weight: bold;
+}
+
+table.infotable td.ordersummary {
+ font-size: 1em;
+ border-bottom: 1px solid $border-color;
+}
+
+table.infotable tr th {
+ font-weight: bold;
+}
+
+table.infotable tr td a {
+ color: $link-color;
+ text-decoration: underline;
+}
+
+table.infotable tr td a:hover {
+ text-decoration: none;
+}
+
+table.infotable .modifierRow,
+table.infotable .threeColHeader {
+ text-align: right;
+}
+
+table.infotable .right {
+ text-align: right;
+}
+
+table.infotable .center {
+ text-align: center;
+}
+
+table.infotable .left,
+table.infotable th {
+ text-align: left;
+}
diff --git a/app/src/Extensions/AddressExtension.php b/app/src/Extensions/AddressExtension.php
new file mode 100644
index 0000000..b2a74cb
--- /dev/null
+++ b/app/src/Extensions/AddressExtension.php
@@ -0,0 +1,29 @@
+push($field);
+ $fields->remove($field);
+ }
+
+ $holder->addExtraClass('col-sm-6');
+ $fields->push($holder);
+ }
+}
\ No newline at end of file
diff --git a/app/src/Extensions/SiteConfigExtension.php b/app/src/Extensions/SiteConfigExtension.php
index 57f6d8c..30d0fca 100644
--- a/app/src/Extensions/SiteConfigExtension.php
+++ b/app/src/Extensions/SiteConfigExtension.php
@@ -2,20 +2,24 @@
namespace Site\Extensions;
+use SilverStripe\AssetAdmin\Forms\UploadField;
+use SilverStripe\Assets\Image;
use SilverStripe\Forms\TextareaField;
+use SilverStripe\Forms\TextField;
use SilverStripe\ORM\DataExtension;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\TreeMultiselectField;
+use BetterBrief\GoogleMapField;
class SiteConfigExtension extends DataExtension
{
private static $db = [
'ExtraCode' => 'Text',
- ];
-
- private static $has_one = [
- 'PrivacyPolicy' => SiteTree::class,
+ 'Longitude' => 'Varchar(255)',
+ 'Latitude' => 'Varchar(255)',
+ 'MapZoom' => 'Int',
+ 'MapAPIKey' => 'Varchar(255)'
];
private static $many_many = [
@@ -32,8 +36,29 @@ class SiteConfigExtension extends DataExtension
SiteTree::class
));
- $tab->push(TreeDropdownField::create('PrivacyPolicyID', 'Select privacy policy page', SiteTree::class));
-
$tab->push(TextareaField::create('ExtraCode', 'Extra site-wide HTML code'));
+
+ $mapTab = $fields->findOrMakeTab('Root.GoogleMaps');
+ $mapTab->push(TextField::create('MapAPIKey'));
+ $mapTab->push(TextField::create('MapZoom'));
+ $mapTab->push(GoogleMapField::create(
+ $this->owner,
+ 'Location'
+ ));
+ }
+
+ public function getGeoJSON()
+ {
+ return '{"type": "MarkerCollection","features": [{"type": "Feature","icon": " ",'
+ .'"properties": {"content": "'.$this->owner->getTitle().'"},"geometry": {"type": "Point",'
+ .'"coordinates": ['.$this->owner->getField('Longitude').','.$this->owner->getField('Latitude').']}}]}';
+ }
+
+ public function DirectionsLink()
+ {
+ return ''
+ .' Get Directions ';
}
}
diff --git a/app/src/Models/CheckoutMapComponent.php b/app/src/Models/CheckoutMapComponent.php
new file mode 100644
index 0000000..8c5df20
--- /dev/null
+++ b/app/src/Models/CheckoutMapComponent.php
@@ -0,0 +1,47 @@
+process($config)
+ )
+ );
+ }
+
+ public function validateData(Order $order, array $data)
+ {
+ }
+
+ public function setData(Order $order, array $data)
+ {
+ }
+
+ public function getData(Order $order)
+ {
+ return [];
+ }
+}
\ No newline at end of file
diff --git a/app/src/Models/CheckoutNoDeliveryConfig.php b/app/src/Models/CheckoutNoDeliveryConfig.php
new file mode 100644
index 0000000..af1cb1e
--- /dev/null
+++ b/app/src/Models/CheckoutNoDeliveryConfig.php
@@ -0,0 +1,43 @@
+addComponent(CustomerDetails::create());
+
+ if (Checkout::member_creation_enabled() && !Security::getCurrentUser()) {
+ $this->addComponent(Membership::create());
+ }
+
+ if (count(GatewayInfo::getSupportedGateways()) > 1) {
+ $this->addComponent(Payment::create());
+ }
+
+ $this->addComponent(Notes::create());
+
+ $this->addComponent(CheckoutMapComponent::create());
+ $this->addComponent(Terms::create());
+ }
+}
\ No newline at end of file
diff --git a/app/src/Templates/DeferedRequirements.php b/app/src/Templates/DeferedRequirements.php
index 65da24f..3b8fe93 100644
--- a/app/src/Templates/DeferedRequirements.php
+++ b/app/src/Templates/DeferedRequirements.php
@@ -19,6 +19,7 @@ class DeferedRequirements implements TemplateGlobalProvider
private static $version;
private static $nojquery = false;
private static $nofontawesome = false;
+ private static $custom_requirements = [];
/**
* @return array
@@ -55,7 +56,19 @@ class DeferedRequirements implements TemplateGlobalProvider
DeferedRequirements::loadJS('app.js');
// Class libs
- $class = str_replace('\\', '.', get_class(Controller::curr()));
+ $class = get_class(Controller::curr());
+ if(isset($config['custom_requirements'][$class])){
+ foreach ($config['custom_requirements'][$class] as $file) {
+ if(strpos($file,'.css')){
+ DeferedRequirements::loadCSS($file);
+ }
+ if(strpos($file,'.js')){
+ DeferedRequirements::loadJS($file);
+ }
+ }
+ }
+
+ $class = str_replace('\\', '.', $class);
$dir = Path::join(
Director::publicFolder(),
ManifestFileFinder::RESOURCES_DIR,
@@ -64,8 +77,8 @@ class DeferedRequirements implements TemplateGlobalProvider
'dist'
);
- if (file_exists(Path::join($dir, 'css', '_' . $class . '.css'))) {
- DeferedRequirements::loadCSS('_' . $class . '.css');
+ if (file_exists(Path::join($dir, 'css', $class . '.css'))) {
+ DeferedRequirements::loadCSS( $class . '.css');
}
if (file_exists(Path::join($dir, 'js', $class . '.js'))) {
diff --git a/app/templates/Includes/Content.ss b/app/templates/Includes/Content.ss
index 82d353d..309ed0a 100644
--- a/app/templates/Includes/Content.ss
+++ b/app/templates/Includes/Content.ss
@@ -1,11 +1,11 @@
-
+
-
+
$ElementalArea
<% if $Form %>
-
<% end_if %>
-
+
diff --git a/app/templates/Page.ss b/app/templates/Page.ss
index 67d23ce..28c50fd 100644
--- a/app/templates/Page.ss
+++ b/app/templates/Page.ss
@@ -5,7 +5,7 @@
<% include MetaHead %>
-
+ data-default-lng="$Longitude" data-default-lat="$Latitude"<% end_with %>>
<%-- Upgrade your Browser notice --%>
@@ -36,6 +36,10 @@
<%-- Require CSS+JS from /public/resourses/[js,css]/[ClassName].[js,css] --%>
$AutoRequirements($ClassName).RAW
+ <%-- Mapbox --%>
+
+
+
<%-- place extra requirements after this line --%>