Repository: chrisdiana/simplestore
Branch: master
Commit: ec7c14138ce7
Files: 13
Total size: 38.4 KB
Directory structure:
gitextract_sfvr6rzj/
├── .gitignore
├── Gruntfile.js
├── LICENSE.md
├── README.md
├── bower.json
├── css/
│ └── simpleStore.css
├── index.html
├── js/
│ ├── config.js
│ └── simpleStore.js
├── package.json
├── plugins/
│ └── google-sheets/
│ ├── DemoSpreadsheet.xlsx
│ └── google-sheets.js
└── products.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.DS_Store
node_modules/*
bower_components/*
release/*
release.zip
.idea/
dev/*
================================================
FILE: Gruntfile.js
================================================
module.exports = function(grunt) {
/*
* To build a release run 'grunt'
* index.html has to be manually copied to 'release/' because of
* reference differences (import.min.css, jquery)
*/
var minBanner = '/* <%= pkg.name %> | Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author %> (<%= pkg.homepage %>) | <%= pkg.license %> license | v<%= pkg.version %> */';
var largeBanner = '/*' + '\n' +
'* <%= pkg.name %> v<%= pkg.version %>' + '\n' +
'* Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author %>' + '\n' +
'* <%= pkg.homepage %>' + '\n' +
'* Free to use under the MIT license.' + '\n' +
'* http://www.opensource.org/licenses/mit-license.php' + '\n' +
'*/' + '\n';
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
uglify: {
options: {
banner: minBanner + '\n'
},
build: {
files: {
'js/simpleStore.min.js': 'js/simpleStore.js'
}
}
},
cssmin: {
target: {
files: {
'css/simpleStore.min.css': 'css/simpleStore.css'
}
}
},
file_append: {
default_options: {
files: [
{prepend: minBanner + '\n', input: 'css/simpleStore.min.css'}
]
}
},
copy: {
main: {
files: [
{src: 'css/simpleStore.min.css', dest: 'release/css/simpleStore.min.css'},
{src: 'js/simpleStore.min.js', dest: 'release/js/simpleStore.min.js'},
{src: 'js/simpleCart.min.js', dest: 'release/js/simpleCart.min.js'},
{src: 'js/config.js', dest: 'release/js/config.js'},
{src: 'products.json', dest: 'release/products.json'},
{src: 'images/favicon.png', dest: 'release/images/favicon.png'}
]
},
}
});
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-file-append');
grunt.registerTask('default', ['uglify', 'cssmin', 'file_append', 'copy']);
};
================================================
FILE: LICENSE.md
================================================
The MIT License (MIT)
Copyright (c) 2015 Chris Diana
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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.
================================================
FILE: README.md
================================================
**UPDATES COMING SOON! [Get notified](http://eepurl.com/dHBK11)**
[Sign up](http://eepurl.com/gntUvf) to get updates on new features and releases
# simpleStore
[simpleStore](http://chrisdiana.github.io/simplestore) is a clean, responsive
storefront boilerplate with no database you can setup in minutes. simpleStore is built on
[simpleCart.js](http://simplecartjs.org) and [Skeleton](http://getskeleton.com)
CSS Framework for a lightweight, fast, simple to use, and completely
customizable experience.



---
# Features
* No Databases, all client-side (just simple HTML, CSS & Javascript)
* Lightweight & Fast
* Tax Rate Calculations
* Unlimited product attributes
* Shipping
* Multiple Currencies
* Payment Gateways (Paypal, Google Checkout, Amazon Payments)
* For more features check out [simpleCart.js](http://simplecartjs.org)
# Plugins
* Google Sheets (Control products from a Google Sheet instead of JSON file)
# Demo
You can see a working demo [here](http://chrisdiana.github.io/simplestore/demo/)
# Installation
Install with Bower
```
bower install
```
or manually install using the latest [release](https://github.com/chrisdiana/simplestore/releases/latest)
# Setup
1.Make sure simpleStore is on a web server (any type will do as long as it can serve static web pages).
2.Configure your payment options in `js/config.js`.
```
checkout: {
type: "PayPal" ,
email: "you@yours.com"
},
```
3.Edit the `js/config.js` to your liking.
4.Add additional products in the `products.json` file.
# Using Plugins
To use a plugin, add a reference just before your `config.js` file
```
<script src="plugins/google-sheets.js"></script>
<script src="js/config.js"></script>
```
## HTML Version
If you are looking for something more basic, check out the [HTML version on this
branch](https://github.com/chrisdiana/simplestore/tree/simplestore-html).
The HTML version uses plain HTML to build the store instead of a JSON
file.
Add additional products using the `<div class="simpleCart_shelfItem"></div>` tags.
## Credit where credit is due
For further documentation on expanding/tweaking simpleStore, check out the
framework/plugin pages.
* [Skeleton](http://getskeleton.com)
* [simpleCart.js](http://simplecartjs.org)
* [Normalize.css](http://necolas.github.io/normalize.css)
* [FontAwesome](http://fortawesome.github.io/Font-Awesome)
* [jQuery](https://jquery.com/)
### A note about JavaScript shopping carts
ALL JavaScript shopping carts are NOT fullproof. Because simpleStore is fully
client-side, some users may attempt to alter prices before checkout.
SimpleStore does the best it can to minimize this
kind of activity. Make sure to monitor your sales. Just like in real life, if someone
walks into your store and changes the price tag, you will certainly not honor
those changes.
# Contributing
All forms of contribution are welcome: bug reports, bug fixes, pull requests and simple suggestions.
If you do wish to contribute, please follow the [Airbnb Javascript Style Guide](https://github.com/airbnb/javascript) Thanks!
## List of contributors
You can find the list of contributors [here](https://github.com/chrisdiana/simplestore/graphs/contributors).
================================================
FILE: bower.json
================================================
{
"name": "simpleStore",
"description": "A clean, responsive storefront boilerplate with no database or backend.",
"version": "1.1.1",
"homepage": "http://cdmedia.github.io/simplestore",
"repository": {
"type": "git",
"url": "https://github.com/cdmedia/simplestore"
},
"main": "index.html",
"license": "MIT",
"dependencies": {
"jquery": "latest",
"skeleton": "~2.0.4",
"fontawesome": "latest"
}
}
================================================
FILE: css/simpleStore.css
================================================
/*
* simplestore
* Copyright 2015 Chris Diana
* https://github.com/cdmedia/simplestore
* Free to use under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
*/
select {
display: block;
float: left;
margin-right: 10px;
}
a.hover {
text-decoration: none;
}
/* Main Layout */
.simpleStore {
margin-top: 20px;
}
.brand {
display: block;
float: left;
text-decoration: none;
color: #000;
}
.brand:hover {
color: #777;
}
.brand img {
max-height: 50px;
}
/* simpleCart */
.simpleCart_shelfItem {
border: 1px solid #EFEFEF;
padding: 25px 18px 10px 18px;
margin: 15px 0;
}
.simpleCart_items {
display: table;
border-collapse: collapse;
width: 100%;
min-height: 20px;
margin-bottom: 50px;
}
.simpleCart_items div:first-child {
width: 100%
}
.simpleCart_decrement, .simpleCart_increment {
font-size: 18px;
line-height: 5px;
text-decoration: none;
}
.simpleCart_shelfItem label {
display: block;
float: left;
line-height: 40px;
margin-right: 10px;
}
.item_thumb, .detail_thumb {
height: 150px;
display: block;
margin: 0 auto;
padding-bottom: 10px;
}
.item_Quantity {
display: inline-block;
width: 50px;
}
.item_price {
font-weight: 700;
font-size: 20px;
line-height: 22px;
}
.item_description {
margin-top: 1rem;
margin-bottom: 1.5rem;
}
.headerRow {
display: table-row;
font-weight: 700;
border-bottom: 1px solid #E1E1E1;
}
.headerRow div {
display: table-cell;
padding: 10px;
}
.itemRow.odd {
background: #FAFAFA;
}
.itemRow {
display: table-row;
border-bottom: 1px solid #E1E1E1;
}
.itemRow:last-child {
border-bottom: 0 solid #fff;
}
.itemRow div {
display: table-cell;
padding: 10px;
}
.itemRow .item-quantity {
text-align: center;
}
/* Cart */
.cart_info {
position: absolute;
bottom: 0px;
right: 0px;
margin: 22px;
text-align: right;
}
.cart_info div {
display: inline;
}
.cart_info_item {
display: block !important;
}
.cart_total {
font-size: 20px;
}
/* Views */
.simpleStore_getDetail_container {
display: block;
float: left;
width: 50%;
padding: 5px 0px;
}
.simpleStore_detailView {
margin: 15px 0px;
border: 1px solid #EFEFEF;
position: relative;
}
.simpleStore_detailView.simpleCart_shelfItem {
padding: 26px 18px 8px 18px;
}
.simpleStore_detailView .item_add {
margin: 0px;
margin-bottom: 0px;
}
.simpleStore_detailView .item_name {
margin-bottom: 1rem;
}
.simpleStore_detailView .item_price {
display: block;
margin-bottom: 1.5rem;
}
.simpleStore_cart_container {
display: none;
}
.simpleStore_cart {
position: relative;
border: 1px solid #EFEFEF;
padding: 22px;
min-height: 230px;
margin: 15px 0px;
}
a.simpleCart_empty {
color: #CDCDCD;
text-decoration: none;
text-transform: uppercase;
font-size: 14px;
}
a.simpleCart_empty:hover {
color: #777;
}
.simpleCart_checkout {
margin: 12px 0px 0px 0px;
}
/* Utility */
.hidden {
display: none;
}
.loader {
display: inline-block;
font-size: 60px;
line-height: 50px;
color: #ddd;
margin: 120px auto;
width: 100%;
height: 50px;
text-align: center;
vertical-align: bottom;
}
a.back {
position: absolute;
top: 10px;
left: 18px;
line-height: 0px;
margin: 0;
padding: 0;
font-size: 34px;
color: #CDCDCD;
text-decoration: none;
}
a.back:hover {
color: #777;
}
a.close {
position: absolute;
top: 18px;
right: 14px;
margin: 0;
line-height: 0px;
padding: 0;
font-size: 32px;
color: #CDCDCD;
text-decoration: none;
font-family: Garamond, "Apple Garamond";
}
a.close:hover {
color: #777;
}
.chevron::before {
border-style: solid;
border-width: 0.1em 0.1em 0 0;
content: '';
display: inline-block;
height: 0.45em;
position: relative;
top: 0.15em;
transform: rotate(-45deg);
vertical-align: top;
width: 0.45em;
left: 0.25em;
transform: rotate(-135deg);
}
.error {
background: #FFE5E5;
padding: 15px;
border-radius: 5px;
position: relative;
margin-bottom: 10px;
}
p.error_text {
margin-bottom: 0rem;
}
.notify {
background: #D9F6FF;
background: rgba(81, 81, 81, 0.8);
color: #fff;
position: fixed;
padding: 14px 0;
text-align: center;
margin: 0 auto;
width: 100%;
font-size: 14px;
top: 0;
right: 0;
top: 0;
z-index: 9999;
}
p.notify_text {
margin-bottom: 0rem;
}
@media (max-width: 920px) {
.simpleStore_getDetail_container {
width: 100%;
}
.simpleCart_shelfItem {
position: relative;
}
.simpleCart_shelfItem .item_name {
font-size: 1.8rem;
}
.simpleStore_getDetail {
position: inherit;
display: block;
width: 100%;
margin: 0px;
margin-bottom: 0px;
}
}
@media (max-width: 620px) {
.simpleStore_detailView .item_thumb {
margin-bottom: 10px;
display: block;
width: 100%;
height: auto;
}
.simpleStore_detailView .item_add {
position: inherit;
display: block;
width: 100%;
}
.cart_info {
position: inherit;
margin: 0px;
padding-top: 15px;
text-align: left;
border-top: 1px solid #E1E1E1;
}
.simpleCart_checkout {
width: 100%;
}
.simpleCart_items {
font-size: 12px;
}
/* Better mobile support for cart */
.item-decrement, .item-increment, .item-total {
display: none !important;
}
}
================================================
FILE: index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Basic Page Needs
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
<meta charset="utf-8">
<title>simpleStore</title>
<meta name="description" content="A clean, responsive storefront boilerplate with no database or backend">
<meta name="author" content="">
<!-- Mobile Specific Metas
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- FONT
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
<link href="//fonts.googleapis.com/css?family=Raleway:400,300,600" rel="stylesheet" type="text/css">
<!-- CSS
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
<link rel="stylesheet" href="css/imports.min.css">
<link rel="stylesheet" href="css/simpleStore.css">
<!-- Favicon
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
<link rel="icon" type="image/png" href="images/favicon.png">
</head>
<body>
<!-- Primary Page Layout
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
<div class="container simpleStore">
<div class="row">
<a class="brand" href="#"></a>
<a class="button button-primary u-pull-right simpleStore_viewCart">
<i class="fa fa-shopping-cart"></i> Cart <span class="simpleCart_total"></span>
</a>
</div>
<div class="simpleStore_container"></div>
<div class="simpleStore_cart_container"></div>
</div>
<!-- Templates
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
<!-- Products View -->
<script id="products-template" type="x-template">
<div class="column">
<div class="simpleCart_shelfItem">
<img src="" class="item_thumb"/>
<div class="row">
<h5 class="item_name"></h5>
<div class="simpleStore_getDetail_container">
<span class="item_price"></span>
</div>
<div class="simpleStore_getDetail_container">
<a class="button u-pull-right simpleStore_getDetail">Details</a>
</div>
</div>
</div>
</div>
</script>
<!-- Product Detail View -->
<script id="product-detail-template" type="x-template">
<div class="simpleCart_shelfItem simpleStore_detailView">
<a href="#" class="close view_close">×</a>
<div class="row">
<div class="four columns">
<img src="" class="item_thumb"/>
</div>
<div class="eight columns">
<h5 class="item_name"></h5>
<p class="item_description"></p>
<span class="item_price"></span>
<div class="qty">
<label>QTY</label>
<input type="number" value="1" min="1" step="1" class="item_Quantity">
</div>
<div class="simpleStore_options"></div>
<a class="item_add button u-pull-right" href="javascript:;">Add to Cart</a>
</div>
</div>
</div>
</script>
<!-- Cart View -->
<script id="cart-template" type="x-template">
<div class="simpleStore_cart">
<h2>Cart</h2>
<a href="#" class="close">×</a>
<div class="row">
<div class="eight columns">
<div class="simpleCart_items"></div>
<a href="javascript:;" class="simpleCart_empty u-pull-left">Empty Cart <i class="fa fa-trash-o"></i></a>
</div>
<div class="four columns">
<div class="cart_info">
<div class="cart_info_item cart_itemcount">Items:
<div class="simpleCart_quantity"></div>
</div>
<div class="cart_info_item cart_taxrate">Tax Rate:
<div class="simpleCart_taxRate"></div>
</div>
<div class="cart_info_item cart_tax">Tax:
<div class="simpleCart_tax"></div>
</div>
<div class="cart_info_item cart_shipping">Shipping:
<div class="simpleCart_shipping"></div>
</div>
<div class="cart_info_item cart_total"><b>Total:
<div class="simpleCart_grandTotal"></div>
</b></div>
<a href="javascript:;" class="button button-primary simpleStore_checkout u-pull-right">Checkout <i class="fa fa-arrow-right"></i></a>
</div>
</div>
</div>
</div>
</script>
<!-- Error View -->
<script id="error-template" type="x-template">
<div class="error">
<b>Sorry, something went wrong :(</b>
<p class="error_text"></p>
<a href="#" class="close alert_close">×</a>
</div>
</script>
<!-- Notify View -->
<script id="notify-template" type="x-template">
<div class="notify">
<p class="notify_text"></p>
</div>
</script>
<!-- End Document
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
</body>
<!-- Scripts
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
<script src="bower_components/jquery/dist/jquery.min.js"></script>
<script src="js/simpleCart.min.js"></script>
<script src="js/simpleStore.js"></script>
<script src="js/config.js"></script>
</html>
================================================
FILE: js/config.js
================================================
$(function() {
simpleCart({
// array representing the format and columns of the cart, see
// the cart columns documentation
cartColumns: [
{ attr: "name" , label: "Name" },
{ attr: "price" , label: "Price", view: 'currency' },
{ view: "decrement" , label: false },
{ attr: "quantity" , label: "Qty" },
{ view: "increment" , label: false },
{ attr: "total" , label: "SubTotal", view: 'currency' },
{ view: "remove" , text: "Remove" , label: false }
],
// "div" or "table" - builds the cart as a table or collection of divs
cartStyle: "div",
// how simpleCart should checkout, see the checkout reference for more info
checkout: {
type: "PayPal" ,
email: "you@yours.com"
},
// set the currency, see the currency reference for more info
currency: "USD",
// collection of arbitrary data you may want to store with the cart,
// such as customer info
data: {},
// set the cart langauge (may be used for checkout)
language: "english-us",
// array of item fields that will not be sent to checkout
excludeFromCheckout: [
'qty',
'thumb'
],
// custom function to add shipping cost
shippingCustom: null,
// flat rate shipping option
shippingFlatRate: 0,
// added shipping based on this value multiplied by the cart quantity
shippingQuantityRate: 0,
// added shipping based on this value multiplied by the cart subtotal
shippingTotalRate: 0,
// tax rate applied to cart subtotal
taxRate: 0,
// true if tax should be applied to shipping
taxShipping: false,
// event callbacks
beforeAdd : null,
afterAdd : null,
load : null,
beforeSave : null,
afterSave : null,
update : null,
ready : null,
checkoutSuccess : null,
checkoutFail : null,
beforeCheckout : null
});
simpleStore.init({
// brand can be text or image URL
brand : "SimpleStore",
// numder of products per row (accepts 1, 2 or 3)
numColumns : 3,
// name of JSON file, located in directory root
JSONFile : "products.json"
});
});
================================================
FILE: js/simpleStore.js
================================================
/*
* simplestore
* Copyright 2015 Chris Diana
* https://github.com/cdmedia/simplestore
* Free to use under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
*/
var simpleStore = {
products: [],
plugins: {},
// Default settings
settings: {
numColumns: 3,
brand: "SimpleStore",
mode: "JSON",
JSONFile: "products.json",
fadeSpeed: 200,
buttonColor: null,
backgroundColor: null,
textColor: null,
container: $('.simpleStore_container'),
cartContainer: $('.simpleStore_cart_container'),
rowClass: 'simpleStore_row_',
columnWidthClasses: {
1: "",
2: "one-half",
3: "one-third"
}
},
productPageOptions: [
'OneOfAKind'
],
extend: function (target, opts, callback) {
var next;
if (typeof opts === "undefined") {
opts = target;
target = simpleStore;
}
for (next in opts) {
if (Object.prototype.hasOwnProperty.call(opts, next)) {
target[next] = opts[next];
}
}
callback(); // check user config options
return target;
},
render: function (url, s) {
var type = url.split('/')[0];
var map = {
// Main view
'': function () {
simpleStore.renderProducts(simpleStore.products, s);
},
// Detail view
'#product': function () {
var id = url.split('#product/')[1].trim();
simpleStore.renderSingleProduct(id, s);
},
// Cart view
'#cart': function () {
simpleStore.renderCart(s);
}
};
if (map[type]) {
map[type]();
} else {
simpleStore.renderError(s);
}
},
insertData: function (tmpl, product) {
tmpl.find('.item_thumb').attr("src", product.image);
tmpl.find('.item_name').text(product.name);
tmpl.find('.item_price').text(product.price);
tmpl.find('.item_description').text(product.description);
},
renderProducts: function (products, s) {
var rowCount = 1,
numProducts = products.length,
numRows = Math.ceil(products.length / s.numColumns),
itemWidth;
s.cartContainer.hide();
s.container.fadeOut(s.fadeSpeed, function () {
// Empty out main container on load
s.container.html('').fadeIn(s.fadeSpeed);
// Build rows based on number of products
for (var r = 0; r < numRows; r++) {
s.container.append('<div class="row ' + s.rowClass + (r + 1) + '"></div>');
}
// Get item column width
var widthClasses = s.columnWidthClasses;
for (var k in widthClasses) {
if (k == s.numColumns) {
itemWidth = widthClasses[k];
}
}
// List layout
products.forEach(function (product, i) {
if (!product.soldOut) {
var tmpl = $('#products-template').html(),
$tmpl = $(tmpl);
// Set item width
$tmpl.first().addClass(itemWidth);
// Insert data into template
simpleStore.insertData($tmpl, product);
// Render detail view on hash change
var getDetail = $tmpl.find('.simpleStore_getDetail');
getDetail.on('click', function (e) {
e.preventDefault();
window.location.hash = 'product/' + product.id;
});
// Check where to add new item based on row
if (i === 0) {
i = 1;
}
if (i % (s.numColumns) === 0) {
rowCount++;
}
// Append to appropriate container
$('.' + s.rowClass + rowCount).append($tmpl);
}
});
});
},
renderProductOptions: function (options, s) {
var optionsLayout = '';
options.forEach(function (option) {
if (!(simpleStore.productPageOptions in option)) {
var selectItems = '';
var attributeLabel = Object.keys(option)[0].trim();
var attributeValues = option[attributeLabel].trim().split(",");
// Set attribute values
$(attributeValues).each(function (attribute, attributeValue) {
selectItems += '<option value="' + attributeValue.replace(/ /g, "_").toLowerCase() + '"> ' + attributeValue + ' </option>';
});
// Build options layout
if (options.length) {
optionsLayout += '<label>' + attributeLabel + '</label><select class="item_' + attributeLabel.replace(/ /g, "_").toLowerCase() + '">' + selectItems + '</select>';
}
} else {
simpleStore.renderProductPageOptions(option);
}
});
return optionsLayout;
},
renderProductPageOptions: function (option) {
if (option.OneOfAKind) {
$('.qty').hide();
}
},
renderSingleProduct: function (id, s) {
s.container.fadeOut(s.fadeSpeed, function () {
var tmpl = $('#product-detail-template').html(),
$tmpl = $(tmpl);
simpleStore.products.forEach(function (product) {
if (product.id == id) {
// Insert data into template
simpleStore.insertData($tmpl, product);
// Load detail view into main container
s.container.html($tmpl);
// Render product options
if (product.options.length) {
var options = simpleStore.renderProductOptions(product.options, s);
$('.simpleStore_options').append(options);
}
s.container.fadeIn(s.fadeSpeed);
}
});
});
},
renderCart: function (s) {
s.container.fadeOut(s.fadeSpeed, function () {
s.cartContainer.fadeIn(s.fadeSpeed);
});
},
renderError: function (s, msg) {
var tmpl = $('#error-template').html(),
$tmpl = $(tmpl);
// Empty out main container on load
s.container.html('').fadeIn(s.fadeSpeed);
if (msg.length) {
$tmpl.find('.error_text').text(msg);
}
s.container.append($tmpl);
s.container.fadeIn(s.fadeSpeed);
$tmpl.find('.alert_close').on('click', function (e) {
e.preventDefault();
$tmpl.fadeOut(s.fadeSpeed, function() {
$tmpl.remove();
});
});
},
handleFailure: function(s, errorMsg) {
setTimeout(function () {
simpleStore.renderError(s, errorMsg);
}, 1000);
},
notifier: function(msg) {
s = this.settings;
var tmpl = $('#notify-template').html(),
$tmpl = $(tmpl);
if (msg.length) {
$tmpl.find('.notify_text').text(msg);
s.container.append($tmpl);
$tmpl.hide();
$tmpl.fadeIn(s.fadeSpeed);
setTimeout(function () {
$tmpl.fadeOut(s.fadeSpeed);
}, 1000);
}
},
initJSON: function (s) {
var errorMsg = 'There was an error loading the JSON file.' +
' Please make sure you have "' + s.JSONFile + '" file in' +
' your main directory.';
// Checks to make sure file exists
$.get(s.JSONFile)
.success(function () {
// Get product data from JSON file
$.getJSON(s.JSONFile, function (data) {
simpleStore.setProducts(data.products);
})
.fail(function () { simpleStore.handleFailure(s, errorMsg); });
})
.fail(function () { simpleStore.handleFailure(s, errorMsg); });
},
checkMode : function (s) {
if (s.hasOwnProperty("spreadsheetID") || s.hasOwnProperty("spreadsheetId")) {
s.mode = "Google";
}
},
checkout : function (s, checkoutData) {
if (!$.isEmptyObject(checkoutData)) {
simpleCart.checkout();
s.cartContainer.fadeOut(s.fadeSpeed, function () {
s.container.html('<i class="fa fa-spin fa-circle-o-notch loader"></i>');
s.container.fadeIn(s.fadeSpeed);
});
}
},
verifyCheckoutData : function (cdata, adata, v) {
for (var d in cdata) {
if (cdata.hasOwnProperty(d)) {
var cp = cdata[d], cn = cp.name, cpp = cp.price;
for (var i = 0; i < adata.length; i++) {
var ap = adata[i], an = ap.name, app = ap.price;
if (cn === an) {if (cpp != app) { v = false; }}
}
}
}
return v;
},
validatePrices : function (s) {
var checkoutData = JSON.parse(localStorage.simpleCart_items),
errorMsg = 'There was an error validating your cart.';
if (s.mode === "JSON") {
$.get(s.JSONFile)
.success(function () {
$.getJSON(s.JSONFile, function (data) {
var JSONData = data.products;
if (simpleStore.verifyCheckoutData(checkoutData, JSONData, true)) {
simpleStore.checkout(s, checkoutData);
} else {
simpleStore.renderError(s, errorMsg);
}
})
.fail(function () { simpleStore.handleFailure(s, errorMsg); });
})
.fail(function () { simpleStore.handleFailure(s, errorMsg); });
} else {
var plugin = s.mode.toLowerCase();
if(simpleStore.plugins[plugin]) {
simpleStore.plugins[plugin].validate(checkoutData);
}
}
},
setProducts: function (products, s) {
if (products.length > 0) {
products.forEach(function (product, index) {
product.id = index + 1;
simpleStore.products.push(product);
});
}
// Manually trigger on initial load
$(window).trigger('hashchange');
},
setLayout: function (s) {
// Set brand
if (s.brand.match('^http://') || s.brand.match('^https://') || s.brand.match('^www.')) {
$('.brand').html('<img src="' + s.brand + '" />');
} else {
$('.brand').html('<h5>' + s.brand + '</h5>');
}
// Set title
$('title').html(s.brand);
},
generateCart: function (s) {
var tmpl = $('#cart-template').html(),
$tmpl = $(tmpl);
s.cartContainer.html($tmpl);
},
generateStore: function () {
var s = this.settings;
// Set mode
this.checkMode(s);
// Check for hash changes
$(window).on('hashchange', function () {
simpleStore.render(window.location.hash, s);
});
// Set products based on mode
switch (s.mode) {
case 'JSON':
this.initJSON(s);
break;
case 'Google':
if(simpleStore.plugins.google) {
simpleStore.plugins.google.init(function (products) {
simpleStore.setProducts(products, s);
});
} else {
var errorMsg = 'There was an error loading the Google plugin. Make sure it is installed properly.';
simpleStore.renderError(s, errorMsg);
}
break;
default:
this.initJSON(s);
}
// Because simpleCart items appends to cart, set up only once
this.generateCart(s);
// Setup layout
this.setLayout(s);
// Handle Checkout
$('.simpleStore_checkout').on('click', function (e) {
e.preventDefault();
simpleStore.validatePrices(s);
});
// View Cart
$('.simpleStore_viewCart').on('click', function (e) {
e.preventDefault();
window.location = '#cart';
});
// Go to home on close
$('.view_close').on('click', function (e) {
e.preventDefault();
window.location.hash = '';
});
// SimpleCart extend
simpleCart({
afterAdd: function() {
simpleStore.notifier('Item added to cart');
}
});
},
init: function (options) {
if ($.isPlainObject(options)) {
return this.extend(this.settings, options, function () {
simpleStore.generateStore();
});
}
}
};
================================================
FILE: package.json
================================================
{
"name": "simplestore",
"version": "1.5",
"description": "A clean, responsive storefront boilerplate with no database or backend.",
"main": "index.html",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/cdmedia/simplestore.git"
},
"author": "Chris Diana",
"license": "MIT",
"bugs": {
"url": "https://github.com/cdmedia/simplestore/issues"
},
"private": true,
"homepage": "https://github.com/cdmedia/simplestore",
"devDependencies": {
"grunt": "~0.4.4",
"grunt-contrib-copy": "latest",
"grunt-contrib-cssmin": "latest",
"grunt-contrib-uglify": "latest",
"grunt-contrib-watch": "latest",
"grunt-file-append": "0.0.6"
}
}
================================================
FILE: plugins/google-sheets/google-sheets.js
================================================
/*
* SimpleStore Google Sheets Plugin
* To use Google spreadsheet as your database, follow the steps below:
* 1. Use the "DemoSpreadsheet.xlsx" as a starting point
* 2. Create a new Google spreadsheet
* 3. Set sharing permissions to either “Public” or set to “Anyone with link can view”
* 4. Publish the sheet (File -> Publish to the web -> Publish)
* 5. Add the spreadsheet ID to your 'config.js' ( spreadsheetID : "XXXXXXXXXXXXXXXXXXXXXXX" )
*/
simpleStore.plugins.google = (function() {
var storeProducts = verifyProducts = [];
function getSpreadsheetData(s, verify, callback) {
verify = typeof verify !== 'undefined' ? verify : false;
var hostname = "https://spreadsheets.google.com";
var format = "json";
var spreadsheetURL = hostname + "/feeds/worksheets/" + s.spreadsheetID + "/public/full?alt=" + format;
var mainsheetURL = hostname + "/feeds/list/" + s.spreadsheetID + "/od6/public/values?alt=" + format;
var settingsSheetName = "Settings";
var productsSheetName = "Products";
var sheetIDs = {};
function getSheetInfo (url, callback) {
// Need to do this because od6 is default Google Sheet ID
$.getJSON(url)
.done(function(data) {
var sheets = data.feed.entry;
$(sheets).each(function(i, sheet) {
var title = sheet.title.$t;
var id = sheet.id.$t;
var sheetID = id.substr(id.lastIndexOf('/') + 1);
if(title == settingsSheetName) {
sheetIDs.settingsSheetID = sheetID;
}
if(title == productsSheetName) {
sheetIDs.productsSheetID = sheetID;
}
});
callback(sheetIDs.settingsSheetID);
loadProductData(sheetIDs.productsSheetID);
});
}
function loadSiteSettings (id, callback) {
var settingsSheetURL = hostname + "/feeds/list/" + s.spreadsheetID + "/" + id + "/public/values?alt=" + format;
$.getJSON(settingsSheetURL)
.done(function(data) {
var data = data.feed.entry;
var s = simpleStore.settings;
if(data[0]) {
var siteName = data[0].gsx$sitenametextorimagelink.$t;
var columns = data[0].gsx$columns123.$t;
if (siteName) {
s.brand = siteName;
}
if (columns) {
s.numColumns = columns;
}
simpleStore.setLayout(s);
}
});
}
function loadProductData (id) {
var productsSheetURL = hostname + "/feeds/list/" + s.spreadsheetID + "/" + id + "/public/values?alt=" + format;
// Get Main Sheet Products data
$.getJSON(productsSheetURL)
.done(function(data) {
var productsData = data.feed.entry;
// Build products
$(productsData).each(function(i) {
var options = this.gsx$options.$t;
var setOptions = function(options) {
var productOptions = [];
if(options) {
var opts = options.split(";").filter(function(el) {return el.length != 0});
$(opts).each(function(i, option) {
var opt = option.trim().split(":"),
key = opt[0],
val = opt[1],
optObj = {};
optObj[key] = val;
productOptions.push(optObj);
});
}
return productOptions;
};
// Get product values
var product = {
name : this.gsx$name.$t,
price : this.gsx$price.$t,
description : this.gsx$description.$t,
options : setOptions(options),
image : this.gsx$image.$t
};
if (verify) {
verifyProducts.push(product);
} else {
storeProducts.push(product);
}
});
callback();
})
.fail(function(data){
if (verify) {
var errorMsg = 'There was an error validating your cart.';
} else {
var errorMsg = 'Error loading spreadsheet data. Make sure the spreadsheet ID is correct.';
}
setTimeout(function(){ simpleStore.renderError(s, errorMsg); }, 1000);
});
}
// Get Sheet data
getSheetInfo(spreadsheetURL, loadSiteSettings);
}
function validatePrices(s, checkoutData) {
verifyProducts = [];
getSpreadsheetData(s, true, function() {
if(simpleStore.verifyCheckoutData(checkoutData, verifyProducts, true)) {
simpleStore.checkout(s, checkoutData);
} else {
var errorMsg = 'There was an error validating your cart.';
simpleStore.renderError(s, errorMsg);
}
});
}
return {
init: function(callback) {
var s = simpleStore.settings;
// Clears out brand to allow for spreadsheet site name
s.brand = "";
simpleStore.setLayout(s);
getSpreadsheetData(s, false, function(){
callback(storeProducts);
});
},
validate: function(checkoutData) {
validatePrices(simpleStore.settings, checkoutData);
}
};
})();
================================================
FILE: products.json
================================================
{
"products" : [
{
"name" : "Awesome T-shirt",
"price" : "35.99",
"options" : [
{ "Size" : "Small,Medium,Large" }
],
"image" : "http://upload.wikimedia.org/wikipedia/commons/c/c6/Grey_Tshirt.jpg",
"description" : "This is a very awesome grey T-shirt"
},
{
"name" : "Cool T-shirt",
"price" : "15.99",
"options" : [
{ "Size" : "Small,Medium,Large" },
{ "Color" : "Blue,Red" },
{ "OneOfAKind" : true }
],
"image" : "http://upload.wikimedia.org/wikipedia/commons/2/24/Blue_Tshirt.jpg",
"description" : "This is a really cool blue T-shirt",
"soldOut" : true
},
{
"name" : "Fun T-shirt",
"price" : "15.99",
"options" : [
{ "Size" : "Small,Medium,Large" }
],
"image" : "http://upload.wikimedia.org/wikipedia/commons/c/c6/Grey_Tshirt.jpg",
"description" : "This is another fun grey T-shirt"
}
]
}
gitextract_sfvr6rzj/ ├── .gitignore ├── Gruntfile.js ├── LICENSE.md ├── README.md ├── bower.json ├── css/ │ └── simpleStore.css ├── index.html ├── js/ │ ├── config.js │ └── simpleStore.js ├── package.json ├── plugins/ │ └── google-sheets/ │ ├── DemoSpreadsheet.xlsx │ └── google-sheets.js └── products.json
SYMBOL INDEX (2 symbols across 1 files)
FILE: plugins/google-sheets/google-sheets.js
function getSpreadsheetData (line 15) | function getSpreadsheetData(s, verify, callback) {
function validatePrices (line 140) | function validatePrices(s, checkoutData) {
Condensed preview — 13 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (44K chars).
[
{
"path": ".gitignore",
"chars": 79,
"preview": ".DS_Store\nnode_modules/*\nbower_components/*\nrelease/*\nrelease.zip\n.idea/\ndev/*\n"
},
{
"path": "Gruntfile.js",
"chars": 1913,
"preview": " module.exports = function(grunt) {\n\n \t/*\n \t * To build a release run 'grunt'\n \t * index.html has to be manually copied "
},
{
"path": "LICENSE.md",
"chars": 1078,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2015 Chris Diana\n\nPermission is hereby granted, free of charge, to any person obtai"
},
{
"path": "README.md",
"chars": 3579,
"preview": "**UPDATES COMING SOON! [Get notified](http://eepurl.com/dHBK11)**\n\n\n[Sign up](http://eepurl.com/gntUvf) to get updates o"
},
{
"path": "bower.json",
"chars": 468,
"preview": "{\n \"name\": \"simpleStore\",\n \"description\": \"A clean, responsive storefront boilerplate with no database or backend."
},
{
"path": "css/simpleStore.css",
"chars": 5641,
"preview": "/*\n* simplestore\n* Copyright 2015 Chris Diana\n* https://github.com/cdmedia/simplestore\n* Free to use under the MIT licen"
},
{
"path": "index.html",
"chars": 5766,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\n <!-- Basic Page Needs\n –––––––––––––––––––––––––––––––––––––––––––––––––"
},
{
"path": "js/config.js",
"chars": 2368,
"preview": "$(function() {\n\tsimpleCart({\n\n\t // array representing the format and columns of the cart, see\n\t // the cart column"
},
{
"path": "js/simpleStore.js",
"chars": 12165,
"preview": "/*\n* simplestore\n* Copyright 2015 Chris Diana\n* https://github.com/cdmedia/simplestore\n* Free to use under the MIT licen"
},
{
"path": "package.json",
"chars": 775,
"preview": "{\n \"name\": \"simplestore\",\n \"version\": \"1.5\",\n \"description\": \"A clean, responsive storefront boilerplate with no data"
},
{
"path": "plugins/google-sheets/google-sheets.js",
"chars": 4642,
"preview": "/*\n * SimpleStore Google Sheets Plugin\n * To use Google spreadsheet as your database, follow the steps below:\n * 1. Use "
},
{
"path": "products.json",
"chars": 883,
"preview": "{\n\t\"products\" : [\n\t\t{\n\t\t\t\"name\" : \"Awesome T-shirt\",\n\t\t\t\"price\" : \"35.99\",\n\t\t\t\"options\" : [\n\t\t\t\t{ \"Size\" : \"Small,Medium"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the chrisdiana/simplestore GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 13 files (38.4 KB), approximately 10.2k tokens, and a symbol index with 2 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.