├── public
├── css
│ ├── products.css
│ ├── auth.css
│ ├── style.min.css
│ ├── addons
│ │ ├── directives.min.css
│ │ ├── rating.min.css
│ │ ├── rating.css
│ │ ├── directives.css
│ │ ├── zmd.hierarchical-display.min.css
│ │ ├── zmd.hierarchical-display.css
│ │ ├── datatables.min.css
│ │ ├── datatables-select.min.css
│ │ ├── datatables-select.css
│ │ └── datatables.css
│ ├── home.css
│ ├── style.css
│ └── general.css
├── scss
│ ├── _custom-styles.scss
│ ├── _custom-variables.scss
│ ├── addons
│ │ ├── _directives.scss
│ │ ├── _rating.scss
│ │ ├── _hierarchical-display.scss
│ │ ├── _datatables.scss
│ │ └── _datatables-select.scss
│ ├── free
│ │ ├── _dropdowns.scss
│ │ ├── _loader.scss
│ │ ├── modules
│ │ │ └── animations-extended
│ │ │ │ └── animations-extended.scss
│ │ ├── _footers.scss
│ │ ├── _badges.scss
│ │ ├── _depreciated.scss
│ │ ├── _input-group.scss
│ │ ├── _list-group.scss
│ │ ├── _cards.scss
│ │ ├── _switch.scss
│ │ ├── _carousels.scss
│ │ ├── _tables.scss
│ │ ├── _pagination.scss
│ │ ├── _buttons.scss
│ │ ├── _navbars.scss
│ │ ├── _msc.scss
│ │ ├── _animations-basic.scss
│ │ ├── _steppers.scss
│ │ └── _treeview.scss
│ ├── style.scss
│ ├── _custom-skin.scss
│ ├── core
│ │ ├── _helpers.scss
│ │ ├── _masks.scss
│ │ ├── bootstrap
│ │ │ └── _functions.scss
│ │ ├── _typography.scss
│ │ ├── _global.scss
│ │ └── _waves.scss
│ ├── mdb.lite.scss
│ └── mdb.scss
├── img
│ ├── flags.png
│ ├── sample.jpg
│ ├── svg
│ │ ├── flags.png
│ │ ├── arrow_left.svg
│ │ └── arrow_right.svg
│ ├── overlays
│ │ ├── 01.png
│ │ ├── 02.png
│ │ ├── 03.png
│ │ ├── 04.png
│ │ ├── 05.png
│ │ ├── 06.png
│ │ ├── 07.png
│ │ ├── 08.png
│ │ └── 09.png
│ ├── carousel
│ │ ├── img1.jpg
│ │ ├── img2.jpg
│ │ └── img3.jpg
│ ├── products
│ │ └── default.jpg
│ └── lightbox
│ │ ├── preloader.gif
│ │ ├── default-skin.png
│ │ └── default-skin.svg
├── font
│ └── roboto
│ │ ├── Roboto-Bold.eot
│ │ ├── Roboto-Bold.ttf
│ │ ├── Roboto-Thin.eot
│ │ ├── Roboto-Thin.ttf
│ │ ├── Roboto-Bold.woff
│ │ ├── Roboto-Bold.woff2
│ │ ├── Roboto-Light.eot
│ │ ├── Roboto-Light.ttf
│ │ ├── Roboto-Light.woff
│ │ ├── Roboto-Light.woff2
│ │ ├── Roboto-Medium.eot
│ │ ├── Roboto-Medium.ttf
│ │ ├── Roboto-Medium.woff
│ │ ├── Roboto-Regular.eot
│ │ ├── Roboto-Regular.ttf
│ │ ├── Roboto-Thin.woff
│ │ ├── Roboto-Thin.woff2
│ │ ├── Roboto-Medium.woff2
│ │ ├── Roboto-Regular.woff
│ │ └── Roboto-Regular.woff2
└── js
│ ├── scripts.js
│ ├── modules
│ ├── scrolling-navbar.js
│ ├── default-file-input.js
│ ├── enhanced-modals.js
│ ├── treeview.js
│ └── bs-custom-file-input.js
│ ├── cart.js
│ └── addons
│ ├── progressBar.min.js
│ ├── progressBar.js
│ ├── rating.min.js
│ ├── jquery.zmd.hierarchical-display.min.js
│ ├── rating.js
│ └── imagesloaded.pkgd.min.js
├── .env.example
├── .gitignore
├── src
├── database
│ ├── categories.json
│ ├── users.json
│ ├── config
│ │ └── config.js
│ ├── models
│ │ ├── Product.js
│ │ ├── OrderItem.js
│ │ ├── User.js
│ │ ├── Order.js
│ │ └── index.js
│ ├── databaseJson.js
│ ├── migrations
│ │ ├── 20220823165755-UserMigration.js
│ │ ├── 20220823171014-ProductMigration.js
│ │ ├── 20220823171705-OrderMigration.js
│ │ └── 20220823172558-OrderItemMigration.js
│ └── products.json
├── middlewares
│ ├── menuMiddleware.js
│ ├── authMiddleware.js
│ ├── redirectIfAutenticated.js
│ ├── userValidationsLogin.js
│ ├── sessionTimeMiddleware.js
│ ├── sessionMiddleware.js
│ └── userValidationsRegister.js
├── routes
│ ├── users.js
│ ├── api.js
│ ├── index.js
│ ├── products.js
│ └── auth.js
├── views
│ ├── errors
│ │ ├── 500.ejs
│ │ └── 404.ejs
│ ├── partials
│ │ ├── scripts.ejs
│ │ ├── head.ejs
│ │ ├── footer.ejs
│ │ ├── product.ejs
│ │ ├── header.ejs
│ │ └── carousel.ejs
│ ├── error.ejs
│ ├── index.ejs
│ ├── products
│ │ ├── list.ejs
│ │ ├── create.ejs
│ │ ├── edit.ejs
│ │ └── detail.ejs
│ ├── auth
│ │ ├── login.ejs
│ │ ├── register.ejs
│ │ └── profile.ejs
│ ├── order.ejs
│ └── cart.ejs
├── controllers
│ ├── apiController.js
│ ├── homeController.js
│ ├── productController.js
│ └── authController.js
└── app.js
├── .sequelizerc
├── package.json
├── README.md
└── bin
└── www
/public/css/products.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | DB_USER=
2 | DB_PASS=
3 | DB_NAME=
--------------------------------------------------------------------------------
/public/scss/_custom-styles.scss:
--------------------------------------------------------------------------------
1 | // Your custom styles
2 |
--------------------------------------------------------------------------------
/public/scss/_custom-variables.scss:
--------------------------------------------------------------------------------
1 | // Your custom variables
2 |
--------------------------------------------------------------------------------
/public/css/auth.css:
--------------------------------------------------------------------------------
1 | .login {
2 | display: grid;
3 | place-items: center;
4 | }
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | yarn.lock
3 | arch_files/
4 | template/
5 | public/img/products
6 | .env
--------------------------------------------------------------------------------
/public/img/flags.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/img/flags.png
--------------------------------------------------------------------------------
/public/img/sample.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/img/sample.jpg
--------------------------------------------------------------------------------
/public/img/svg/flags.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/img/svg/flags.png
--------------------------------------------------------------------------------
/public/img/overlays/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/img/overlays/01.png
--------------------------------------------------------------------------------
/public/img/overlays/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/img/overlays/02.png
--------------------------------------------------------------------------------
/public/img/overlays/03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/img/overlays/03.png
--------------------------------------------------------------------------------
/public/img/overlays/04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/img/overlays/04.png
--------------------------------------------------------------------------------
/public/img/overlays/05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/img/overlays/05.png
--------------------------------------------------------------------------------
/public/img/overlays/06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/img/overlays/06.png
--------------------------------------------------------------------------------
/public/img/overlays/07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/img/overlays/07.png
--------------------------------------------------------------------------------
/public/img/overlays/08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/img/overlays/08.png
--------------------------------------------------------------------------------
/public/img/overlays/09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/img/overlays/09.png
--------------------------------------------------------------------------------
/src/database/categories.json:
--------------------------------------------------------------------------------
1 | [
2 | {"id": 1, "name": "Impresa"},
3 | {"id": 2, "name": "Digital"}
4 | ]
--------------------------------------------------------------------------------
/public/img/carousel/img1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/img/carousel/img1.jpg
--------------------------------------------------------------------------------
/public/img/carousel/img2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/img/carousel/img2.jpg
--------------------------------------------------------------------------------
/public/img/carousel/img3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/img/carousel/img3.jpg
--------------------------------------------------------------------------------
/public/img/products/default.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/img/products/default.jpg
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Bold.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Bold.eot
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Bold.ttf
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Thin.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Thin.eot
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Thin.ttf
--------------------------------------------------------------------------------
/public/img/lightbox/preloader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/img/lightbox/preloader.gif
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Bold.woff
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Bold.woff2
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Light.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Light.eot
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Light.ttf
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Light.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Light.woff
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Light.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Light.woff2
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Medium.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Medium.eot
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Medium.ttf
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Medium.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Medium.woff
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Regular.eot
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Regular.ttf
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Thin.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Thin.woff
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Thin.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Thin.woff2
--------------------------------------------------------------------------------
/public/img/lightbox/default-skin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/img/lightbox/default-skin.png
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Medium.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Medium.woff2
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Regular.woff
--------------------------------------------------------------------------------
/public/font/roboto/Roboto-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sargilla/node-ecommerce/HEAD/public/font/roboto/Roboto-Regular.woff2
--------------------------------------------------------------------------------
/public/scss/addons/_directives.scss:
--------------------------------------------------------------------------------
1 | // Optional directives
2 | @each $key in (0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100) {
3 | .opacity-#{$key} {
4 | opacity: $key * .01;
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/src/middlewares/menuMiddleware.js:
--------------------------------------------------------------------------------
1 | module.exports = (req, res, next) => {
2 | res.locals.active = req.path.split("/")[1]; // [0] will be empty since routes start with '/'
3 | next();
4 | };
5 |
--------------------------------------------------------------------------------
/public/scss/free/_dropdowns.scss:
--------------------------------------------------------------------------------
1 | // Dropdowns
2 | .dropdown {
3 | .dropdown-menu {
4 | .dropdown-item {
5 | &:active {
6 | background-color: $grey-darken-1;
7 | }
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/public/scss/free/_loader.scss:
--------------------------------------------------------------------------------
1 | // Loader / Spinner
2 | .fast {
3 | &.spinner-border {
4 | animation: $spinner-border-animation;
5 | }
6 | &.spinner-grow {
7 | animation: $spinner-grow-animation;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/middlewares/authMiddleware.js:
--------------------------------------------------------------------------------
1 | authMiddleware = (req, res, next) => {
2 | if (!req.session.userLogged) {
3 | return res.redirect("/login");
4 | }
5 |
6 | next();
7 | };
8 |
9 | module.exports = authMiddleware;
10 |
--------------------------------------------------------------------------------
/public/img/svg/arrow_left.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/public/img/svg/arrow_right.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/middlewares/redirectIfAutenticated.js:
--------------------------------------------------------------------------------
1 | redirectIfAutenticated = (req, res, next) => {
2 | if (req.session.userLogged) {
3 | return res.redirect("/profile");
4 | }
5 |
6 | next();
7 | };
8 |
9 | module.exports = redirectIfAutenticated;
10 |
--------------------------------------------------------------------------------
/public/css/style.min.css:
--------------------------------------------------------------------------------
1 | .view,body,html{height:100%}.carousel{height:50%}.carousel .carousel-inner,.carousel .carousel-inner .active,.carousel .carousel-inner .carousel-item{height:100%}@media (max-width:776px){.carousel{height:100%}}.page-footer{background-color:#929FBA}
--------------------------------------------------------------------------------
/public/scss/free/modules/animations-extended/animations-extended.scss:
--------------------------------------------------------------------------------
1 | /*
2 | * MDBootstrap Animations Extended
3 | * Learn more: https://mdbootstrap.com/docs/jquery/css/animations/
4 | * About MDBootstrap: https://mdbootstrap.com/
5 | */
6 |
7 | @import "module";
8 |
--------------------------------------------------------------------------------
/src/routes/users.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const router = express.Router();
3 |
4 | /* GET users listing. */
5 | router.get('/', function(req, res, next) {
6 | res.send('respond with a resource');
7 | });
8 |
9 | module.exports = router;
10 |
--------------------------------------------------------------------------------
/public/css/addons/directives.min.css:
--------------------------------------------------------------------------------
1 | .opacity-0{opacity:0}.opacity-10{opacity:.1}.opacity-20{opacity:.2}.opacity-30{opacity:.3}.opacity-40{opacity:.4}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-80{opacity:.8}.opacity-90{opacity:.9}.opacity-100{opacity:1}
--------------------------------------------------------------------------------
/src/middlewares/userValidationsLogin.js:
--------------------------------------------------------------------------------
1 | const { check } = require("express-validator");
2 |
3 | const validations = [
4 | check("email").isEmail().withMessage("El email es invalido"),
5 | check("password", "Password invalido").notEmpty(),
6 | ];
7 |
8 | module.exports = validations;
9 |
--------------------------------------------------------------------------------
/src/routes/api.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const router = express.Router();
3 |
4 | const controller = require("../controllers/apiController");
5 |
6 | router.get("/product/:id", controller.product);
7 | router.post("/checkout", controller.checkout);
8 |
9 | module.exports = router;
10 |
--------------------------------------------------------------------------------
/public/css/addons/rating.min.css:
--------------------------------------------------------------------------------
1 | .mdb-rating .rate-popover{color:grey}.mdb-rating .live{color:#000}.mdb-rating .oneStar{color:#44370f}.mdb-rating .twoStars{color:#96781e}.mdb-rating .threeStars{color:#e2b52e}.mdb-rating .fourStars{color:#f1ba12}.mdb-rating .fiveStars{color:#f3cb06}.mdb-rating .amber-text{color:#ffc107!important}
--------------------------------------------------------------------------------
/.sequelizerc:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | config: path.resolve('./src/database/config', 'config.js'),
5 | 'models-path': path.resolve('./src/database/models'),
6 | 'seeders-path': path.resolve('./src/database/seeders'),
7 | 'migrations-path': path.resolve('./src/database/migrations'),
8 | }
--------------------------------------------------------------------------------
/public/js/scripts.js:
--------------------------------------------------------------------------------
1 | window.addEventListener("load", function () {
2 | /* Animations initialization */
3 | new WOW().init();
4 |
5 | /* Toastr Initialization */
6 | toastr.options = {
7 | positionClass: "toast-bottom-right",
8 | fadeIn: 300,
9 | fadeOut: 1000,
10 | timeOut: 5000,
11 | extendedTimeOut: 1000,
12 | };
13 | });
14 |
--------------------------------------------------------------------------------
/src/views/errors/500.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%- include('../partials/head') %>
6 |
7 |
8 |
9 | <%- include('../partials/header') %>
10 |
11 |
12 |
Ocurrió un error
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/views/errors/404.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%- include('../partials/head') %>
6 |
7 |
8 |
9 | <%- include('../partials/header') %>
10 |
11 |
12 |
Pagina no encontrada
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/public/css/home.css:
--------------------------------------------------------------------------------
1 | html,
2 | body,
3 | header,
4 | .carousel {
5 | height: 60vh;
6 | }
7 |
8 | @media (max-width: 740px) {
9 | html,
10 | body,
11 | header,
12 | .carousel {
13 | height: 100vh;
14 | }
15 | }
16 |
17 | @media (min-width: 800px) and (max-width: 850px) {
18 | html,
19 | body,
20 | header,
21 | .carousel {
22 | height: 100vh;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/database/users.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": 2,
4 | "email": "juan@juan.com",
5 | "password": "$2a$10$dyX8uOZQCiP6AoQfWCuapuiAyxCcA2CCF7SDSmdh.VAuSIA/RKXjW",
6 | "img": ""
7 | },
8 | {
9 | "id": 3,
10 | "email": "sargilla@gmail.com",
11 | "password": "$2a$10$51r5wHisvhqgxQGteCpDi.GjGsEwY29A3OjvHjZe9QR4DhzY6uz3W",
12 | "img": ""
13 | }
14 | ]
--------------------------------------------------------------------------------
/public/scss/free/_footers.scss:
--------------------------------------------------------------------------------
1 | // Footers
2 | footer {
3 | &.page-footer {
4 | bottom: 0;
5 | color: $white-base;
6 | .container-fluid {
7 | width: auto;
8 | }
9 | .footer-copyright {
10 | overflow: hidden;
11 | color: $footer-copyright-color;
12 | background-color: $footer-copyright-bg-color;
13 | }
14 | a {
15 | color: $white-base;
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/public/scss/free/_badges.scss:
--------------------------------------------------------------------------------
1 | // Badges
2 | .badge {
3 | color: $white !important;
4 | border-radius: $border-radius-base;
5 | box-shadow: $z-depth-1;
6 | }
7 | .badge-pill {
8 | padding-right: $badge-pill-padding-x;
9 | padding-left: $badge-pill-padding-x;
10 | border-radius: $badge-pill-border-radius;
11 | }
12 | @each $name, $color in $basic-mdb-colors {
13 | @include make-badge($name, $color);
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/src/routes/index.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const router = express.Router();
3 |
4 | const controller = require("../controllers/homeController");
5 | const authMiddleware = require("../middlewares/authMiddleware");
6 | /* GET home page. */
7 | router.get("/", controller.home);
8 | router.get("/cart", authMiddleware, controller.cart);
9 | router.get("/order/:id", authMiddleware, controller.order);
10 |
11 | module.exports = router;
12 |
--------------------------------------------------------------------------------
/public/scss/free/_depreciated.scss:
--------------------------------------------------------------------------------
1 | // These settings will be only for one version
2 | // Scrolable navbar
3 |
4 | /*
5 | .navbar {
6 | &.fixed-top,
7 | &.sticky-top {
8 | .navbar-collapse {
9 | @media (min-width: 400px) and (max-width: 767px),
10 | (min-width: 800px) and (max-width: 850px) {
11 | max-height: 340px;
12 | overflow-x: hidden;
13 | overflow-y: auto;
14 | }
15 | }
16 | }
17 | }
18 | */
19 |
--------------------------------------------------------------------------------
/public/css/addons/rating.css:
--------------------------------------------------------------------------------
1 | .mdb-rating .rate-popover {
2 | color: grey; }
3 |
4 | .mdb-rating .live {
5 | color: black; }
6 |
7 | .mdb-rating .oneStar {
8 | color: #44370f; }
9 |
10 | .mdb-rating .twoStars {
11 | color: #96781e; }
12 |
13 | .mdb-rating .threeStars {
14 | color: #e2b52e; }
15 |
16 | .mdb-rating .fourStars {
17 | color: #f1ba12; }
18 |
19 | .mdb-rating .fiveStars {
20 | color: #f3cb06; }
21 |
22 | .mdb-rating .amber-text {
23 | color: #ffc107 !important; }
--------------------------------------------------------------------------------
/public/js/modules/scrolling-navbar.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | (function ($) {
4 | var SCROLLING_NAVBAR_OFFSET_TOP = 50;
5 | $(window).on('scroll', function () {
6 | var $navbar = $('.navbar');
7 |
8 | if ($navbar.length) {
9 | if ($navbar.offset().top > SCROLLING_NAVBAR_OFFSET_TOP) {
10 | $('.scrolling-navbar').addClass('top-nav-collapse');
11 | } else {
12 | $('.scrolling-navbar').removeClass('top-nav-collapse');
13 | }
14 | }
15 | });
16 | })(jQuery);
--------------------------------------------------------------------------------
/public/js/cart.js:
--------------------------------------------------------------------------------
1 | function setCarritoVacio() {
2 | cartRows.innerHTML = `
3 |
4 | No tienes products en el carrito
5 |
6 | `;
7 | }
8 | function vaciarCarrito() {
9 | localStorage.removeItem("carrito");
10 | }
11 |
12 | function calcularTotal(products) {
13 | return products.reduce(
14 | (acum, product) => (acum += product.price * product.quantity),
15 | 0
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/public/scss/addons/_rating.scss:
--------------------------------------------------------------------------------
1 | .mdb-rating {
2 |
3 | .rate-popover {
4 | color: #808080;
5 | }
6 |
7 | .live {
8 | color: #000;
9 | }
10 |
11 | .oneStar {
12 | color: #44370f;
13 | }
14 |
15 | .twoStars {
16 | color: #96781e;
17 | }
18 |
19 | .threeStars {
20 | color: #e2b52e;
21 | }
22 |
23 | .fourStars {
24 | color: #f1ba12;
25 | }
26 |
27 | .fiveStars {
28 | color: #f3cb06;
29 | }
30 |
31 | .amber-text {
32 | color: #ffc107;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/public/css/addons/directives.css:
--------------------------------------------------------------------------------
1 | .opacity-0 {
2 | opacity: 0; }
3 |
4 | .opacity-10 {
5 | opacity: 0.1; }
6 |
7 | .opacity-20 {
8 | opacity: 0.2; }
9 |
10 | .opacity-30 {
11 | opacity: 0.3; }
12 |
13 | .opacity-40 {
14 | opacity: 0.4; }
15 |
16 | .opacity-50 {
17 | opacity: 0.5; }
18 |
19 | .opacity-60 {
20 | opacity: 0.6; }
21 |
22 | .opacity-70 {
23 | opacity: 0.7; }
24 |
25 | .opacity-80 {
26 | opacity: 0.8; }
27 |
28 | .opacity-90 {
29 | opacity: 0.9; }
30 |
31 | .opacity-100 {
32 | opacity: 1; }
--------------------------------------------------------------------------------
/public/scss/free/_input-group.scss:
--------------------------------------------------------------------------------
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 | &.md-addon {
11 | font-weight: 500;
12 | background-color: transparent;
13 | border: none;
14 | }
15 | }
16 | .form-control {
17 | padding: $input-group-form-control-py $input-group-form-control-px;
18 | margin: 0;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/views/partials/scripts.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/views/error.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%- include('../partials/head') %>
6 |
7 |
8 |
9 | <%- include('../partials/header') %>
10 |
11 |
12 |
13 | <%= message %>
14 |
15 |
16 | <%= error.status %>
17 |
18 |
<%= error.stack %>
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/controllers/apiController.js:
--------------------------------------------------------------------------------
1 | const db = require("../database/models");
2 |
3 | module.exports = {
4 | product: async function (req, res) {
5 | let product = await db.Product.findByPk(req.params.id);
6 | return res.json(product);
7 | },
8 | checkout: async function (req, res) {
9 | // return res.send({ ...req.body, userId: req.session.userLogged.id });
10 | let order = await db.Order.create(
11 | { ...req.body, userId: req.session.userLogged.id },
12 | {
13 | include: db.Order.OrderItems,
14 | }
15 | );
16 | res.json({ ok: true, status: 200, order: order });
17 | },
18 | };
19 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "magazine",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "start": "nodemon ./bin/www"
7 | },
8 | "dependencies": {
9 | "bcryptjs": "^2.4.3",
10 | "cookie-parser": "~1.4.4",
11 | "debug": "~2.6.9",
12 | "dotenv": "^16.0.1",
13 | "ejs": "~2.6.1",
14 | "express": "~4.16.1",
15 | "express-session": "^1.17.3",
16 | "express-validator": "^6.14.1",
17 | "http-errors": "~1.6.3",
18 | "method-override": "^3.0.0",
19 | "morgan": "~1.9.1",
20 | "multer": "^1.4.5-lts.1",
21 | "mysql2": "^2.3.3",
22 | "sequelize": "^6.21.4"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/controllers/homeController.js:
--------------------------------------------------------------------------------
1 | const db = require("../database/models");
2 | module.exports = {
3 | home: async function (req, res) {
4 | let products = await db.Product.findAll({
5 | where: {
6 | marked: 1,
7 | },
8 | });
9 |
10 | return res.render("index", { title: "E-Commerce", products });
11 | },
12 | cart: function (req, res) {
13 | return res.render("cart");
14 | },
15 | order: async function (req, res) {
16 | let order = await db.Order.findByPk(req.params.id, {
17 | include: db.Order.OrderItems,
18 | });
19 | // res.send(order);
20 | return res.render("order", { order });
21 | },
22 | };
23 |
--------------------------------------------------------------------------------
/public/js/modules/default-file-input.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | (function ($) {
4 | $('.input-default-wrapper').on('change', '.input-default-js', function (e) {
5 |
6 | var $this = $(e.target),
7 | $label = $this.next('label'),
8 | $files = $this[0].files;
9 | var fileName = '';
10 |
11 | if ($files && $files.length > 1) {
12 | fileName = ($this.attr('data-multiple-target') || '').replace('{target}', $files.length);
13 | } else if (e.target.value) {
14 | fileName = e.target.value.split('\\').pop();
15 | }
16 | fileName ? $label.find('.span-choose-file').html(fileName) : $label.html($label.html());
17 | });
18 | })(jQuery);
--------------------------------------------------------------------------------
/src/database/config/config.js:
--------------------------------------------------------------------------------
1 | require("dotenv").config();
2 | module.exports = {
3 | development: {
4 | username: process.env.DB_USER,
5 | password: process.env.DB_PASS,
6 | database: process.env.DB_NAME,
7 | host: "127.0.0.1",
8 | dialect: "mysql",
9 | },
10 | test: {
11 | username: process.env.DB_USER,
12 | password: process.env.DB_PASS,
13 | database: process.env.DB_NAME,
14 | host: "127.0.0.1",
15 | dialect: "mysql",
16 | },
17 | production: {
18 | username: process.env.DB_USER,
19 | password: process.env.DB_PASS,
20 | database: process.env.DB_NAME,
21 | host: "127.0.0.1",
22 | dialect: "mysql",
23 | },
24 | };
25 |
--------------------------------------------------------------------------------
/src/views/partials/head.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Node E-Commerce
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/public/scss/style.scss:
--------------------------------------------------------------------------------
1 | // Your custom styles
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 | .carousel .carousel-inner {
13 | height: 100%; }
14 | .carousel .carousel-inner .carousel-item,
15 | .carousel .carousel-inner .active {
16 | height: 100%; }
17 |
18 | /* Adjustment for mobile devices*/
19 | @media (max-width: 776px) {
20 | .carousel {
21 | height: 100%; } }
22 |
23 | /* Footer color for sake of consistency with Navbar */
24 | .page-footer {
25 | background-color: #929FBA; }
26 |
--------------------------------------------------------------------------------
/public/scss/free/_list-group.scss:
--------------------------------------------------------------------------------
1 | // List group
2 | .media {
3 | .media-left {
4 | padding: $list-group-padding;
5 |
6 | img {
7 | box-shadow: $z-depth-1;
8 | }
9 | }
10 | }
11 |
12 | .list-group {
13 | .list-group-item {
14 | &:first-child {
15 | border-top-left-radius: $border-radius-base;
16 | border-top-right-radius: $border-radius-base;
17 | }
18 |
19 | &:last-child {
20 | border-bottom-right-radius: $border-radius-base;
21 | border-bottom-left-radius: $border-radius-base;
22 | }
23 | }
24 |
25 | a,
26 | button {
27 | transition: $list-group-transition;
28 |
29 | &:hover {
30 | transition: $list-group-transition;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/public/scss/free/_cards.scss:
--------------------------------------------------------------------------------
1 | // Cards
2 | .card {
3 | font-weight: 400;
4 | border: 0;
5 | box-shadow: $z-depth-1;
6 | &[class*="border"] {
7 | border: 1px solid $grey-base;
8 | box-shadow: none;
9 | }
10 | .card-body {
11 | h1, h2, h3, h4, h5, h6 {
12 | font-weight: 400;
13 | }
14 | .card-title {
15 | a {
16 | transition: $md-card-link-transition;
17 | &:hover {
18 | transition: $md-card-link-transition;
19 | }
20 | }
21 | }
22 | .card-text {
23 | font-size: $md-card-font-size;
24 | font-weight: 400;
25 | color: $md-card-text-color;
26 | }
27 | }
28 | .md-form {
29 | label {
30 | font-weight: 300;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/middlewares/sessionTimeMiddleware.js:
--------------------------------------------------------------------------------
1 | module.exports = (req, res, next) => {
2 | let dateNow = Date.now();
3 | console.log("dateNow", dateNow);
4 | console.log("lastActivity:", req.session.lastActitity);
5 | // reviso si es un usuario
6 | if (req.session.userLogged && req.session.lastActitity) {
7 | // resto las fecha en formato numerico
8 | let compare = dateNow - req.session.lastActitity;
9 | // console.log("fechas comparadas", compare);
10 | // si es mayor a 30 min, redirijo al login
11 | if (compare > 1000 * 60 * 30) {
12 | req.session.destroy();
13 | return res.redirect("/login");
14 | }
15 | // sino actualizo la fecha en formato numerico
16 | req.session.lastActitity = dateNow;
17 | }
18 | return next();
19 | };
20 |
--------------------------------------------------------------------------------
/src/database/models/Product.js:
--------------------------------------------------------------------------------
1 | module.exports = (sequelize, dataTypes) => {
2 | let alias = "Product";
3 | let columns = {
4 | id: {
5 | type: dataTypes.INTEGER(11),
6 | primaryKey: true,
7 | autoIncrement: true,
8 | allowNull: false,
9 | },
10 | name: {
11 | type: dataTypes.STRING(100),
12 | allowNull: false,
13 | },
14 | img: {
15 | type: dataTypes.STRING(100),
16 | allowNull: true,
17 | },
18 | price: {
19 | type: dataTypes.DECIMAL(10, 2),
20 | allowNull: false,
21 | },
22 | marked: {
23 | type: dataTypes.BOOLEAN,
24 | defaultValue: false,
25 | },
26 | };
27 |
28 | let configurations = {};
29 |
30 | const Product = sequelize.define(alias, columns, configurations);
31 |
32 | return Product;
33 | };
34 |
--------------------------------------------------------------------------------
/public/js/modules/enhanced-modals.js:
--------------------------------------------------------------------------------
1 | /*
2 | Enhanced Bootstrap Modals
3 | https://mdbootstrap.com
4 | office@mdbootstrap.com
5 | */
6 |
7 | (function($){
8 | $('body').on('shown.bs.modal', '.modal', function() {
9 | if(!$('.modal-backdrop').length) {
10 |
11 | $modal_dialog = $(this).children('.modal-dialog')
12 |
13 | if($modal_dialog.hasClass('modal-side')) {
14 | $(this).addClass('modal-scrolling');
15 | $('body').addClass('scrollable');
16 | }
17 |
18 | if($modal_dialog.hasClass('modal-frame')) {
19 | $(this).addClass('modal-content-clickable');
20 | $('body').addClass('scrollable');
21 | }
22 | }
23 | });
24 | $('body').on('hidden.bs.modal', '.modal', function() {
25 | $('body').removeClass('scrollable');
26 | });
27 | })(jQuery);
28 |
--------------------------------------------------------------------------------
/public/scss/_custom-skin.scss:
--------------------------------------------------------------------------------
1 | // Your custom skin
2 | // Skins
3 | $skins: () !default;
4 | $skins: map-merge((
5 | "test": (
6 | "skin-primary-color": #fff,
7 | "skin-navbar": #fff,
8 | "skin-footer-color": #fff,
9 | "skin-flat": #fff,
10 | "skin-accent": #fff,
11 | "skin-sidenav-item": #fff,
12 | "skin-sidenav-item-hover": #fff,
13 | "skin-gradient-start": #fff,
14 | "skin-gradient-end": #fff,
15 | "skin-mask-slight": #fff,
16 | "skin-mask-light": #fff,
17 | "skin-mask-strong": #fff,
18 | "skin-sn-child": #fff,
19 | "skin-btn-primary": #fff,
20 | "skin-btn-secondary": #fff,
21 | "skin-btn-default": #fff,
22 | "skin-text": #fff
23 | )
24 | ), $skins);
25 |
26 |
--------------------------------------------------------------------------------
/src/database/databaseJson.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const path = require('path')
3 |
4 | module.exports = {
5 | readJson: function (filename) {
6 | const pJson = fs.readFileSync(path.join(__dirname, filename));
7 | try {
8 | const elements = JSON.parse(pJson)
9 | return elements
10 | } catch (e) {
11 | console.log(`el archivo ${pJson} puede estar vacio`)
12 | return []
13 | }
14 | },
15 | writeJson: function (dataArray, filename) {
16 | const data = JSON.stringify(dataArray, null, 4)
17 | const pJson = fs.writeFileSync(path.join(__dirname, filename), data);
18 | return pJson
19 | },
20 | lastElementId: function(array) {
21 | if (array.length == 0) { return 0 }
22 | return Math.max(...array.map(ele => ele.id))
23 | },
24 | }
--------------------------------------------------------------------------------
/src/middlewares/sessionMiddleware.js:
--------------------------------------------------------------------------------
1 | const db = require("../database/models");
2 | const Users = db.User;
3 |
4 | sessionMiddleware = async (req, res, next) => {
5 | res.locals.userFound = false;
6 | let userFromCookie;
7 |
8 | if (req.session && req.session.userLogged) {
9 | res.locals.userFound = true;
10 | res.locals.userLogged = req.session.userLogged;
11 | if (req.session.userLogged.id === 1) {
12 | res.locals.userAdmin = true;
13 | }
14 | } else {
15 | if (req.cookies.userId) {
16 | userFromCookie = await Users.findOne({
17 | where: { id: req.cookies.userId },
18 | });
19 | }
20 |
21 | if (userFromCookie) {
22 | res.locals.userFound = true;
23 | res.locals.userLogged = req.session.userLogged = userFromCookie;
24 | }
25 | }
26 |
27 | next();
28 | };
29 |
30 | module.exports = sessionMiddleware;
31 |
--------------------------------------------------------------------------------
/public/scss/addons/_hierarchical-display.scss:
--------------------------------------------------------------------------------
1 | .zmd-hierarchical-display {
2 | visibility: hidden;
3 | &.in {
4 | visibility: visible;
5 | }
6 | }
7 | .zmd-hierarchical-displaying {
8 | visibility: visible;
9 | }
10 |
11 | .animation {
12 | animation-duration: 1s;
13 | animation-fill-mode: both;
14 | }
15 |
16 | .animation.zoomedIn,
17 | .animation.zoomedOut {
18 | animation-timing-function: cubic-bezier(.55, 0, .1, 1); // "Swift Out" easing curve
19 | }
20 |
21 | @keyframes zoomedIn {
22 | from {
23 | transform: scale(0);
24 | }
25 | to {
26 | transform: scale(1);
27 | }
28 | }
29 |
30 | @keyframes zoomedOut {
31 | from {
32 | transform: scale(1);
33 | }
34 | to {
35 | transform: scale(0);
36 | }
37 | }
38 |
39 | .zoomedIn {
40 | animation-name: zoomedIn;
41 | }
42 |
43 | .zoomedOut {
44 | animation-name: zoomedOut;
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # E-Commerce
2 |
3 | Proyecto de un E-Commerce en Nodejs, con ejs, base de datos Mysql con Sequelize.
4 |
5 | Este proyecto cuenta con un ABM de productos, registro y login de usuarios, middlewares para rutas de usuario y es un boilerplate para empezar a desarrollar un carrito de compras
6 |
7 | ## Instalación
8 |
9 | Clonar el repo
10 |
11 | ```
12 | git clone git@github.com:sargilla/node-ecommerce.git
13 | ```
14 |
15 | Instalar paquetes
16 |
17 | ```
18 | npm install
19 | ```
20 |
21 | Crear .env para las variables de entorno
22 |
23 | ```
24 | cp .env.example .env
25 | ```
26 |
27 | Crear la base de datos y configurar el .env con los datos de su conexión
28 |
29 | ```
30 | DB_USER=
31 | DB_PASS=
32 | DB_NAME=
33 | ```
34 |
35 | Ejecutar la migración para crear las tablas en la DB_NAME
36 |
37 | ```
38 | sequelize db:migrate
39 | ```
40 |
41 | Inicializar el proyecto
42 |
43 | ```
44 | npm start
45 | ```
46 |
--------------------------------------------------------------------------------
/public/js/addons/progressBar.min.js:
--------------------------------------------------------------------------------
1 | (function($){$.fn.progressBar=function(givenValue){const $this=$(this);function init(selector){const progressValue=selector.children().attr('aria-valuenow');selector.children().width(`${progressValue}%`);selector.children().html(' ');$this.hasClass('md-progress')?selector.children().children().addClass('md-progress-bar-text'):selector.children().children().addClass('progress-bar-text');(progressValue!==100)?selector.children().children().text(`${progressValue}%`):selector.children().children().html(' ')}
2 | function set(selector,value){selector.children().removeClass('success fail active');selector.children().attr('aria-valuenow',value);init(selector);if(value>100){return!1}else if(value===100){selector.children().addClass('success')}else if(value<30){selector.children().addClass('fail')}else{selector.children().addClass('active')}
3 | return!0}
4 | set($this,givenValue)}}(jQuery))
--------------------------------------------------------------------------------
/src/database/models/OrderItem.js:
--------------------------------------------------------------------------------
1 | module.exports = (sequelize, dataTypes) => {
2 | let alias = "OrderItem";
3 | let columns = {
4 | id: {
5 | type: dataTypes.INTEGER(11),
6 | primaryKey: true,
7 | autoIncrement: true,
8 | allowNull: false,
9 | },
10 |
11 | name: {
12 | type: dataTypes.STRING(100),
13 | allowNull: false,
14 | },
15 | price: {
16 | type: dataTypes.DECIMAL(10, 2),
17 | allowNull: false,
18 | },
19 | quantity: {
20 | type: dataTypes.INTEGER(11),
21 | allowNull: false,
22 | },
23 | };
24 | let configurations = {};
25 |
26 | const OrderItem = sequelize.define(alias, columns, configurations);
27 |
28 | OrderItem.associate = (models) => {
29 | OrderItem.belongsTo(models.Order, {
30 | as: "order",
31 | });
32 |
33 | OrderItem.belongsTo(models.Product, {
34 | as: "product",
35 | });
36 | };
37 |
38 | return OrderItem;
39 | };
40 |
--------------------------------------------------------------------------------
/src/database/models/User.js:
--------------------------------------------------------------------------------
1 | module.exports = (sequelize, dataTypes) => {
2 | let alias = "User";
3 | let columns = {
4 | id: {
5 | type: dataTypes.INTEGER(11),
6 | primaryKey: true,
7 | autoIncrement: true,
8 | allowNull: false,
9 | },
10 | name: {
11 | type: dataTypes.STRING(50),
12 | allowNull: false,
13 | },
14 |
15 | email: {
16 | type: dataTypes.STRING(100),
17 | allowNull: false,
18 | },
19 | password: {
20 | type: dataTypes.STRING(100),
21 | allowNull: false,
22 | },
23 | img: {
24 | type: dataTypes.STRING(100),
25 | allowNull: true,
26 | },
27 | };
28 | let configurations = {};
29 |
30 | const User = sequelize.define(alias, columns, configurations);
31 |
32 | User.associate = (models) => {
33 | User.hasMany(models.Order, {
34 | as: "orders",
35 | foreignKey: "userId",
36 | });
37 | };
38 |
39 | return User;
40 | };
41 |
--------------------------------------------------------------------------------
/public/css/style.css:
--------------------------------------------------------------------------------
1 | /* Required height of parents of the Half Page Carousel for proper displaying carousel itself */
2 | html,
3 | body,
4 | .view {
5 | height: 100%;
6 | }
7 |
8 | table.table td,
9 | table.table th {
10 | vertical-align: middle;
11 | }
12 | /* Half Page Carousel itself*/
13 | .carousel {
14 | height: 50%;
15 | }
16 | .carousel .carousel-inner {
17 | height: 100%;
18 | }
19 | .carousel .carousel-inner .carousel-item,
20 | .carousel .carousel-inner .active {
21 | height: 100%;
22 | }
23 |
24 | /* Adjustment for mobile devices*/
25 | @media (max-width: 776px) {
26 | .carousel {
27 | height: 100%;
28 | }
29 | }
30 |
31 | /* Footer color for sake of consistency with Navbar */
32 | .page-footer {
33 | background-color: #929fba;
34 | }
35 |
36 | .cart-number {
37 | position: absolute;
38 | top: 0;
39 | padding-top: 6px;
40 | }
41 |
42 | main.error {
43 | height: 100%;
44 | display: grid;
45 | place-items: center;
46 | }
47 |
48 | main.error h1 {
49 | text-align: center;
50 | }
51 |
--------------------------------------------------------------------------------
/src/views/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%- include('./partials/head') %>
6 |
7 |
8 |
9 |
10 | <%- include('./partials/header') %>
11 |
12 | <%- include('./partials/carousel') %>
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | <% products.forEach( prod=> { %>
27 | <%- include('./partials/product' ,{prod}) %>
28 |
29 | <% } ) %>
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | <%- include('./partials/footer') %>
44 |
45 | <%- include('./partials/scripts') %>
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/src/database/models/Order.js:
--------------------------------------------------------------------------------
1 | module.exports = (sequelize, dataTypes) => {
2 | let alias = "Order";
3 | let columns = {
4 | id: {
5 | type: dataTypes.INTEGER(11),
6 | primaryKey: true,
7 | autoIncrement: true,
8 | allowNull: false,
9 | },
10 | // userId: {
11 | // type: dataTypes.INTEGER(11),
12 | // allowNull: false,
13 | // },
14 | total: {
15 | type: dataTypes.DECIMAL(10, 2),
16 | allowNull: false,
17 | },
18 | paymentMethod: {
19 | type: dataTypes.STRING(25),
20 | allowNull: false,
21 | },
22 | shippingMethod: {
23 | type: dataTypes.STRING(25),
24 | allowNull: true,
25 | },
26 | };
27 | let configurations = {};
28 |
29 | const Order = sequelize.define(alias, columns, configurations);
30 |
31 | Order.associate = (models) => {
32 | Order.User = Order.belongsTo(models.User, {
33 | as: "user",
34 | foreignKey: "userId",
35 | });
36 | Order.OrderItems = Order.hasMany(models.OrderItem, {
37 | as: "orderItems",
38 | });
39 | };
40 |
41 | return Order;
42 | };
43 |
--------------------------------------------------------------------------------
/src/views/products/list.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%- include('../partials/head') %>
6 |
7 |
8 |
9 |
10 | <%- include('../partials/header') %>
11 |
12 |
13 |
Nuestros Productos
14 |
Agregar Producto
15 |
16 |
17 | <% products.forEach( prod=> { %>
18 | <%- include('../partials/product' ,{prod}) %>
19 | <% } ) %>
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | <%- include('../partials/footer') %>
28 | <%- include('../partials/scripts') %>
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/public/scss/free/_switch.scss:
--------------------------------------------------------------------------------
1 | // Switch free
2 | .bs-switch {
3 | position: relative;
4 | display: inline-block;
5 | width: 60px;
6 | height: 34px;
7 | input {
8 | display: none;
9 | &:checked {
10 | + .slider {
11 | background-color: #2196F3;
12 | &:before {
13 | transform: translateX(26px);
14 | }
15 | }
16 | }
17 | &:focus {
18 | + .slider {
19 | box-shadow: 0 0 1px #2196F3;
20 | }
21 | }
22 | }
23 | .slider {
24 | position: absolute;
25 | cursor: pointer;
26 | top: 0;
27 | left: 0;
28 | right: 0;
29 | bottom: 0;
30 | background-color: #ccc;
31 | -webkit-transition: .4s;
32 | transition: .4s;
33 | &:before {
34 | position: absolute;
35 | content: "";
36 | height: 26px;
37 | width: 26px;
38 | left: 4px;
39 | bottom: 4px;
40 | background-color: white;
41 | -webkit-transition: .4s;
42 | transition: .4s;
43 | }
44 | &.round {
45 | border-radius: 34px;
46 | &:before {
47 | border-radius: 50%;
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/database/models/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const Sequelize = require('sequelize');
6 | const basename = path.basename(__filename);
7 | const env = process.env.NODE_ENV || 'development';
8 | const config = require(__dirname + '/../config/config.js')[env];
9 | const db = {};
10 |
11 | let sequelize;
12 | if (config.use_env_variable) {
13 | sequelize = new Sequelize(process.env[config.use_env_variable], config);
14 | } else {
15 | sequelize = new Sequelize(config.database, config.username, config.password, config);
16 | }
17 |
18 | fs
19 | .readdirSync(__dirname)
20 | .filter(file => {
21 | return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
22 | })
23 | .forEach(file => {
24 | const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
25 | db[model.name] = model;
26 | });
27 |
28 | Object.keys(db).forEach(modelName => {
29 | if (db[modelName].associate) {
30 | db[modelName].associate(db);
31 | }
32 | });
33 |
34 | db.sequelize = sequelize;
35 | db.Sequelize = Sequelize;
36 |
37 | module.exports = db;
38 |
--------------------------------------------------------------------------------
/src/routes/products.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const path = require("path");
3 | const router = express.Router();
4 | const multer = require("multer");
5 |
6 | const controller = require("../controllers/productController");
7 |
8 | const storage = multer.diskStorage({
9 | destination: function (req, file, cb) {
10 | cb(null, "public/img/products");
11 | },
12 | filename: function (req, file, cb) {
13 | const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1e9);
14 | cb(
15 | null,
16 | file.fieldname + "-" + uniqueSuffix + path.extname(file.originalname)
17 | );
18 | },
19 | });
20 |
21 | const upload = multer({ storage });
22 |
23 | /* GET home page. */
24 | router.get("/", controller.index);
25 |
26 | /* GET Product */
27 | router.get("/detail/:id", controller.detail);
28 |
29 | //rutas para crear
30 | router.get("/create", controller.create);
31 | router.post("/", upload.single("img"), controller.store);
32 |
33 | //rutas para editar
34 | router.get("/edit/:id", controller.edit);
35 | router.put("/:id", upload.single("img"), controller.update);
36 |
37 | //ruta para eliminar
38 | router.delete("/:id", controller.delete);
39 |
40 | module.exports = router;
41 |
--------------------------------------------------------------------------------
/src/database/migrations/20220823165755-UserMigration.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = {
4 | up: async (queryInterface, Sequelize) => {
5 | await queryInterface.createTable("users", {
6 | id: {
7 | type: Sequelize.INTEGER(11),
8 | primaryKey: true,
9 | autoIncrement: true,
10 | allowNull: false,
11 | },
12 | name: {
13 | type: Sequelize.STRING(50),
14 | allowNull: false,
15 | },
16 |
17 | email: {
18 | type: Sequelize.STRING(100),
19 | allowNull: false,
20 | },
21 | password: {
22 | type: Sequelize.STRING(100),
23 | allowNull: false,
24 | },
25 | img: {
26 | type: Sequelize.STRING(100),
27 | allowNull: true,
28 | },
29 | createdAt: {
30 | allowNull: false,
31 | type: Sequelize.DATE,
32 | },
33 | updatedAt: {
34 | allowNull: false,
35 | type: Sequelize.DATE,
36 | },
37 | deletedAt: {
38 | allowNull: true,
39 | type: Sequelize.DATE,
40 | },
41 | });
42 | },
43 |
44 | down: async (queryInterface, Sequelize) => {
45 | await queryInterface.dropTable("users");
46 | },
47 | };
48 |
--------------------------------------------------------------------------------
/src/database/migrations/20220823171014-ProductMigration.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = {
4 | up: async (queryInterface, Sequelize) => {
5 | await queryInterface.createTable("products", {
6 | id: {
7 | type: Sequelize.INTEGER(11),
8 | primaryKey: true,
9 | autoIncrement: true,
10 | allowNull: false,
11 | },
12 | name: {
13 | type: Sequelize.STRING(100),
14 | allowNull: false,
15 | },
16 | img: {
17 | type: Sequelize.STRING(100),
18 | allowNull: true,
19 | },
20 | price: {
21 | type: Sequelize.DECIMAL(10, 2),
22 | allowNull: false,
23 | },
24 | marked: {
25 | type: Sequelize.BOOLEAN,
26 | defaultValue: false,
27 | },
28 | createdAt: {
29 | allowNull: false,
30 | type: Sequelize.DATE,
31 | },
32 | updatedAt: {
33 | allowNull: false,
34 | type: Sequelize.DATE,
35 | },
36 | deletedAt: {
37 | allowNull: true,
38 | type: Sequelize.DATE,
39 | },
40 | });
41 | },
42 |
43 | down: async (queryInterface, Sequelize) => {
44 | await queryInterface.dropTable("products");
45 | },
46 | };
47 |
--------------------------------------------------------------------------------
/src/middlewares/userValidationsRegister.js:
--------------------------------------------------------------------------------
1 | const { body } = require("express-validator");
2 |
3 | const validations = [
4 | body("nombre")
5 | .trim()
6 | .notEmpty()
7 | .withMessage("Debes de ingresar tu nombre")
8 | .bail()
9 | .isLength({ min: 3, max: 20 })
10 | .withMessage("Debes ingresar entre 3 y 20 caracteres"),
11 | body("email")
12 | .notEmpty()
13 | .withMessage("Debes de ingresar tu email")
14 | .bail()
15 | .isEmail()
16 | .withMessage("Debes ingresar un formato de correo electrónico válido"),
17 | body("password")
18 | .trim()
19 | .notEmpty()
20 | .withMessage("Debes de ingresar una contraseña")
21 | .bail()
22 | .isStrongPassword()
23 | .withMessage(
24 | "Tu contraseña debe tener mínimo 8 caracteres, una mayúscula, una minúscula y un símbolo"
25 | ),
26 | body("confirm-password")
27 | .trim()
28 | .notEmpty()
29 | .withMessage("Debes de ingresar una contraseña")
30 | .bail()
31 | .custom((value, { req }) => {
32 | if (value !== req.body.password) {
33 | // Mensaje en caso de no coincidir
34 | throw new Error("Las contraseñas no coinciden");
35 | }
36 | return true;
37 | }),
38 | ];
39 |
40 | module.exports = validations;
41 |
--------------------------------------------------------------------------------
/public/js/addons/progressBar.js:
--------------------------------------------------------------------------------
1 | (function ($) {
2 | $.fn.progressBar = function (givenValue) {
3 | const $this = $(this);
4 |
5 | function init(selector) {
6 | const progressValue = selector.children().attr('aria-valuenow');
7 | selector.children().width(`${progressValue}%`);
8 | selector.children().html(' ');
9 | $this.hasClass('md-progress') ? selector.children().children().addClass('md-progress-bar-text') : selector.children().children().addClass('progress-bar-text');
10 | (progressValue !== 100) ? selector.children().children().text(`${progressValue}%`) : selector.children().children().html(' ');
11 | }
12 |
13 | function set(selector, value) {
14 | selector.children().removeClass('success fail active');
15 | selector.children().attr('aria-valuenow', value);
16 | init(selector);
17 | if (value > 100) {
18 | return false;
19 | } else if (value === 100) {
20 | selector.children().addClass('success');
21 | } else if (value < 30) {
22 | selector.children().addClass('fail');
23 | } else {
24 | selector.children().addClass('active');
25 | }
26 | return true;
27 | }
28 |
29 | set($this, givenValue);
30 | };
31 | }(jQuery));
32 |
--------------------------------------------------------------------------------
/src/database/products.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": 1,
4 | "name": "producto 1 editado",
5 | "price": "201",
6 | "img": "img-1661268122380-595561361.jpg"
7 | },
8 | {
9 | "id": 2,
10 | "name": "Cambio de nombre",
11 | "price": "200",
12 | "img": "img-1661268130149-305096459.jpg"
13 | },
14 | {
15 | "id": 3,
16 | "name": "prod 3",
17 | "price": "11",
18 | "img": "img-1661268145315-106564143.jpg"
19 | },
20 | {
21 | "id": 4,
22 | "name": "producto 4",
23 | "price": "400",
24 | "img": "img-1661268157858-278932779.jpg"
25 | },
26 | {
27 | "id": 5,
28 | "name": "prodcut con imagen",
29 | "price": "122",
30 | "img": "img-1661268166822-528372102.jpg"
31 | },
32 | {
33 | "id": 6,
34 | "name": "Administrador",
35 | "price": "21",
36 | "img": "img-1661268174526-879242619.jpg"
37 | },
38 | {
39 | "id": 7,
40 | "name": "perocha",
41 | "price": "21",
42 | "img": "img-1661268190564-815606767.jpg"
43 | },
44 | {
45 | "id": 8,
46 | "name": "Otro Mas",
47 | "price": "1343",
48 | "img": "img-1661268339991-990446140.jpg"
49 | }
50 | ]
--------------------------------------------------------------------------------
/public/css/addons/zmd.hierarchical-display.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Material Design Hierarchical Display by Sergey Kupletsky (@zavoloklom) - https://github.com/zavoloklom/material-design-hierarchical-display/
3 | * License - https://github.com/zavoloklom/material-design-hierarchical-display/blob/master/LICENSE (MIT License)
4 | */.zmd-hierarchical-display{visibility:hidden}.zmd-hierarchical-display.in{visibility:visible}.zmd-hierarchical-displaying{visibility:visible}.animation{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.animation.zoomedIn,.animation.zoomedOut{-webkit-animation-timing-function:cubic-bezier(.55,0,.1,1);animation-timing-function:cubic-bezier(.55,0,.1,1)}@-webkit-keyframes zoomedIn{from{-webkit-transform:scale(0);transform:scale(0)}to{-webkit-transform:scale(1);transform:scale(1)}}@keyframes zoomedIn{from{-webkit-transform:scale(0);transform:scale(0)}to{-webkit-transform:scale(1);transform:scale(1)}}@-webkit-keyframes zoomedOut{from{-webkit-transform:scale(1);transform:scale(1)}to{-webkit-transform:scale(0);transform:scale(0)}}@keyframes zoomedOut{from{-webkit-transform:scale(1);transform:scale(1)}to{-webkit-transform:scale(0);transform:scale(0)}}.zoomedIn{-webkit-animation-name:zoomedIn;animation-name:zoomedIn}.zoomedOut{-webkit-animation-name:zoomedOut;animation-name:zoomedOut}
--------------------------------------------------------------------------------
/src/routes/auth.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const path = require("path");
3 | const router = express.Router();
4 | const multer = require("multer");
5 | const { check } = require("express-validator");
6 |
7 | const controller = require("../controllers/authController");
8 | const redirectIfAutenticated = require("../middlewares/redirectIfAutenticated");
9 | const authMiddleware = require("../middlewares/authMiddleware");
10 | const userValidationsLogin = require("../middlewares/userValidationsLogin");
11 |
12 | // const storage = multer.diskStorage({
13 | // destination: function (req, file, cb) {
14 | // cb(null, 'public/img/users')
15 | // },
16 | // filename: function (req, file, cb) {
17 | // const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9)
18 | // cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname))
19 | // }
20 | // })
21 |
22 | // const upload = multer ({storage})
23 |
24 | router.get("/login", redirectIfAutenticated, controller.showLogin);
25 | router.post("/login", controller.login);
26 |
27 | router.get("/register", redirectIfAutenticated, controller.showRegister);
28 | router.post("/register", userValidationsLogin, controller.register);
29 |
30 | router.post("/logout", controller.logout);
31 |
32 | router.get("/profile", authMiddleware, controller.profile);
33 |
34 | module.exports = router;
35 |
--------------------------------------------------------------------------------
/src/database/migrations/20220823171705-OrderMigration.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = {
4 | up: async (queryInterface, Sequelize) => {
5 | await queryInterface.createTable("orders", {
6 | id: {
7 | type: Sequelize.INTEGER(11),
8 | primaryKey: true,
9 | autoIncrement: true,
10 | allowNull: false,
11 | },
12 | userId: {
13 | type: Sequelize.INTEGER(11),
14 | allowNull: false,
15 | references: {
16 | model: {
17 | tableName: "users",
18 | },
19 | key: "id",
20 | },
21 | },
22 | total: {
23 | type: Sequelize.DECIMAL(10, 2),
24 | allowNull: false,
25 | },
26 | paymentMethod: {
27 | type: Sequelize.STRING(25),
28 | allowNull: false,
29 | },
30 | shippingMethod: {
31 | type: Sequelize.STRING(25),
32 | allowNull: true,
33 | },
34 | createdAt: {
35 | allowNull: false,
36 | type: Sequelize.DATE,
37 | },
38 | updatedAt: {
39 | allowNull: false,
40 | type: Sequelize.DATE,
41 | },
42 | deletedAt: {
43 | allowNull: true,
44 | type: Sequelize.DATE,
45 | },
46 | });
47 | },
48 |
49 | down: async (queryInterface, Sequelize) => {
50 | await queryInterface.dropTable("orders");
51 | },
52 | };
53 |
--------------------------------------------------------------------------------
/public/scss/free/_carousels.scss:
--------------------------------------------------------------------------------
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 | cursor: pointer;
19 | border-radius: $carousel-indicators-border-radius;
20 | }
21 | }
22 | }
23 | .carousel-fade {
24 | .carousel-item {
25 | opacity: 0;
26 | transition-duration: $carousel-transition-duration;
27 | transition-property: opacity;
28 | }
29 | .carousel-item.active,
30 | .carousel-item-next.carousel-item-left,
31 | .carousel-item-prev.carousel-item-right {
32 | opacity: 1;
33 | }
34 | .carousel-item-left,
35 | .carousel-item-right {
36 | &.active {
37 | opacity: 0;
38 | }
39 | }
40 | .carousel-item-next,
41 | .carousel-item-prev,
42 | .carousel-item.active,
43 | .carousel-item-left.active,
44 | .carousel-item-prev.active {
45 | transform: $carousel-item-transform;
46 | @supports (transform-style: preserve-3d) {
47 | transform: $carousel-item-transform-2;
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/views/partials/footer.ejs:
--------------------------------------------------------------------------------
1 |
2 |
46 |
--------------------------------------------------------------------------------
/public/scss/core/_helpers.scss:
--------------------------------------------------------------------------------
1 | // Helpers
2 | // MDB helpers
3 | .img-fluid,
4 | .video-fluid {
5 | max-width: 100%;
6 | height: auto;
7 | }
8 |
9 | .flex-center {
10 | display: flex;
11 | align-items: center;
12 | justify-content: center;
13 | height: 100%;
14 |
15 | p {
16 | margin: 0;
17 | }
18 |
19 | ul {
20 | text-align: center;
21 |
22 | li {
23 | margin-bottom: $flex-center-ul-mb;
24 |
25 | &:last-of-type {
26 | margin-bottom: 0;
27 | }
28 | }
29 | }
30 | }
31 |
32 | .hr-light {
33 | border-top: 1px solid $hr-light;
34 | }
35 |
36 | .hr-dark {
37 | border-top: 1px solid $hr-dark;
38 | }
39 |
40 | // Responsive width
41 | .w-responsive {
42 | width: 75%;
43 |
44 | @media (max-width: 740px) {
45 | width: 100%;
46 | }
47 | }
48 |
49 | // Collapsible body
50 | .collapsible-body {
51 | display: none;
52 | }
53 |
54 | .jumbotron {
55 | background-color: $white-base;
56 | border-radius: $border-radius-base;
57 | box-shadow: $z-depth-1;
58 | }
59 |
60 | @each $name,
61 | $color in $basic-mdb-colors {
62 | @include bg-variant(".bg-#{$name}", $color);
63 |
64 | .border-#{$name} {
65 | border-color: $color !important;
66 | }
67 | }
68 |
69 | .card-img-100 {
70 | width: 100px;
71 | height: 100px;
72 | }
73 |
74 | .card-img-64 {
75 | width: 64px;
76 | height: 64px;
77 | }
78 |
79 | .mml-1 {
80 | margin-left: - .25rem !important;
81 | }
82 |
83 | .flex-1 {
84 | flex: 1;
85 | }
86 |
--------------------------------------------------------------------------------
/public/img/lightbox/default-skin.svg:
--------------------------------------------------------------------------------
1 | default-skin 2
--------------------------------------------------------------------------------
/public/scss/core/_masks.scss:
--------------------------------------------------------------------------------
1 | // Masks
2 | // General properties
3 | .view {
4 | position: relative;
5 | overflow: hidden;
6 | cursor: default;
7 | .mask {
8 | position: absolute;
9 | top: 0;
10 | right: 0;
11 | bottom: 0;
12 | left: 0;
13 | width: 100%;
14 | height: 100%;
15 | overflow: hidden;
16 | background-attachment: fixed;
17 | }
18 | img, video {
19 | position: relative;
20 | display: block;
21 | }
22 | video {
23 | &.video-intro {
24 | top: 50%;
25 | left: 50%;
26 | z-index: -100;
27 | width: auto;
28 | min-width: 100%;
29 | height: auto;
30 | min-height: 100%;
31 | transition: $intro-video-transition opacity;
32 | transform: $intro-video-transform;
33 | }
34 | }
35 | }
36 |
37 | // Overlay
38 | .overlay {
39 | .mask {
40 | opacity: 0;
41 | transition: $mask-overlay-transition;
42 | &:hover {
43 | opacity: 1;
44 | }
45 | }
46 | }
47 |
48 | // Zoom
49 | .zoom {
50 | img, video {
51 | transition: $mask-zoom-transition;
52 | }
53 | &:hover {
54 | img, video {
55 | transform: $mask-zoom-transform;
56 | }
57 | }
58 | }
59 |
60 | // Patterns
61 | $patterns: (
62 | 1: "01",
63 | 2: "02",
64 | 3: "03",
65 | 4: "04",
66 | 5: "05",
67 | 6: "06",
68 | 7: "07",
69 | 8: "08",
70 | 9: "09"
71 | ) !default;
72 |
73 | @each $no, $filename in $patterns {
74 | .pattern-#{$no} {
75 | background: url("#{$image-path}/overlays/#{$filename}.png");
76 | background-attachment: fixed;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/database/migrations/20220823172558-OrderItemMigration.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = {
4 | up: async (queryInterface, Sequelize) => {
5 | await queryInterface.createTable("orderitems", {
6 | id: {
7 | type: Sequelize.INTEGER(11),
8 | primaryKey: true,
9 | autoIncrement: true,
10 | allowNull: false,
11 | },
12 | orderId: {
13 | type: Sequelize.INTEGER(11),
14 | allowNull: false,
15 | references: {
16 | model: {
17 | tableName: "orders",
18 | },
19 | key: "id",
20 | },
21 | },
22 | productId: {
23 | type: Sequelize.INTEGER(11),
24 | allowNull: true,
25 | references: {
26 | model: {
27 | tableName: "products",
28 | },
29 | key: "id",
30 | },
31 | },
32 | name: {
33 | type: Sequelize.STRING(100),
34 | allowNull: false,
35 | },
36 | price: {
37 | type: Sequelize.DECIMAL(10, 2),
38 | allowNull: false,
39 | },
40 | quantity: {
41 | type: Sequelize.INTEGER(11),
42 | allowNull: false,
43 | },
44 | createdAt: {
45 | allowNull: false,
46 | type: Sequelize.DATE,
47 | },
48 | updatedAt: {
49 | allowNull: false,
50 | type: Sequelize.DATE,
51 | },
52 | deletedAt: {
53 | allowNull: true,
54 | type: Sequelize.DATE,
55 | },
56 | });
57 | },
58 |
59 | down: async (queryInterface, Sequelize) => {
60 | await queryInterface.dropTable("orderitems");
61 | },
62 | };
63 |
--------------------------------------------------------------------------------
/public/scss/free/_tables.scss:
--------------------------------------------------------------------------------
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 | // &.btn {
24 | // color: inherit;
25 | // }
26 | }
27 | .label-table {
28 | height: $table-label-line-height;
29 | padding: 0;
30 | margin: 0;
31 | line-height: $table-label-height;
32 | }
33 | &.btn-table {
34 | td {
35 | vertical-align: middle;
36 | }
37 | }
38 | }
39 | &.table-hover {
40 | tbody {
41 | tr {
42 | &:hover {
43 | background-color: $table-hover-background-color;
44 | transition: $table-hover-transition;
45 | }
46 | }
47 | }
48 | }
49 | .th-lg {
50 | min-width: $table-th-lg-min-width;
51 | }
52 | .th-sm {
53 | min-width: $table-th-sm-min-width;
54 | }
55 | &.table-sm {
56 | th,
57 | td {
58 | padding-top: $table-sm-padding-y;
59 | padding-bottom: $table-sm-padding-y;
60 | }
61 | }
62 | }
63 | .table-scroll-vertical {
64 | max-height: $table-scroll-vertical-max-height;
65 | overflow-y: auto;
66 | }
67 | .table-fixed {
68 | table-layout: fixed;
69 | }
70 | .table-responsive,
71 | .table-responsive-sm,
72 | .table-responsive-md,
73 | .table-responsive-lg,
74 | .table-responsive-xl {
75 | > .table-bordered {
76 | border-top: 1px solid #dee2e6;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/public/scss/mdb.lite.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Material Design for Bootstrap 4
3 | * Version: MDB Lite 4.8.11
4 | *
5 | *
6 | * Copyright: Material Design for Bootstrap
7 | * https://mdbootstrap.com/
8 | *
9 | * Read the license: https://mdbootstrap.com/general/license/
10 | *
11 | *
12 | * Documentation: https://mdbootstrap.com/
13 | *
14 | * Getting started: https://mdbootstrap.com/docs/jquery/getting-started/download/
15 | *
16 | * Tutorials: https://mdbootstrap.com/education/bootstrap/
17 | *
18 | * Templates: https://mdbootstrap.com/templates/
19 | *
20 | * Support: https://mdbootstrap.com/support/
21 | *
22 | * Contact: office@mdbootstrap.com
23 | *
24 | * Attribution: Animate CSS, Twitter Bootstrap, Materialize CSS, Normalize CSS, Waves JS, WOW JS, Toastr, Chart.js
25 | *
26 | */
27 |
28 | @charset "UTF-8";
29 |
30 | // Bootstrap
31 | @import "core/bootstrap/functions";
32 | @import "core/bootstrap/variables";
33 |
34 | // CORE
35 | @import "core/mixins";
36 | // Your custom variables
37 | @import "custom-variables";
38 | @import "core/colors";
39 | @import "core/variables";
40 | @import "core/global";
41 | @import "core/helpers";
42 | @import "core/typography";
43 | @import "core/masks";
44 | @import "core/waves";
45 |
46 | // FREE
47 | @import "free/animations-basic";
48 | @import "free/buttons";
49 | @import "free/cards";
50 | @import "free/dropdowns";
51 | @import "free/input-group";
52 | @import "free/navbars";
53 | @import "free/pagination";
54 | @import "free/badges";
55 | @import "free/modals";
56 | @import "free/carousels";
57 | @import "free/forms";
58 | @import "free/msc";
59 | @import "free/footers";
60 | @import "free/list-group";
61 | @import "free/tables";
62 | @import "free/depreciated";
63 | @import "free/steppers";
64 | @import "free/loader";
65 | @import "free/treeview";
66 |
67 | // Your custom styles
68 | @import "custom-styles";
69 |
--------------------------------------------------------------------------------
/public/css/addons/zmd.hierarchical-display.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Material Design Hierarchical Display by Sergey Kupletsky (@zavoloklom) - https://github.com/zavoloklom/material-design-hierarchical-display/
3 | * License - https://github.com/zavoloklom/material-design-hierarchical-display/blob/master/LICENSE (MIT License)
4 | */
5 | .zmd-hierarchical-display {
6 | visibility: hidden; }
7 | .zmd-hierarchical-display.in {
8 | visibility: visible; }
9 |
10 | .zmd-hierarchical-displaying {
11 | visibility: visible; }
12 |
13 | .animation {
14 | -webkit-animation-duration: 1s;
15 | animation-duration: 1s;
16 | -webkit-animation-fill-mode: both;
17 | animation-fill-mode: both; }
18 |
19 | .animation.zoomedIn,
20 | .animation.zoomedOut {
21 | -webkit-animation-timing-function: cubic-bezier(0.55, 0, 0.1, 1);
22 | animation-timing-function: cubic-bezier(0.55, 0, 0.1, 1); }
23 |
24 | @-webkit-keyframes zoomedIn {
25 | from {
26 | -webkit-transform: scale(0);
27 | transform: scale(0); }
28 | to {
29 | -webkit-transform: scale(1);
30 | transform: scale(1); } }
31 |
32 | @keyframes zoomedIn {
33 | from {
34 | -webkit-transform: scale(0);
35 | transform: scale(0); }
36 | to {
37 | -webkit-transform: scale(1);
38 | transform: scale(1); } }
39 |
40 | @-webkit-keyframes zoomedOut {
41 | from {
42 | -webkit-transform: scale(1);
43 | transform: scale(1); }
44 | to {
45 | -webkit-transform: scale(0);
46 | transform: scale(0); } }
47 |
48 | @keyframes zoomedOut {
49 | from {
50 | -webkit-transform: scale(1);
51 | transform: scale(1); }
52 | to {
53 | -webkit-transform: scale(0);
54 | transform: scale(0); } }
55 |
56 | .zoomedIn {
57 | -webkit-animation-name: zoomedIn;
58 | animation-name: zoomedIn; }
59 |
60 | .zoomedOut {
61 | -webkit-animation-name: zoomedOut;
62 | animation-name: zoomedOut; }
63 |
--------------------------------------------------------------------------------
/src/views/auth/login.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%- include('../partials/head') %>
6 |
7 |
8 |
9 |
10 |
11 | <%- include('../partials/header') %>
12 |
13 |
43 |
44 | <%- include('../partials/footer') %>
45 | <%- include('../partials/scripts') %>
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/controllers/productController.js:
--------------------------------------------------------------------------------
1 | const db = require("../database/models");
2 |
3 | const controller = {
4 | index: async function (req, res) {
5 | let products = await db.Product.findAll();
6 | return res.render("products/list", { products });
7 | },
8 | detail: async function (req, res) {
9 | let product = db.Product.findByPk(req.params.id);
10 | return res.render("products/detail", { product });
11 | },
12 | create: function (req, res) {
13 | return res.render("products/create");
14 | },
15 | store: async function (req, res) {
16 | let image = "";
17 | if (req.file) {
18 | image = req.file.filename;
19 | }
20 |
21 | //guardo el nuevo producto con la estructura
22 | await db.Product.create({
23 | name: req.body.name,
24 | price: req.body.price,
25 | img: image,
26 | marked: req.body.marked ? true : false,
27 | });
28 |
29 | //redireccione al listado de productos
30 | return res.redirect("/products");
31 | },
32 | edit: async function (req, res) {
33 | let product = await db.Product.findByPk(req.params.id);
34 | if (product) {
35 | return res.render("products/edit", { product });
36 | }
37 | return res.redirect("/products");
38 | },
39 | update: async function (req, res) {
40 | let product = await db.Product.findByPk(req.params.id);
41 | if (product) {
42 | let image = product.img;
43 | if (req.file) {
44 | image = req.file.filename;
45 | }
46 | await product.update({
47 | name: req.body.name,
48 | price: req.body.price,
49 | img: image,
50 | marked: req.body.marked ? true : false,
51 | });
52 | }
53 | return res.redirect("/products");
54 | },
55 | delete: async function (req, res) {
56 | await db.Product.destroy({
57 | where: { id: req.params.id },
58 | });
59 |
60 | res.redirect("/products");
61 | },
62 | };
63 |
64 | module.exports = controller;
65 |
--------------------------------------------------------------------------------
/bin/www:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * Module dependencies.
5 | */
6 |
7 | var app = require('../src/app');
8 | var debug = require('debug')('magazine:server');
9 | var http = require('http');
10 |
11 | /**
12 | * Get port from environment and store in Express.
13 | */
14 |
15 | var port = normalizePort(process.env.PORT || '3000');
16 | app.set('port', port);
17 |
18 | /**
19 | * Create HTTP server.
20 | */
21 |
22 | var server = http.createServer(app);
23 |
24 | /**
25 | * Listen on provided port, on all network interfaces.
26 | */
27 |
28 | server.listen(port);
29 | server.on('error', onError);
30 | server.on('listening', onListening);
31 |
32 | /**
33 | * Normalize a port into a number, string, or false.
34 | */
35 |
36 | function normalizePort(val) {
37 | var port = parseInt(val, 10);
38 |
39 | if (isNaN(port)) {
40 | // named pipe
41 | return val;
42 | }
43 |
44 | if (port >= 0) {
45 | // port number
46 | return port;
47 | }
48 |
49 | return false;
50 | }
51 |
52 | /**
53 | * Event listener for HTTP server "error" event.
54 | */
55 |
56 | function onError(error) {
57 | if (error.syscall !== 'listen') {
58 | throw error;
59 | }
60 |
61 | var bind = typeof port === 'string'
62 | ? 'Pipe ' + port
63 | : 'Port ' + port;
64 |
65 | // handle specific listen errors with friendly messages
66 | switch (error.code) {
67 | case 'EACCES':
68 | console.error(bind + ' requires elevated privileges');
69 | process.exit(1);
70 | break;
71 | case 'EADDRINUSE':
72 | console.error(bind + ' is already in use');
73 | process.exit(1);
74 | break;
75 | default:
76 | throw error;
77 | }
78 | }
79 |
80 | /**
81 | * Event listener for HTTP server "listening" event.
82 | */
83 |
84 | function onListening() {
85 | var addr = server.address();
86 | var bind = typeof addr === 'string'
87 | ? 'pipe ' + addr
88 | : 'port ' + addr.port;
89 | debug('Listening on ' + bind);
90 | }
91 |
--------------------------------------------------------------------------------
/src/views/products/create.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%- include('../partials/head') %>
6 |
7 |
8 |
9 |
10 |
11 | <%- include('../partials/header') %>
12 |
13 |
14 |
Nuevo Producto
15 |
41 |
42 |
43 | <%- include('../partials/footer') %>
44 | <%- include('../partials/scripts') %>
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/views/partials/product.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
21 |
22 | $<%= prod.price %>
23 |
24 |
25 | Comprar
26 |
27 | <% if (locals.userFound && locals.userAdmin) { %>
28 |
38 | <% } %>
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/public/scss/mdb.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Material Design for Bootstrap 4
3 | * Version: MDB FREE 4.8.11
4 | *
5 | *
6 | * Copyright: Material Design for Bootstrap
7 | * https://mdbootstrap.com/
8 | *
9 | * Read the license: https://mdbootstrap.com/general/license/
10 | *
11 | *
12 | * Documentation: https://mdbootstrap.com/
13 | *
14 | * Getting started: https://mdbootstrap.com/docs/jquery/getting-started/download/
15 | *
16 | * Tutorials: https://mdbootstrap.com/education/bootstrap/
17 | *
18 | * Templates: https://mdbootstrap.com/templates/
19 | *
20 | * Support: https://mdbootstrap.com/support/
21 | *
22 | * Contact: office@mdbootstrap.com
23 | *
24 | * Attribution: Animate CSS, Twitter Bootstrap, Materialize CSS, Normalize CSS, Waves JS, WOW JS, Toastr, Chart.js
25 | *
26 | */
27 |
28 | @charset "UTF-8";
29 |
30 | // Bootstrap
31 | @import "core/bootstrap/functions";
32 | @import "core/bootstrap/variables";
33 | @import "core/bootstrap/rfs";
34 |
35 | // CORE
36 | @import "core/mixins";
37 | // Your custom variables
38 | @import "custom-variables";
39 | @import "core/colors";
40 | @import "core/variables";
41 | @import "core/global";
42 | @import "core/helpers";
43 | @import "core/typography";
44 | @import "core/masks";
45 | @import "core/waves";
46 |
47 | // FREE
48 | @import "free/animations-basic";
49 | @import "free/modules/animations-extended/module";
50 | @import "free/buttons";
51 | @import "free/cards";
52 | @import "free/dropdowns";
53 | @import "free/input-group";
54 | @import "free/navbars";
55 | @import "free/pagination";
56 | @import "free/badges";
57 | @import "free/modals";
58 | @import "free/carousels";
59 | @import "free/forms";
60 | @import "free/msc";
61 | @import "free/footers";
62 | @import "free/list-group";
63 | @import "free/tables";
64 | @import "free/depreciated";
65 | @import "free/steppers";
66 | @import "free/loader";
67 | @import "free/treeview";
68 | // Free addons
69 | // @import "addons/datatables";
70 | // @import "addons/datatables-select";
71 | // @import "addons/directives";
72 | // @import "addons/hierarchical-display";
73 | // @import "addons/flags";
74 | // @import "addons/rating";
75 |
76 | // Your custom styles
77 | @import "custom-styles";
78 |
--------------------------------------------------------------------------------
/src/views/products/edit.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%- include('../partials/head') %>
6 |
7 |
8 |
9 |
10 |
11 | <%- include('../partials/header') %>
12 |
13 |
14 |
Editar Producto
15 |
46 |
47 |
48 |
49 | <%- include('../partials/footer') %>
50 | <%- include('../partials/scripts') %>
51 |
52 |
53 |
--------------------------------------------------------------------------------
/public/scss/free/_pagination.scss:
--------------------------------------------------------------------------------
1 | // Pagination
2 | .pagination {
3 | .page-item {
4 | &.active {
5 | .page-link {
6 | color: $white-base;
7 | background-color: $primary-color;
8 | border-radius: $border-radius-base;
9 | box-shadow: $z-depth-1;
10 | transition: $pagination-active-transition;
11 | &:hover {
12 | background-color: $primary-color;
13 | }
14 | }
15 | }
16 | &.disabled {
17 | .page-link {
18 | color: $pagination-page-item-disabled-color;
19 | }
20 | }
21 | .page-link {
22 | font-size: $pagination-page-link-font-size;
23 | color: $pagination-page-link-color;
24 | background-color: transparent;
25 | border: 0;
26 | outline: 0;
27 | transition: $pagination-page-link-transition;
28 | &:hover {
29 | background-color: $pagination-page-link-hover-bg-color;
30 | border-radius: $border-radius-base;
31 | transition: $pagination-page-link-transition;
32 | }
33 | &:focus {
34 | background-color: transparent;
35 | box-shadow: none;
36 | }
37 | }
38 | }
39 | &.pagination-lg {
40 | .page-item {
41 | .page-link {
42 | font-size: $pagination-page-link-font-size-lg;
43 | }
44 | }
45 | }
46 | &.pagination-sm {
47 | .page-item {
48 | .page-link {
49 | font-size: $pagination-page-link-font-size-sm;
50 | }
51 | }
52 | }
53 | &.pagination-circle {
54 | .page-item {
55 | .page-link {
56 | margin-right: $pagination-circle-margin-x;
57 | margin-left: $pagination-circle-margin-x;
58 | border-radius: $pagination-circle-border-radius;
59 | &:hover {
60 | border-radius: $pagination-circle-border-radius;
61 | }
62 | }
63 | &.active {
64 | .page-link {
65 | border-radius: $pagination-circle-border-radius;
66 | }
67 | }
68 | }
69 | }
70 | @each $name, $color in $pagination-colors {
71 | &.pg-#{$name} {
72 | .page-item {
73 | &.active {
74 | .page-link {
75 | background-color: $color;
76 | &:hover {
77 | background-color: $color;
78 | }
79 | }
80 | }
81 | }
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/public/css/general.css:
--------------------------------------------------------------------------------
1 | * {
2 | padding: 0;
3 | margin: 0;
4 | box-sizing: border-box;
5 | text-decoration: none;
6 | font-family: 'Kdam Thmor Pro', sans-serif;
7 | }
8 |
9 | body {
10 | font-size: 14px;
11 | background-color:#fff;
12 | }
13 |
14 | header{
15 | position: fixed;
16 | top: 0;
17 | right: 0;
18 | left: 0;
19 | background-color: antiquewhite;
20 | z-index: 10;
21 | }
22 | .menu-header {
23 | display: flex;
24 | justify-content: space-between;
25 | max-width: 1200px;
26 | margin-left: auto;
27 | margin-right: auto;
28 | }
29 | .logo {
30 | font-size: 38px;
31 | font-weight: bolder;
32 | padding: 2px;
33 | }
34 |
35 | .menu-user {
36 | display: flex;
37 | }
38 |
39 | .menu-user-item {
40 | display: block;
41 | padding: 10px;
42 | background-color: antiquewhite;
43 | text-decoration: none;
44 | color: teal;
45 | }
46 |
47 | .menu-user-item:hover {
48 | background-color: teal;
49 | color: antiquewhite;
50 | }
51 |
52 | main{
53 | }
54 |
55 | section{
56 | padding: 20px;
57 | }
58 |
59 | .container{
60 | margin: 63px 5px 0 5px;
61 | max-width: 1200px;
62 | }
63 |
64 | .main-full{
65 | height: 91vh;
66 | background-color: burlywood;
67 | }
68 |
69 | .section-title{
70 | display: flex;
71 | justify-content: space-between;
72 | }
73 |
74 | .btn-new-title{
75 | display: inline-block;
76 | margin-bottom: 5px;
77 | padding: 10px;
78 | border-radius: 5px;
79 | background-color: rgb(24, 24, 224);
80 | color: aliceblue;
81 | }
82 | .btn-new-title:hover{
83 | background-color: rgb(68, 68, 255);
84 | }
85 |
86 | .form-new {
87 | padding: 10px;
88 | display: flex;
89 | gap: 10px;
90 | flex-wrap: wrap;
91 | }
92 |
93 | .form-new>div {
94 | flex-basis: 100%;
95 | margin-top: 10px;
96 | }
97 |
98 | .form-new>div>label {
99 | display: block;
100 | }
101 |
102 | .form-new>div>input {
103 | display: block;
104 | width: 100%;
105 | padding: 3px;
106 | border-radius: 3px;
107 | }
108 |
109 | @media (min-width:600px){
110 | .form-new>div {
111 | flex-basis: 49%;
112 | }
113 |
114 | }
115 |
116 | @media (min-width:1200px) {
117 | .container {
118 | margin-left: auto;
119 | margin-right: auto;
120 | }
121 | }
--------------------------------------------------------------------------------
/src/views/auth/register.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%- include('../partials/head') %>
6 |
7 |
8 |
9 |
10 |
11 | <%- include('../partials/header') %>
12 | <%- include('../partials/header') %>
13 |
14 |
56 |
57 | <%- include('../partials/footer') %>
58 | <%- include('../partials/scripts') %>
59 |
60 |
61 |
--------------------------------------------------------------------------------
/src/app.js:
--------------------------------------------------------------------------------
1 | const createError = require("http-errors");
2 | const express = require("express");
3 | const path = require("path");
4 | const cookieParser = require("cookie-parser");
5 | const logger = require("morgan");
6 | const mo = require("method-override");
7 | const ses = require("express-session");
8 |
9 | const indexRouter = require("./routes/index");
10 | const usersRouter = require("./routes/users");
11 | const productsRouter = require("./routes/products");
12 | const authRouter = require("./routes/auth");
13 | const apiRouter = require("./routes/api");
14 | const sessionMiddleware = require("./middlewares/sessionMiddleware");
15 | const sessionTimeMiddleware = require("./middlewares/sessionTimeMiddleware");
16 | const menuMiddleware = require("./middlewares/menuMiddleware");
17 |
18 | const app = express();
19 |
20 | // .ENV
21 | require("dotenv").config();
22 |
23 | // view engine setup
24 | app.set("views", path.join(__dirname, "views"));
25 | app.set("view engine", "ejs");
26 |
27 | app.use(logger("dev"));
28 | app.use(express.json());
29 | app.use(express.urlencoded({ extended: false }));
30 | app.use(mo("_method"));
31 | app.use(cookieParser());
32 | app.use(express.static(path.join(__dirname, "../public")));
33 | app.use(
34 | ses({ secret: "es un secreto", resave: false, saveUninitialized: true })
35 | );
36 |
37 | // esto es un middleware de tiempo de session
38 | app.use(sessionMiddleware);
39 | app.use(sessionTimeMiddleware);
40 |
41 | app.use(menuMiddleware);
42 |
43 | app.use("/", indexRouter);
44 | app.use("/", authRouter);
45 | app.use("/users/", usersRouter);
46 | app.use("/products/", productsRouter);
47 | app.use("/api/", apiRouter);
48 |
49 | // catch 404 and forward to error handler
50 | app.use(function (req, res, next) {
51 | return res.render("errors/404");
52 | //next(createError(404));
53 | });
54 |
55 | // vista no encontrada
56 | app.use(function (err, req, res, next) {
57 | console.log(err);
58 | if (err["view"] != null) {
59 | console.error("errorView", err.message);
60 | return res.render("errors/500");
61 | }
62 | return next();
63 | });
64 |
65 | // error handler
66 | app.use(function (err, req, res, next) {
67 | console.log("errorHandler", err.message);
68 | // set locals, only providing error in development
69 | res.locals.message = err.message;
70 | res.locals.error = req.app.get("env") === "development" ? err : {};
71 |
72 | // render the error page
73 | res.status(err.status || 500);
74 | res.render("error");
75 | });
76 |
77 | module.exports = app;
78 |
--------------------------------------------------------------------------------
/public/js/addons/rating.min.js:
--------------------------------------------------------------------------------
1 | (function($){$.fn.mdbRate=function(){var $stars;var myDefaultWhiteList=$.fn.tooltip.Constructor.Default.whiteList
2 | myDefaultWhiteList.textarea=[];myDefaultWhiteList.button=[];var $container=$(this);var titles=['Very bad','Poor','OK','Good','Excellent'];for(var i=0;i<5;i++){$container.append(` `)}
4 | $stars=$container.children();if($container.hasClass('rating-faces')){$stars.addClass('far fa-meh-blank')}else if($container.hasClass('empty-stars')){$stars.addClass('far fa-star')}else{$stars.addClass('fas fa-star')}
5 | $stars.on('mouseover',function(){var index=$(this).attr('data-index');markStarsAsActive(index)});function markStarsAsActive(index){unmarkActive();for(var i=0;i<=index;i++){if($container.hasClass('rating-faces')){$($stars.get(i)).removeClass('fa-meh-blank');$($stars.get(i)).addClass('live');switch(index){case '0':$($stars.get(i)).addClass('fa-angry');break;case '1':$($stars.get(i)).addClass('fa-frown');break;case '2':$($stars.get(i)).addClass('fa-meh');break;case '3':$($stars.get(i)).addClass('fa-smile');break;case '4':$($stars.get(i)).addClass('fa-laugh');break}}else if($container.hasClass('empty-stars')){$($stars.get(i)).addClass('fas');switch(index){case '0':$($stars.get(i)).addClass('oneStar');break;case '1':$($stars.get(i)).addClass('twoStars');break;case '2':$($stars.get(i)).addClass('threeStars');break;case '3':$($stars.get(i)).addClass('fourStars');break;case '4':$($stars.get(i)).addClass('fiveStars');break}}else{$($stars.get(i)).addClass('amber-text')}}}
6 | function unmarkActive(){$stars.parent().hasClass('rating-faces')?$stars.addClass('fa-meh-blank'):$stars;$container.hasClass('empty-stars')?$stars.removeClass('fas'):$container;$stars.removeClass('fa-angry fa-frown fa-meh fa-smile fa-laugh live oneStar twoStars threeStars fourStars fiveStars amber-text')}
7 | $stars.on('click',function(){$stars.popover('hide')});$container.on('click','#voteSubmitButton',function(){$stars.popover('hide')});$container.on('click','#closePopoverButton',function(){$stars.popover('hide')});if($container.hasClass('feedback')){$(function(){$stars.popover({container:$container,content:` Submit! Close
`})})}
8 | $stars.tooltip()}})(jQuery)
--------------------------------------------------------------------------------
/public/js/modules/treeview.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | (function ($) {
4 | $.fn.mdbTreeview = function () {
5 | var $this = $(this);
6 |
7 | if ($this.hasClass('treeview')) {
8 | var $toggler = $this.find('.rotate');
9 | $.each($toggler, function (e) {
10 | $($toggler[e]).off('click');
11 | $($toggler[e]).on('click', function () {
12 | var $this = $(this);
13 | $this.siblings('.nested').toggleClass('active');
14 | $this.toggleClass('down');
15 | });
16 | });
17 | }
18 |
19 | if ($this.hasClass('treeview-animated')) {
20 | var $elements = $this.find('.treeview-animated-element');
21 | var $closed = $this.find('.closed');
22 | $this.find('.nested').hide();
23 | $closed.off('click');
24 | $closed.on('click', function () {
25 | var $this = $(this);
26 | var $target = $this.siblings('.nested');
27 | var $pointer = $this.children('.fa-angle-right');
28 | $this.toggleClass('open');
29 | $pointer.toggleClass('down');
30 | !$target.hasClass('active') ? $target.addClass('active').slideDown() : $target.removeClass('active').slideUp();
31 | return false;
32 | });
33 | $elements.off('click');
34 | $elements.on('click', function () {
35 | var $this = $(this);
36 | $this.hasClass('opened') ? $this.removeClass('opened') : ($elements.removeClass('opened'), $this.addClass('opened'));
37 | });
38 | }
39 |
40 | if ($this.hasClass('treeview-colorful')) {
41 | var _$elements = $this.find('.treeview-colorful-element');
42 |
43 | var $header = $this.find('.treeview-colorful-items-header');
44 | $this.find('.nested').hide();
45 | $header.off('click');
46 | $header.on('click', function () {
47 | var $this = $(this);
48 | var $target = $this.siblings('.nested');
49 | var $pointerPlus = $this.children('.fa-plus-circle');
50 | var $pointerMinus = $this.children('.fa-minus-circle');
51 | $this.toggleClass('open');
52 | $pointerPlus.removeClass('fa-plus-circle');
53 | $pointerPlus.addClass('fa-minus-circle');
54 | $pointerMinus.removeClass('fa-minus-circle');
55 | $pointerMinus.addClass('fa-plus-circle');
56 | !$target.hasClass('active') ? $target.addClass('active').slideDown() : $target.removeClass('active').slideUp();
57 | });
58 |
59 | _$elements.off('click');
60 |
61 | _$elements.on('click', function () {
62 | var $this = $(this);
63 | $this.hasClass('opened') ? _$elements.removeClass('opened') : (_$elements.removeClass('opened'), $this.addClass('opened'));
64 | });
65 | }
66 | };
67 | })(jQuery);
--------------------------------------------------------------------------------
/public/scss/free/_buttons.scss:
--------------------------------------------------------------------------------
1 | // Buttons
2 | .btn {
3 | margin: $btn-margin-basic;
4 | color: inherit;
5 | text-transform: uppercase;
6 | word-wrap: break-word;
7 | white-space: normal;
8 | cursor: pointer;
9 | border: 0;
10 | border-radius: $border-radius-base;
11 | box-shadow: $z-depth-1;
12 | transition: $btn-transition;
13 | @include button-size($btn-padding-y-basic, $btn-padding-x-basic, $btn-font-size-basic);
14 |
15 | @include hover-focus-active {
16 | outline: 0;
17 | box-shadow: $z-depth-1-half;
18 | }
19 |
20 | &.btn-block {
21 | margin: inherit;
22 | }
23 |
24 | .fas,
25 | .fab,
26 | .far {
27 | &.right {
28 | margin-left: $btn-icon-margin;
29 | }
30 | &.left {
31 | margin-right: $btn-icon-margin;
32 | }
33 | }
34 |
35 | &.btn-lg {
36 | @include button-size($btn-padding-y-large, $btn-padding-x-large, $btn-font-size-large);
37 | }
38 | &.btn-md {
39 | @include button-size($btn-padding-y-medium, $btn-padding-x-medium, $btn-font-size-medium);
40 | }
41 | &.btn-sm {
42 | @include button-size($btn-padding-y-small, $btn-padding-x-small, $btn-font-size-small);
43 | }
44 |
45 | &.disabled,
46 | &:disabled {
47 | @include hover-focus-active {
48 | box-shadow: $z-depth-1;
49 | }
50 | }
51 |
52 | &[class*="btn-outline-"] {
53 | padding-top: $btn-outline-padding-y-basic;
54 | padding-bottom: $btn-outline-padding-y-basic;
55 | &.btn-lg {
56 | padding-top: $btn-outline-padding-y-large;
57 | padding-bottom: $btn-outline-padding-y-large;
58 | }
59 | &.btn-md {
60 | padding-top: $btn-outline-padding-y-medium;
61 | padding-bottom: $btn-outline-padding-y-medium;
62 | }
63 | &.btn-sm {
64 | padding-top: $btn-outline-padding-y-small;
65 | padding-bottom: $btn-outline-padding-y-small;
66 | }
67 | }
68 | }
69 |
70 | .btn-link {
71 | color: $black-base;
72 | background-color: transparent;
73 | box-shadow: none;
74 | @include hover-focus-active {
75 | color: $black-base;
76 | background-color: transparent;
77 | box-shadow: none;
78 | }
79 | }
80 |
81 | .btn-group {
82 | > .btn:not(:first-child),
83 | > .btn-group:not(:first-child) {
84 | margin-left: -$btn-group-margin;
85 | }
86 | }
87 |
88 | @each $btn_name, $color_value in $mdb-colors {
89 | @include make-button($btn_name, $color_value);
90 | @include make-outline-button($btn_name, $color_value);
91 | }
92 |
93 | @each $name, $val in $gradients {
94 | @include make-gradient-button($name, $val);
95 | }
96 |
97 | .btn-warning:not(:disabled):not(.disabled).active,
98 | .btn-warning:not(:disabled):not(.disabled):active,
99 | .show > .btn-warning.dropdown-toggle {
100 | color: $white-base;
101 | }
102 |
103 |
--------------------------------------------------------------------------------
/src/views/order.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%- include('./partials/head') %>
6 |
7 |
8 |
9 | <%- include('./partials/header') %>
10 |
11 |
12 |
Pedido Nro
13 |
14 |
15 |
16 |
17 |
18 |
19 | #
20 |
21 |
22 | Producto
23 |
24 |
25 | Precio
26 |
27 |
28 | Cantidad
29 |
30 |
31 | Subtotal
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
42 |
43 |
44 |
59 |
60 |
61 | <%- include('./partials/footer') %>
62 | <%- include('./partials/scripts') %>
63 |
64 |
65 |
--------------------------------------------------------------------------------
/public/scss/free/_navbars.scss:
--------------------------------------------------------------------------------
1 | // Navbars
2 | .navbar {
3 | font-weight: $navbar-font-weight;
4 | box-shadow: $z-depth-1;
5 | form {
6 | .md-form {
7 | input {
8 | margin: 0 $navbar-form-input-mr $navbar-form-input-mb $navbar-form-input-ml;
9 | }
10 | }
11 | }
12 | .breadcrumb {
13 | padding: $navbar-breadcrumb-padding-top 0 0 $navbar-breadcrumb-padding-left;
14 | margin: 0;
15 | font-size: $navbar-double-font-size;
16 | font-weight: $navbar-font-weight;
17 | background-color: inherit;
18 | .breadcrumb-item {
19 | color: $white-base;
20 | &.active {
21 | color: $navbar-breadcrumb-color;
22 | }
23 | &:before {
24 | color: $navbar-breadcrumb-color;
25 | }
26 | }
27 | }
28 | .navbar-toggler {
29 | border-width: 0;
30 | outline: 0;
31 | }
32 | .nav-flex-icons {
33 | flex-direction: row;
34 | }
35 | .container {
36 | @media (max-width: $medium-screen) {
37 | width: 100%;
38 | .navbar-toggler-right {
39 | right: 0;
40 | }
41 | }
42 | }
43 | .nav-item {
44 | .nav-link {
45 | display: block;
46 | &.disabled {
47 | &:active {
48 | pointer-events: none;
49 | }
50 | }
51 | .fas, .fab, .far {
52 | padding-right: $navbar-flex-icons-padding-lg;
53 | padding-left: $navbar-flex-icons-padding-lg;
54 | }
55 | @media (max-width: $medium-screen) {
56 | padding-right: $navbar-flex-icons-padding-md;
57 | padding-left: $navbar-flex-icons-padding-md;
58 | }
59 | }
60 | }
61 | .dropdown-menu {
62 | position: absolute !important;
63 | margin-top: 0;
64 | a {
65 | padding: $navbar-dropdown-menu-padding;
66 | font-size: $navbar-dropdown-font-size;
67 | font-weight: $navbar-font-weight;
68 | color: $black;
69 | }
70 | form {
71 | @media (max-width: $small-screen) {
72 | width: 17rem;
73 | }
74 | @media (min-width: $small-screen) {
75 | width: 22rem;
76 | }
77 | }
78 | }
79 | &.navbar-light {
80 | @include make-navbar($navbar-light-disabled-color, $navbar-light-toggler-icon, $black, $navbar-light-hover-color, $navbar-light-bg-active-color);
81 | }
82 | &.navbar-dark {
83 | @include make-navbar($navbar-dark-disabled-color, $navbar-dark-toggler-icon, $white, $navbar-dark-hover-color, $navbar-dark-bg-active-color);
84 | }
85 | &.scrolling-navbar {
86 | @media (min-width: $small-screen) {
87 | padding-top: $navbar-scrolling-padding;
88 | padding-bottom: $navbar-scrolling-padding;
89 | transition: $navbar-scrolling-transition;
90 | .navbar-nav > li {
91 | transition-duration: $navbar-scrolling-transition-duration;
92 | }
93 | &.top-nav-collapse {
94 | padding-top: $navbar-top-collapse-padding;
95 | padding-bottom: $navbar-top-collapse-padding;
96 | }
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/public/scss/core/bootstrap/_functions.scss:
--------------------------------------------------------------------------------
1 | // Bootstrap functions
2 | //
3 | // Utility mixins and functions for evaluating source code across our variables, maps, and mixins.
4 |
5 | // Ascending
6 | // Used to evaluate Sass maps like our grid breakpoints.
7 | @mixin _assert-ascending($map, $map-name) {
8 | $prev-key: null;
9 | $prev-num: null;
10 | @each $key, $num in $map {
11 | @if $prev-num == null or unit($num) == "%" {
12 | // Do nothing
13 | } @else if not comparable($prev-num, $num) {
14 | @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}' !";
15 | } @else if $prev-num >= $num {
16 | @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}' !";
17 | }
18 | $prev-key: $key;
19 | $prev-num: $num;
20 | }
21 | }
22 |
23 | // Starts at zero
24 | // Used to ensure the min-width of the lowest breakpoint starts at 0.
25 | @mixin _assert-starts-at-zero($map, $map-name: "$grid-breakpoints") {
26 | $values: map-values($map);
27 | $first-value: nth($values, 1);
28 | @if $first-value != 0 {
29 | @warn "First breakpoint in #{$map-name} must start at 0, but starts at #{$first-value}.";
30 | }
31 | }
32 |
33 | // Replace `$search` with `$replace` in `$string`
34 | // Used on our SVG icon backgrounds for custom forms.
35 | //
36 | // @author Hugo Giraudel
37 | // @param {String} $string - Initial string
38 | // @param {String} $search - Substring to replace
39 | // @param {String} $replace ('') - New value
40 | // @return {String} - Updated string
41 | @function str-replace($string, $search, $replace: "") {
42 | $index: str-index($string, $search);
43 |
44 | @if $index {
45 | @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
46 | }
47 |
48 | @return $string;
49 | }
50 |
51 | // Color contrast
52 | @function color-yiq($color, $dark: $yiq-text-dark, $light: $yiq-text-light) {
53 | $r: red($color);
54 | $g: green($color);
55 | $b: blue($color);
56 |
57 | $yiq: (($r * 299) + ($g * 587) + ($b * 114)) / 1000;
58 |
59 | @if ($yiq >= $yiq-contrasted-threshold) {
60 | @return $dark;
61 | } @else {
62 | @return $light;
63 | }
64 | }
65 |
66 | // Retrieve color Sass maps
67 | @function color($key: "blue") {
68 | @return map-get($colors, $key);
69 | }
70 |
71 | @function theme-color($key: "primary") {
72 | @return map-get($theme-colors, $key);
73 | }
74 |
75 | @function gray($key: "100") {
76 | @return map-get($grays, $key);
77 | }
78 |
79 | // Request a theme color level
80 | @function theme-color-level($color-name: "primary", $level: 0) {
81 | $color: theme-color($color-name);
82 | $color-base: if($level > 0, $black, $white);
83 | $level: abs($level);
84 |
85 | @return mix($color-base, $color, $level * $theme-color-interval);
86 | }
87 |
--------------------------------------------------------------------------------
/src/controllers/authController.js:
--------------------------------------------------------------------------------
1 | const bcryptjs = require("bcryptjs");
2 | const db = require("../database/models");
3 | const { validationResult } = require("express-validator");
4 |
5 | const controller = {
6 | showLogin: function (req, res) {
7 | return res.render("auth/login");
8 | },
9 | login: async function (req, res) {
10 | //validar los datos
11 | let errores = validationResult(req);
12 |
13 | //si hay errores, retornarlos a la vista
14 | if (!errores.isEmpty()) {
15 | let errors = errores.mapped();
16 | console.log(errors);
17 | return res.render("auth/login", { errors: errors, olds: req.body });
18 | }
19 |
20 | //leo el json
21 | let user = await db.User.findOne({
22 | where: {
23 | email: req.body.email,
24 | },
25 | });
26 |
27 | console.log(req.body);
28 | //buscar al usuario
29 | if (user) {
30 | let passOk = bcryptjs.compareSync(req.body.password, user.password);
31 | if (passOk) {
32 | //si la password es correcta se guarda el ususario en session
33 | req.session.userLogged = user;
34 | req.session.lastActitity = Date.now();
35 |
36 | //si recordar usuario esta activado enviamos una cookie con el email
37 | if (req.body.rememberMe) {
38 | res.cookie("userId", user.id, { maxAge: 1000 * 60 * 5 });
39 | }
40 | //redirigimos al menu de usuario
41 | return res.redirect("/profile");
42 | } else {
43 | //si la password no es correcta devolvemos el error
44 | return res.render("auth/login", {
45 | errors: {
46 | password: {
47 | msg: "La contraseña no es válida.",
48 | },
49 | },
50 | olds: req.body,
51 | });
52 | }
53 | } else {
54 | return res.render("auth/login", {
55 | errors: { email: { msg: "No se encontró el usuario", olds: req.body } },
56 | });
57 | }
58 | },
59 | showRegister: function (req, res) {
60 | return res.render("auth/register");
61 | },
62 | register: async function (req, res) {
63 | //validar los datos
64 | let errores = validationResult(req);
65 |
66 | //si hay errores, retornarlos a la vista
67 | if (!errores.isEmpty()) {
68 | let errors = errores.mapped();
69 | console.log(errors);
70 | return res.render("register", { errors: errors, olds: req.body });
71 | }
72 |
73 | let data = {
74 | name: req.body.name,
75 | email: req.body.email,
76 | password: bcryptjs.hashSync(req.body.password, 10),
77 | };
78 | //guarda el usuario en base de datos
79 | let newUser = await db.User.create(data);
80 |
81 | // SE LOGEA EN SESSION
82 | req.session.userLogged = newUser;
83 |
84 | //redirigimos a menu de usuario
85 | return res.redirect(`/profile/`);
86 | },
87 | logout: function (req, res) {
88 | req.session.destroy();
89 | res.clearCookie("userId");
90 | return res.redirect("/");
91 | },
92 | profile: function (req, res) {
93 | return res.render("auth/profile");
94 | },
95 | };
96 |
97 | module.exports = controller;
98 |
--------------------------------------------------------------------------------
/public/js/addons/jquery.zmd.hierarchical-display.min.js:
--------------------------------------------------------------------------------
1 | (function(i){"use strict";function t(t){return this.each(function(){var a=i(this),e=a.data("zmd.hierarchicalDisplay"),o=i.extend({},n.DEFAULTS,a.data(),"object"==typeof t&&t);return e||a.data("zmd.hierarchicalDisplay",e=new n(this,o)),"string"==typeof t?e[t]():o.action in e?e[o.action]():void 0})}var n=function(t,a){this.$element=i(t),this.$children=this.$element.children(),this.options=i.extend({},n.DEFAULTS,a),this._time=n.TRANSITION_DURATION*this.options.speed,this.init(),!0===this.options.debug&&this._debug()};n.VERSION="1.0.1",n.TRANSITION_DURATION=300,n.DEFAULTS={action:"show",speed:5,animationIn:"zoomedIn",animationOut:"zoomedOut",debug:!1},n.prototype.init=function(){var t,n,a,e=this,o=this.$element,s=this.$children,h=this.options,l=this._time;o.addClass("zmd-hierarchical-display"),s.each(function(){t=i(this).position(),n=.8*t.left+t.top,a=parseFloat(n/l).toFixed(2),i(this).css("-webkit-animation-delay",a+"s").css("animation-delay",a+"s")}),this._delay=a,s.last().on("webkitAnimationEnd animationend",function(){i(this).hasClass(h.animationOut)&&e._complete("hidden"),i(this).hasClass(h.animationIn)&&e._complete("shown")})},n.prototype.show=function(){var t=this.$element,n=(this.$children,this.options);t.hasClass("in")||t.hasClass("zmd-hierarchical-displaying")||(this._removeAnimations(),t.trigger(i.Event("show.zmd.hierarchicalDisplay")),this._addAnimation(n.animationIn))},n.prototype.hide=function(){var t=this.$element,n=(this.$children,this.options);"hidden"===t.css("visibility")||t.hasClass("zmd-hierarchical-displaying")||(this._removeAnimations(),t.trigger(i.Event("hide.zmd.hierarchicalDisplay")),this._addAnimation(n.animationOut))},n.prototype.toggle=function(){return this.$element.hasClass("in")?this.hide():this.show()},n.prototype._removeAnimations=function(){var t=this.options;this.$children.each(function(){i(this).removeClass(t.animationIn).removeClass(t.animationOut)})},n.prototype._addAnimation=function(t){this.$element.addClass("zmd-hierarchical-displaying"),this.$children.each(function(){i(this).addClass(t).addClass("animation")})},n.prototype._complete=function(t){this.$element.removeClass("zmd-hierarchical-displaying").toggleClass("in").trigger(i.Event(t+".zmd.hierarchicalDisplay"))},n.prototype._debug=function(){i(document).on("show.zmd.hierarchicalDisplay",function(i){console.log('Event "show.zmd.hierarchicalDisplay". For more information see:'),console.log(i)}).on("shown.zmd.hierarchicalDisplay",function(i){console.log('Event "shown.zmd.hierarchicalDisplay". For more information see:'),console.log(i)}).on("hide.zmd.hierarchicalDisplay",function(i){console.log('Event "hide.zmd.hierarchicalDisplay". For more information see:'),console.log(i)}).on("hidden.zmd.hierarchicalDisplay",function(i){console.log('Event "hidden.zmd.hierarchicalDisplay". For more information see:'),console.log(i)})},i.fn.hierarchicalDisplay=t,i.fn.hierarchicalDisplay.Constructor=n,i(document).on("ready",function(){i('[data-animation="hierarchical-display"]').each(function(){t.call(i(this))})}),i(document).on("click",'[data-toggle="hierarchical-display"]',function(n){var a=i(this),e=i(a.attr("data-target")||a.attr("href"));a.is("a")&&n.preventDefault(),t.call(e,"toggle")})})(jQuery);
--------------------------------------------------------------------------------
/public/scss/free/_msc.scss:
--------------------------------------------------------------------------------
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 |
9 | .free-bird {
10 | margin-top: $edge-header-margin-top;
11 | }
12 |
13 | // Additional gradients
14 | .juicy-peach-gradient {
15 | background-image: linear-gradient(to right, #ffecd2 0%, #fcb69f 100%);
16 | }
17 |
18 | .young-passion-gradient {
19 | background-image: linear-gradient(to right, #ff8177 0%, #ff867a 0%, #ff8c7f 21%, #f99185 52%, #cf556c 78%, #b12a5b 100%);
20 | }
21 |
22 | .lady-lips-gradient {
23 | background-image: linear-gradient(to top, #ff9a9e 0%, #fecfef 99%, #fecfef 100%);
24 | }
25 |
26 | .sunny-morning-gradient {
27 | background-image: linear-gradient(120deg, #f6d365 0%, #fda085 100%);
28 | }
29 |
30 | .rainy-ashville-gradient {
31 | background-image: linear-gradient(to top, #fbc2eb 0%, #a6c1ee 100%);
32 | }
33 |
34 | .frozen-dreams-gradient {
35 | background-image: linear-gradient(to top, #fdcbf1 0%, #fdcbf1 1%, #e6dee9 100%);
36 | }
37 |
38 | .warm-flame-gradient {
39 | background-image: linear-gradient(45deg, #ff9a9e 0%, #fad0c4 99%, #fad0c4 100%);
40 | }
41 |
42 | .night-fade-gradient {
43 | background-image: linear-gradient(to top, #a18cd1 0%, #fbc2eb 100%);
44 | }
45 |
46 | .spring-warmth-gradient {
47 | background-image: linear-gradient(to top, #fad0c4 0%, #ffd1ff 100%);
48 | }
49 |
50 | .winter-neva-gradient {
51 | background-image: linear-gradient(120deg, #a1c4fd 0%, #c2e9fb 100%);
52 | }
53 |
54 | .dusty-grass-gradient {
55 | background-image: linear-gradient(120deg, #d4fc79 0%, #96e6a1 100%);
56 | }
57 |
58 | .tempting-azure-gradient {
59 | background-image: linear-gradient(120deg, #84fab0 0%, #8fd3f4 100%);
60 | }
61 |
62 | .heavy-rain-gradient {
63 | background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%);
64 | }
65 |
66 | .amy-crisp-gradient {
67 | background-image: linear-gradient(120deg, #a6c0fe 0%, #f68084 100%);
68 | }
69 |
70 | .mean-fruit-gradient {
71 | background-image: linear-gradient(120deg, #fccb90 0%, #d57eeb 100%);
72 | }
73 |
74 | .deep-blue-gradient {
75 | background-image: linear-gradient(120deg, #e0c3fc 0%, #8ec5fc 100%);
76 | }
77 |
78 | .ripe-malinka-gradient {
79 | background-image: linear-gradient(120deg, #f093fb 0%, #f5576c 100%);
80 | }
81 |
82 | .cloudy-knoxville-gradient {
83 | background-image: linear-gradient(120deg, #fdfbfb 0%, #ebedee 100%);
84 | }
85 |
86 | .morpheus-den-gradient {
87 | background-image: linear-gradient(to top, #30cfd0 0%, #330867 100%);
88 | }
89 |
90 | .rare-wind-gradient {
91 | background-image: linear-gradient(to top, #a8edea 0%, #fed6e3 100%);
92 | }
93 |
94 | .near-moon-gradient {
95 | background-image: linear-gradient(to top, #5ee7df 0%, #b490ca 100%);
96 | }
97 |
98 | .schedule-list {
99 | .hr-bold {
100 | border-top: 2px solid #212529;
101 | }
102 |
103 | .font-smaller {
104 | font-size: .8rem;
105 | }
106 | }
107 |
108 | .note {
109 | padding: 10px;
110 | border-left: 6px solid;
111 | border-radius: 5px;
112 | strong {
113 | font-weight: 600;
114 | }
115 | p {
116 | font-weight: 500;
117 | }
118 | }
119 |
120 | @each $name, $color in $note {
121 | .note-#{$name} {
122 | background-color: map-get($color, bgc);
123 | border-color: map-get($color, border-color);
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/src/views/auth/profile.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%- include('../partials/head') %>
6 |
7 |
8 |
9 |
10 | <%- include('../partials/header') %>
11 |
12 |
13 |
14 |
15 |
16 | Perfil de <%= locals.userLogged.name%>
17 |
18 |
19 |
22 |
23 |
Nombre:
24 | <%= locals.userLogged.name %>
25 |
26 |
Email:
27 | <%= locals.userLogged.email %>
28 |
29 |
Editar mi perfil
30 |
Salir
31 |
32 |
33 |
34 |
37 |
38 |
39 |
40 |
41 |
42 | #
43 |
44 |
45 | Fecha
46 |
47 |
48 | Envío
49 |
50 |
51 | Pago
52 |
53 |
54 | Total
55 |
56 |
57 |
58 |
59 |
60 |
61 | 1
62 | 2022/06/04 10:00
63 | Correo Argentino
64 | Efectivo
65 | $1220
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | <%- include('../partials/footer') %>
77 | <%- include('../partials/scripts') %>
78 |
79 |
80 |
--------------------------------------------------------------------------------
/public/scss/core/_typography.scss:
--------------------------------------------------------------------------------
1 | // Typography
2 |
3 | // Roboto font
4 | @font-face {
5 | font-family: Roboto;
6 | font-weight: 200;
7 | src: local(Roboto Thin), url("#{$roboto-font-path}Roboto-Thin.eot");
8 | 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");
9 | }
10 |
11 | @font-face {
12 | font-family: Roboto;
13 | font-weight: 300;
14 | src: local(Roboto Light), url("#{$roboto-font-path}Roboto-Light.eot");
15 | 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");
16 | }
17 |
18 | @font-face {
19 | font-family: Roboto;
20 | font-weight: 400;
21 | src: local(Roboto Regular), url("#{$roboto-font-path}Roboto-Regular.eot");
22 | 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");
23 | }
24 |
25 | @font-face {
26 | font-family: Roboto;
27 | font-weight: 500;
28 | src: url("#{$roboto-font-path}Roboto-Medium.eot");
29 | 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");
30 | }
31 |
32 | @font-face {
33 | font-family: Roboto;
34 | font-weight: 700;
35 | src: url("#{$roboto-font-path}Roboto-Bold.eot");
36 | 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");
37 | }
38 |
39 | // General properties
40 | body {
41 | font-family: $mdb-font-family;
42 | font-weight: $font-weight-light;
43 | }
44 |
45 | h1, h2, h3, h4, h5, h6 {
46 | font-weight: $font-weight-light;
47 | }
48 |
49 | // Blockquote
50 | .blockquote {
51 | padding: $blockquote-padding-y $blockquote-padding-x;
52 | border-left: .25rem solid #eceeef;
53 | &.text-right {
54 | border-right: .25rem solid #eceeef;
55 | border-left: none;
56 | }
57 | .bq-title {
58 | margin-bottom: 0;
59 | font-size: $font-size-large;
60 | font-weight: 400;
61 | }
62 | p {
63 | padding: $blockquote-p-padding-y 0;
64 | font-size: $blockquote-p-font-size;
65 | }
66 | }
67 |
68 | @each $name, $color in $basic {
69 | .bq-#{$name} {
70 | border-left: 3px solid $color !important;
71 | .bq-title {
72 | color: $color !important;
73 | }
74 | }
75 | }
76 |
77 | // Responsive headings
78 | @each $key, $val in $grid-breakpoints {
79 | @include media-breakpoint-up($key) {
80 | $y: map-get($responsive-headings, $key);
81 | @each $name, $value in $y {
82 | .#{$name}-responsive {
83 | font-size: $value;
84 | }
85 | }
86 | }
87 | }
88 |
89 | @each $name, $color in $basic-mdb-colors {
90 | @include text-emphasis-variant(".text-#{$name}", $color);
91 | }
92 |
93 | .font-small {
94 | font-size: $font-size-small;
95 | }
96 |
--------------------------------------------------------------------------------
/public/css/addons/datatables.min.css:
--------------------------------------------------------------------------------
1 | div.dataTables_wrapper div.dataTables_filter input,div.dataTables_wrapper div.dataTables_filter select,div.dataTables_wrapper div.dataTables_length input,div.dataTables_wrapper div.dataTables_length select{width:auto}table.dataTable thead{cursor:pointer}div.dataTables_wrapper div.dataTables_length.d-flex.flex-row label{margin-top:1.2rem;margin-right:1rem}div.dataTables_wrapper div.dataTables_length.d-flex.flex-row .select-wrapper.mdb-select .select-dropdown,div.dataTables_wrapper div.dataTables_length.d-flex.flex-row .select-wrapper.mdb-select span{margin-top:1rem}div.dataTables_wrapper div.dataTables_filter label,div.dataTables_wrapper div.dataTables_length label{text-align:left;font-weight:400;padding-top:.5rem;padding-bottom:.5rem}div.dataTables_wrapper div.dataTables_filter{text-align:right}div.dataTables_wrapper div.dataTables_filter input{margin-left:.5rem;display:inline-block}div.dataTables_wrapper div.dataTables_info,div.dataTables_wrapper div.dataTables_paginate{font-weight:400;padding-top:1rem;padding-bottom:1rem}div.dataTables_wrapper div.dataTables_paginate{text-align:right;margin:0}div.dataTables_wrapper div.dataTables_paginate ul.pagination{-webkit-box-pack:end;-webkit-justify-content:flex-end;-ms-flex-pack:end;justify-content:flex-end}div.dataTables_wrapper div.dataTables_paginate ul.pagination .page-item.active .page-link:focus{background-color:#4285f4}div.dataTables_wrapper div.dataTables_paginate ul.pagination .page-item .page-link:focus{-webkit-box-shadow:none;box-shadow:none}@media (max-width:767px){div.dataTables_wrapper div .dataTables_filter,div.dataTables_wrapper div .dataTables_info,div.dataTables_wrapper div .dataTables_length,div.dataTables_wrapper div .dataTables_paginate ul.pagination{text-align:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center}}.bs-select select{display:inline-block!important}table.dataTable thead>tr>td.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc{padding-right:30px}table.dataTable thead>tr>td:active,table.dataTable thead>tr>th:active{outline:0}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_desc_disabled{cursor:pointer;position:relative}table.dataTable thead .sorting:after,table.dataTable thead .sorting:before,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_desc:before,table.dataTable thead .sorting_desc_disabled:after,table.dataTable thead .sorting_desc_disabled:before{position:absolute;bottom:.9em;display:block;opacity:.3;font-family:'Font Awesome\ 5 Free';font-weight:900;font-size:1rem}table.dataTable thead .sorting:before,table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_desc:before,table.dataTable thead .sorting_desc_disabled:before{right:1em;content:"\f0de"}table.dataTable thead .sorting:after,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_desc_disabled:after{content:"\f0dd";right:16px}table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_desc:after{opacity:1}table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_desc_disabled:after{opacity:0}
--------------------------------------------------------------------------------
/src/views/partials/header.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | E-Commerce
8 |
9 |
10 |
11 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
56 |
57 |
58 |
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/public/scss/free/_animations-basic.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * animate.css -http://daneden.me/animate
3 | * Version - 3.7.0
4 | * Licensed under the MIT license - http://opensource.org/licenses/MIT
5 | *
6 | * Copyright (c) 2018 Daniel Eden
7 | */
8 | .animated {
9 | animation-duration: 1s;
10 | animation-fill-mode: both;
11 | &.infinite {
12 | animation-iteration-count: infinite;
13 | }
14 | &.delay-1s {
15 | animation-delay: 1s;
16 | }
17 | &.delay-2s {
18 | animation-delay: 2s;
19 | }
20 | &.delay-3s {
21 | animation-delay: 3s;
22 | }
23 | &.delay-4s {
24 | animation-delay: 4s;
25 | }
26 | &.delay-5s {
27 | animation-delay: 5s;
28 | }
29 | &.fast {
30 | animation-duration: 800ms;
31 | }
32 | &.faster {
33 | animation-duration: 500ms;
34 | }
35 | &.slow {
36 | animation-duration: 2s;
37 | }
38 | &.slower {
39 | animation-duration: 3s;
40 | }
41 | }
42 |
43 | @media (prefers-reduced-motion) {
44 | .animated {
45 | transition: none !important;
46 | animation: unset !important;
47 | }
48 | }
49 |
50 | @keyframes fadeIn {
51 | from {
52 | opacity: 0;
53 | }
54 |
55 | to {
56 | opacity: 1;
57 | }
58 | }
59 |
60 | .fadeIn {
61 | animation-name: fadeIn;
62 | }
63 |
64 | @keyframes fadeInDown {
65 | from {
66 | opacity: 0;
67 | transform: translate3d(0, -100%, 0);
68 | }
69 |
70 | to {
71 | opacity: 1;
72 | transform: translate3d(0, 0, 0);
73 | }
74 | }
75 |
76 | .fadeInDown {
77 | animation-name: fadeInDown;
78 | }
79 |
80 | @keyframes fadeInLeft {
81 | from {
82 | opacity: 0;
83 | transform: translate3d(-100%, 0, 0);
84 | }
85 |
86 | to {
87 | opacity: 1;
88 | transform: translate3d(0, 0, 0);
89 | }
90 | }
91 |
92 | .fadeInLeft {
93 | animation-name: fadeInLeft;
94 | }
95 |
96 |
97 | @keyframes fadeInRight {
98 | from {
99 | opacity: 0;
100 | transform: translate3d(100%, 0, 0);
101 | }
102 |
103 | to {
104 | opacity: 1;
105 | transform: translate3d(0, 0, 0);
106 | }
107 | }
108 |
109 | .fadeInRight {
110 | animation-name: fadeInRight;
111 | }
112 |
113 |
114 | @keyframes fadeInUp {
115 | from {
116 | opacity: 0;
117 | transform: translate3d(0, 100%, 0);
118 | }
119 |
120 | to {
121 | opacity: 1;
122 | transform: translate3d(0, 0, 0);
123 | }
124 | }
125 |
126 | .fadeInUp {
127 | animation-name: fadeInUp;
128 | }
129 |
130 |
131 | @keyframes fadeOut {
132 | from {
133 | opacity: 1;
134 | }
135 |
136 | to {
137 | opacity: 0;
138 | }
139 | }
140 |
141 | .fadeOut {
142 | animation-name: fadeOut;
143 | }
144 |
145 |
146 | @keyframes fadeOutDown {
147 | from {
148 | opacity: 1;
149 | }
150 |
151 | to {
152 | opacity: 0;
153 | transform: translate3d(0, 100%, 0);
154 | }
155 | }
156 |
157 | .fadeOutDown {
158 | animation-name: fadeOutDown;
159 | }
160 |
161 |
162 | @keyframes fadeOutLeft {
163 | from {
164 | opacity: 1;
165 | }
166 |
167 | to {
168 | opacity: 0;
169 | transform: translate3d(-100%, 0, 0);
170 | }
171 | }
172 |
173 | .fadeOutLeft {
174 | animation-name: fadeOutLeft;
175 | }
176 |
177 |
178 | @keyframes fadeOutRight {
179 | from {
180 | opacity: 1;
181 | }
182 |
183 | to {
184 | opacity: 0;
185 | transform: translate3d(100%, 0, 0);
186 | }
187 | }
188 |
189 | .fadeOutRight {
190 | animation-name: fadeOutRight;
191 | }
192 |
193 |
194 | @keyframes fadeOutUp {
195 | from {
196 | opacity: 1;
197 | }
198 |
199 | to {
200 | opacity: 0;
201 | transform: translate3d(0, -100%, 0);
202 | }
203 | }
204 |
205 | .fadeOutUp {
206 | animation-name: fadeOutUp;
207 | }
208 |
--------------------------------------------------------------------------------
/public/scss/core/_global.scss:
--------------------------------------------------------------------------------
1 | // Globals
2 | // Full palette of colors
3 | @each $color_name, $color in $mdb-colors-1 {
4 | @each $color_type, $color_value in $color {
5 | @if $color_type == "base" {
6 | .#{$color_name} {
7 | background-color: $color_value !important;
8 | }
9 | .#{$color_name}-text {
10 | color: $color-value !important;
11 | }
12 | .rgba-#{$color_name}-slight,
13 | .rgba-#{$color_name}-slight:after {
14 | background-color: rgba($color_value, .1);
15 | }
16 | .rgba-#{$color_name}-light,
17 | .rgba-#{$color_name}-light:after {
18 | background-color: rgba($color_value, .3);
19 | }
20 | .rgba-#{$color_name}-strong,
21 | .rgba-#{$color_name}-strong:after {
22 | background-color: rgba($color_value, .7);
23 | }
24 | }
25 | @else {
26 | @if $enable_full_palette {
27 | .#{$color_name}.#{$color_type} {
28 | background-color: $color_value !important;
29 | }
30 | }
31 | }
32 | }
33 | }
34 |
35 | // Stylish color
36 | @each $color_name, $color_value in $stylish-rgba {
37 | .#{$color_name} {
38 | background-color: $color_value;
39 | }
40 | }
41 |
42 | // Material colors palette
43 | @each $color_name, $color in $material-colors {
44 | .#{$color_name} {
45 | background-color: $color !important;
46 | }
47 | }
48 |
49 | // Basic gradients
50 | @each $name, $val in $gradients {
51 | @include make-gradient($name, $val);
52 | }
53 | @each $name, $val in $gradients-rgba {
54 | @include make-gradient-rgba($name, $val);
55 | }
56 |
57 | .dark-grey-text {
58 | color: #4f4f4f !important;
59 | &:hover,
60 | &:focus {
61 | color: #4f4f4f !important;
62 | }
63 | }
64 |
65 | // Shadow on hover
66 | .hoverable {
67 | box-shadow: none;
68 | transition: $transition-hoverable;
69 | &:hover {
70 | box-shadow: $z-depth-2;
71 | transition: $transition-hoverable;
72 | }
73 | }
74 |
75 | // Shadows
76 | .z-depth-0 {
77 | box-shadow: none !important;
78 | }
79 | .z-depth-1 {
80 | box-shadow: $z-depth-1 !important;
81 | }
82 | .z-depth-1-half {
83 | box-shadow: $z-depth-1-half !important;
84 | }
85 | .z-depth-2 {
86 | box-shadow: $z-depth-2 !important;
87 | }
88 | .z-depth-3 {
89 | box-shadow: $z-depth-3 !important;
90 | }
91 | .z-depth-4 {
92 | box-shadow: $z-depth-4 !important;
93 | }
94 | .z-depth-5 {
95 | box-shadow: $z-depth-5 !important;
96 | }
97 |
98 | // Disabled cursor
99 | .disabled,
100 | :disabled {
101 | pointer-events: none !important;
102 | }
103 |
104 | // Links
105 | a {
106 | color: $link-color;
107 | text-decoration: none;
108 | cursor: pointer;
109 | transition: $transition-basic;
110 | &:hover {
111 | color: $link-hover-color;
112 | text-decoration: none;
113 | transition: $transition-basic;
114 | }
115 | &.disabled,
116 | &:disabled {
117 | &:hover {
118 | color: $link-color;
119 | }
120 | }
121 | }
122 |
123 | a:not([href]):not([tabindex]), a:not([href]):not([tabindex]):focus, a:not([href]):not([tabindex]):hover {
124 | color: inherit;
125 | text-decoration: none;
126 | }
127 |
128 | // Divider
129 | .divider-new {
130 | display: flex;
131 | flex-direction: row;
132 | align-items: center;
133 | justify-content: center;
134 | margin-top: $divider-margin-y;
135 | margin-bottom: $divider-margin-y;
136 | > h1, h2, h3, h4, h5, h6 {
137 | margin-bottom: 0;
138 | }
139 | &:before,
140 | &:after {
141 | flex: 1;
142 | height: 1.5px;
143 | height: $divider-height;
144 | content: "";
145 | background: #c6c6c6;
146 | }
147 | &:before {
148 | margin: 0 $divider-margin-x 0 0;
149 | }
150 | &:after {
151 | margin: 0 0 0 $divider-margin-x;
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/public/css/addons/datatables-select.min.css:
--------------------------------------------------------------------------------
1 | table.dataTable tbody>tr.selected,table.dataTable tbody>tr>.selected{background-color:#B0BED9}table.dataTable.display tbody>tr.odd.selected,table.dataTable.display tbody>tr.odd>.selected,table.dataTable.stripe tbody>tr.odd.selected,table.dataTable.stripe tbody>tr.odd>.selected{background-color:#acbad4}table.dataTable.display tbody>tr.selected:hover,table.dataTable.display tbody>tr>.selected:hover,table.dataTable.hover tbody>tr.selected:hover,table.dataTable.hover tbody>tr>.selected:hover{background-color:#aab7d1}table.dataTable.display tbody>tr.selected>.sorting_1,table.dataTable.display tbody>tr.selected>.sorting_2,table.dataTable.display tbody>tr.selected>.sorting_3,table.dataTable.display tbody>tr>.selected,table.dataTable.order-column tbody>tr.selected>.sorting_1,table.dataTable.order-column tbody>tr.selected>.sorting_2,table.dataTable.order-column tbody>tr.selected>.sorting_3,table.dataTable.order-column tbody>tr>.selected{background-color:#acbad5}table.dataTable.display tbody>tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe tbody>tr.odd.selected>.sorting_1{background-color:#a6b4cd}table.dataTable.display tbody>tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe tbody>tr.odd.selected>.sorting_2{background-color:#a8b5cf}table.dataTable.display tbody>tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe tbody>tr.odd.selected>.sorting_3{background-color:#a9b7d1}table.dataTable.display tbody>tr.even.selected>.sorting_1,table.dataTable.order-column.stripe tbody>tr.even.selected>.sorting_1{background-color:#acbad5}table.dataTable.display tbody>tr.even.selected>.sorting_2,table.dataTable.order-column.stripe tbody>tr.even.selected>.sorting_2{background-color:#aebcd6}table.dataTable.display tbody>tr.even.selected>.sorting_3,table.dataTable.order-column.stripe tbody>tr.even.selected>.sorting_3{background-color:#afbdd8}table.dataTable.display tbody>tr.odd>.selected,table.dataTable.order-column.stripe tbody>tr.odd>.selected{background-color:#a6b4cd}table.dataTable.display tbody>tr.even>.selected,table.dataTable.order-column.stripe tbody>tr.even>.selected{background-color:#acbad5}table.dataTable.display tbody>tr.selected:hover>.sorting_1,table.dataTable.order-column.hover tbody>tr.selected:hover>.sorting_1{background-color:#a2aec7}table.dataTable.display tbody>tr.selected:hover>.sorting_2,table.dataTable.order-column.hover tbody>tr.selected:hover>.sorting_2{background-color:#a3b0c9}table.dataTable.display tbody>tr.selected:hover>.sorting_3,table.dataTable.order-column.hover tbody>tr.selected:hover>.sorting_3{background-color:#a5b2cb}table.dataTable.display tbody>tr:hover>.selected,table.dataTable.display tbody>tr>.selected:hover,table.dataTable.order-column.hover tbody>tr:hover>.selected,table.dataTable.order-column.hover tbody>tr>.selected:hover{background-color:#a2aec7}table.dataTable tbody td.select-checkbox,table.dataTable tbody th.select-checkbox{position:relative}table.dataTable tbody td.select-checkbox:after,table.dataTable tbody td.select-checkbox:before,table.dataTable tbody th.select-checkbox:after,table.dataTable tbody th.select-checkbox:before{display:block;position:absolute;top:1.2em;left:50%;width:12px;height:12px;-webkit-box-sizing:border-box;box-sizing:border-box}table.dataTable tbody td.select-checkbox:before,table.dataTable tbody th.select-checkbox:before{content:' ';margin-top:4px;margin-left:-6px;border:1px solid #000;-webkit-border-radius:3px;border-radius:3px}table.dataTable tr.selected td.select-checkbox:after,table.dataTable tr.selected th.select-checkbox:after{content:'\2714';margin-top:0;margin-left:-4px;text-align:center;text-shadow:1px 1px #B0BED9,-1px -1px #B0BED9,1px -1px #B0BED9,-1px 1px #B0BED9}div.dataTables_wrapper span.select-info,div.dataTables_wrapper span.select-item{margin-left:.5em}@media screen and (max-width:640px){div.dataTables_wrapper span.select-info,div.dataTables_wrapper span.select-item{margin-left:0;display:block}}
--------------------------------------------------------------------------------
/public/scss/addons/_datatables.scss:
--------------------------------------------------------------------------------
1 | /*
2 | * MDBootstrap integration with Datatables
3 | * Learn more: https://mdbootstrap.com/docs/jquery/tables/datatables/
4 | * About MDBootstrap: https://mdbootstrap.com/
5 | *
6 | * This combined file was created by the DataTables downloader builder:
7 | * https://datatables.net/download
8 | *
9 | * To rebuild or modify this file with the latest versions of the included
10 | * software please visit:
11 | * https://datatables.net/download/#bs4/dt-1.10.18
12 | *
13 | * Included libraries:
14 | * DataTables 1.10.18
15 | */
16 |
17 | div.dataTables_wrapper div {
18 | &.dataTables_length {
19 | select, input {
20 | width: auto;
21 | }
22 | &.d-flex.flex-row {
23 | label {
24 | margin-top: 1.2rem;
25 | margin-right: 1rem;
26 | }
27 | .select-wrapper.mdb-select {
28 | span, .select-dropdown {
29 | margin-top: 1rem;
30 | }
31 | }
32 | }
33 | }
34 | &.dataTables_length,
35 | &.dataTables_filter {
36 | label {
37 | padding-top: .5rem;
38 | padding-bottom: .5rem;
39 | font-weight: 400;
40 | text-align: left;
41 | }
42 | }
43 | &.dataTables_filter {
44 | select,
45 | input {
46 | width: auto;
47 | }
48 | input {
49 | display: inline-block;
50 | margin-left: .5rem;
51 | }
52 | text-align: right;
53 | }
54 | &.dataTables_info,
55 | &.dataTables_paginate {
56 | padding-top: 1rem;
57 | padding-bottom: 1rem;
58 | font-weight: 400;
59 | }
60 | &.dataTables_paginate {
61 | margin: 0;
62 | text-align: right;
63 | ul.pagination {
64 | -ms-flex-pack: end;
65 | -webkit-justify-content: flex-end;
66 | justify-content: flex-end;
67 | -webkit-box-pack: end;
68 | .page-item {
69 | &.active .page-link:focus {
70 | background-color: #4285f4;
71 | }
72 | .page-link:focus {
73 | -webkit-box-shadow: none;
74 | box-shadow: none;
75 | }
76 | }
77 | }
78 | }
79 | }
80 |
81 | @media (max-width: 767px) {
82 | div.dataTables_wrapper div {
83 | .dataTables_length, .dataTables_filter, .dataTables_info, .dataTables_paginate ul.pagination {
84 | -ms-flex-pack: center;
85 | -webkit-justify-content: center;
86 | justify-content: center;
87 | text-align: center;
88 | -webkit-box-pack: center;
89 | }
90 | }
91 | }
92 |
93 | .bs-select select {
94 | display: inline-block !important;
95 | }
96 |
97 | table.dataTable thead {
98 | cursor: pointer;
99 | > tr > {
100 | th,
101 | td {
102 | &.sorting_asc, &.sorting_desc, &.sorting {
103 | padding-right: 30px;
104 | }
105 | }
106 | th:active, td:active {
107 | outline: none;
108 | }
109 | }
110 | .sorting,
111 | .sorting_asc,
112 | .sorting_desc,
113 | .sorting_asc_disabled,
114 | .sorting_desc_disabled {
115 | position: relative;
116 | cursor: pointer;
117 | &:before, &:after {
118 | position: absolute;
119 | bottom: .9em;
120 | display: block;
121 | opacity: .3;
122 | }
123 | }
124 | .sorting:before, .sorting_asc:before, .sorting_desc:before, .sorting_asc_disabled:before, .sorting_desc_disabled:before {
125 | right: 1em;
126 | font-family: "Font Awesome\ 5 Free", sans-serif;
127 | font-size: 1rem;
128 | font-weight: 900;
129 | content: "\f0de";
130 | }
131 | .sorting:after, .sorting_asc:after, .sorting_desc:after, .sorting_asc_disabled:after, .sorting_desc_disabled:after {
132 | right: 16px;
133 | font-family: "Font Awesome\ 5 Free", sans-serif;
134 | font-size: 1rem;
135 | font-weight: 900;
136 | content: "\f0dd";
137 | }
138 | .sorting_asc:before, .sorting_desc:after {
139 | opacity: 1;
140 | }
141 | .sorting_asc_disabled:before, .sorting_desc_disabled:after {
142 | opacity: 0;
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/public/scss/core/_waves.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Waves v0.7.6
3 | * http://fian.my.id/Waves
4 | *
5 | * Copyright 2014-2018 Alfiana E. Sibuea and other contributors
6 | * Released under the MIT license
7 | * https://github.com/fians/Waves/blob/master/LICENSE */
8 |
9 | @mixin waves-transition($transition){
10 | -webkit-transition: $transition;
11 | -moz-transition: $transition;
12 | -o-transition: $transition;
13 | transition: $transition;
14 | }
15 |
16 | @mixin waves-transform($string){
17 | -webkit-transform: $string;
18 | -moz-transform: $string;
19 | -ms-transform: $string;
20 | -o-transform: $string;
21 | transform: $string;
22 | }
23 |
24 | @mixin waves-box-shadow($shadow){
25 | -webkit-box-shadow: $shadow;
26 | box-shadow: $shadow;
27 | }
28 |
29 | .waves-effect {
30 | position: relative;
31 | overflow: hidden;
32 | cursor: pointer;
33 | -webkit-user-select: none;
34 | -moz-user-select: none;
35 | -ms-user-select: none;
36 | user-select: none;
37 | -webkit-tap-highlight-color: transparent;
38 |
39 | .waves-ripple {
40 | $gradient: rgba(0, 0, 0, .2) 0,rgba(0, 0, 0, .3) 40%,rgba(0, 0, 0, .4) 50%,rgba(0, 0, 0, .5) 60%,rgba(255, 255, 255, 0) 70%;
41 | position: absolute;
42 | width: 100px;
43 | height: 100px;
44 | margin-top: -50px;
45 | margin-left: -50px;
46 | pointer-events: none;
47 | background: rgba(0, 0, 0, .2);
48 | background: radial-gradient($gradient);
49 | border-radius: 50%;
50 | opacity: 0;
51 | -webkit-transition-property: -webkit-transform, opacity;
52 | -moz-transition-property: -moz-transform, opacity;
53 | -o-transition-property: -o-transform, opacity;
54 | transition-property: transform, opacity;
55 | @include waves-transition(all .5s ease-out);
56 | @include waves-transform(scale(0) translate(0,0));
57 | }
58 |
59 | &.waves-light .waves-ripple {
60 | $gradient: rgba(255, 255, 255, .2) 0,rgba(255, 255, 255, .3) 40%,rgba(255, 255, 255, .4) 50%,rgba(255, 255, 255, .5) 60%,rgba(255, 255, 255, 0) 70%;
61 | background: rgba(255, 255, 255, .4);
62 | background: radial-gradient($gradient);
63 | }
64 |
65 | &.waves-classic .waves-ripple {
66 | background: rgba(0, 0, 0, .2);
67 | }
68 |
69 | &.waves-classic.waves-light .waves-ripple {
70 | background: rgba(255, 255, 255, .4);
71 | }
72 | }
73 |
74 | .waves-notransition {
75 | @include waves-transition(none #{"!important"});
76 | }
77 |
78 | .waves-button,
79 | .waves-circle {
80 | @include waves-transform(translateZ(0));
81 | -webkit-mask-image: -webkit-radial-gradient(circle, #fff 100%, #000 100%);
82 | }
83 |
84 | .waves-button,
85 | .waves-button:hover,
86 | .waves-button:visited,
87 | .waves-button-input {
88 | z-index: 1;
89 | font-size: 1em;
90 | line-height: 1em;
91 | color: inherit;
92 | text-align: center;
93 | text-decoration: none;
94 | white-space: nowrap;
95 | vertical-align: middle;
96 | cursor: pointer;
97 | background-color: rgba(0, 0, 0, 0);
98 | border: none;
99 | outline: none;
100 | }
101 |
102 | .waves-button {
103 | padding: .85em 1.1em;
104 | border-radius: .2em;
105 | }
106 |
107 | .waves-button-input {
108 | padding: .85em 1.1em;
109 | margin: 0;
110 | }
111 |
112 | .waves-input-wrapper {
113 | position: relative;
114 | display: inline-block;
115 | vertical-align: middle;
116 | border-radius: .2em;
117 |
118 | &.waves-button {
119 | padding: 0;
120 | }
121 |
122 | .waves-button-input {
123 | position: relative;
124 | top: 0;
125 | left: 0;
126 | z-index: 1;
127 | }
128 | }
129 |
130 | .waves-circle {
131 | width: 2.5em;
132 | height: 2.5em;
133 | line-height: 2.5em;
134 | text-align: center;
135 | border-radius: 50%;
136 | }
137 |
138 | .waves-float {
139 | -webkit-mask-image: none;
140 | @include waves-box-shadow(0 1px 1.5px 1px rgba(0, 0, 0, .12));
141 | @include waves-transition(all 300ms);
142 |
143 | &:active {
144 | @include waves-box-shadow(0 8px 20px 1px rgba(0, 0, 0, .3));
145 | }
146 | }
147 |
148 | .waves-block {
149 | display: block;
150 | }
151 |
152 | a {
153 | &.waves-effect,
154 | &.waves-light {
155 | display: inline-block;
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/public/js/addons/rating.js:
--------------------------------------------------------------------------------
1 | (function ($) {
2 | $.fn.mdbRate = function () {
3 | var $stars;
4 | // Custom whitelist to allow for using HTML tags in popover content
5 | var myDefaultWhiteList = $.fn.tooltip.Constructor.Default.whiteList
6 | myDefaultWhiteList.textarea = [];
7 | myDefaultWhiteList.button = [];
8 |
9 | var $container = $(this);
10 |
11 | var titles = ['Very bad', 'Poor', 'OK', 'Good', 'Excellent'];
12 |
13 | for (var i = 0; i < 5; i++) {
14 | $container.append(` `);
16 | }
17 |
18 | $stars = $container.children();
19 |
20 | if ($container.hasClass('rating-faces')) {
21 | $stars.addClass('far fa-meh-blank');
22 | } else if ($container.hasClass('empty-stars')) {
23 | $stars.addClass('far fa-star');
24 | } else {
25 | $stars.addClass('fas fa-star');
26 | }
27 |
28 | $stars.on('mouseover', function () {
29 | var index = $(this).attr('data-index');
30 | markStarsAsActive(index);
31 | });
32 |
33 | function markStarsAsActive(index) {
34 | unmarkActive();
35 |
36 | for (var i = 0; i <= index; i++) {
37 |
38 | if ($container.hasClass('rating-faces')) {
39 | $($stars.get(i)).removeClass('fa-meh-blank');
40 | $($stars.get(i)).addClass('live');
41 |
42 | switch (index) {
43 | case '0':
44 | $($stars.get(i)).addClass('fa-angry');
45 | break;
46 | case '1':
47 | $($stars.get(i)).addClass('fa-frown');
48 | break;
49 | case '2':
50 | $($stars.get(i)).addClass('fa-meh');
51 | break;
52 | case '3':
53 | $($stars.get(i)).addClass('fa-smile');
54 | break;
55 | case '4':
56 | $($stars.get(i)).addClass('fa-laugh');
57 | break;
58 | }
59 |
60 | } else if ($container.hasClass('empty-stars')) {
61 | $($stars.get(i)).addClass('fas');
62 | switch (index) {
63 | case '0':
64 | $($stars.get(i)).addClass('oneStar');
65 | break;
66 | case '1':
67 | $($stars.get(i)).addClass('twoStars');
68 | break;
69 | case '2':
70 | $($stars.get(i)).addClass('threeStars');
71 | break;
72 | case '3':
73 | $($stars.get(i)).addClass('fourStars');
74 | break;
75 | case '4':
76 | $($stars.get(i)).addClass('fiveStars');
77 | break;
78 | }
79 | } else {
80 | $($stars.get(i)).addClass('amber-text');
81 |
82 | }
83 | }
84 | }
85 |
86 | function unmarkActive() {
87 | $stars.parent().hasClass('rating-faces') ? $stars.addClass('fa-meh-blank') : $stars;
88 | $container.hasClass('empty-stars') ? $stars.removeClass('fas') : $container;
89 | $stars.removeClass('fa-angry fa-frown fa-meh fa-smile fa-laugh live oneStar twoStars threeStars fourStars fiveStars amber-text');
90 | }
91 |
92 | $stars.on('click', function () {
93 | $stars.popover('hide');
94 | });
95 |
96 | // Submit, you can add some extra custom code here
97 | // ex. to send the information to the server
98 | $container.on('click', '#voteSubmitButton', function () {
99 | $stars.popover('hide');
100 | });
101 |
102 | // Cancel, just close the popover
103 | $container.on('click', '#closePopoverButton', function () {
104 | $stars.popover('hide');
105 | });
106 |
107 | if ($container.hasClass('feedback')) {
108 |
109 | $(function () {
110 | $stars.popover({
111 | // Append popover to #rateMe to allow handling form inside the popover
112 | container: $container,
113 | // Custom content for popover
114 | content: ` Submit! Close
`
115 | });
116 | })
117 | }
118 |
119 | $stars.tooltip();
120 | }
121 | })(jQuery);
--------------------------------------------------------------------------------
/src/views/cart.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%- include('./partials/head') %>
6 |
7 |
8 |
9 | <%- include('./partials/header') %>
10 |
11 |
12 |
Productos en mi carrito
13 |
14 |
15 |
16 |
17 |
18 |
19 | #
20 |
21 |
22 | Producto
23 |
24 |
25 | Precio
26 |
27 |
28 | Cantidad
29 |
30 |
31 | Subtotal
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
42 |
43 |
44 |
84 |
85 |
86 | <%- include('./partials/footer') %>
87 | <%- include('./partials/scripts') %>
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/public/scss/addons/_datatables-select.scss:
--------------------------------------------------------------------------------
1 | /*
2 | * MDBootstrap integration with Datatables
3 | * Learn more: https://mdbootstrap.com/docs/jquery/tables/datatables/
4 | * About MDBootstrap: https://mdbootstrap.com/
5 | *
6 | * This combined file was created taking that code from this webstie:
7 | * https://cdn.datatables.net/select/1.2.7/css/select.dataTables.min.css
8 | *
9 | *
10 | * To rebuild or modify this file with the latest versions of the included
11 | * software please visit:
12 | * https://datatables.net/download/#bs4/dt-1.10.18
13 | *
14 | * Included libraries:
15 | * DataTables 1.10.18
16 | */
17 |
18 | table {
19 | &.dataTable {
20 | tbody > tr {
21 | &.selected,
22 | > .selected {
23 | background-color: #b0bed9;
24 | }
25 | }
26 | &.stripe, &.display {
27 | tbody > tr.odd {
28 | &.selected,
29 | > .selected {
30 | background-color: #acbad4;
31 | }
32 | }
33 | }
34 | &.hover, &.display {
35 | tbody > tr {
36 | &.selected:hover,
37 | > .selected:hover {
38 | background-color: #aab7d1;
39 | }
40 | }
41 | }
42 | &.order-column, &.display {
43 | tbody > tr {
44 | &.selected > {
45 | .sorting_1, .sorting_2, .sorting_3 {
46 | background-color: #acbad5;
47 | }
48 | }
49 | > .selected {
50 | background-color: #acbad5;
51 | }
52 | }
53 | }
54 | &.display, &.order-column.stripe {
55 | tbody > tr {
56 | &.odd.selected > .sorting_1 {
57 | background-color: #a6b4cd;
58 | }
59 | }
60 | }
61 | &.display tbody > tr.odd.selected > .sorting_2, &.order-column.stripe tbody > tr.odd.selected > .sorting_2 {
62 | background-color: #a8b5cf;
63 | }
64 | &.display tbody > tr.odd.selected > .sorting_3, &.order-column.stripe tbody > tr.odd.selected > .sorting_3 {
65 | background-color: #a9b7d1;
66 | }
67 | &.display tbody > tr.even.selected > .sorting_1, &.order-column.stripe tbody > tr.even.selected > .sorting_1 {
68 | background-color: #acbad5;
69 | }
70 | &.display tbody > tr.even.selected > .sorting_2, &.order-column.stripe tbody > tr.even.selected > .sorting_2 {
71 | background-color: #aebcd6;
72 | }
73 | &.display tbody > tr.even.selected > .sorting_3, &.order-column.stripe tbody > tr.even.selected > .sorting_3 {
74 | background-color: #afbdd8;
75 | }
76 | &.display tbody > tr.odd > .selected, &.order-column.stripe tbody > tr.odd > .selected {
77 | background-color: #a6b4cd;
78 | }
79 | &.display tbody > tr.even > .selected, &.order-column.stripe tbody > tr.even > .selected {
80 | background-color: #acbad5;
81 | }
82 | &.display tbody > tr.selected:hover > .sorting_1, &.order-column.hover tbody > tr.selected:hover > .sorting_1 {
83 | background-color: #a2aec7;
84 | }
85 | &.display tbody > tr.selected:hover > .sorting_2, &.order-column.hover tbody > tr.selected:hover > .sorting_2 {
86 | background-color: #a3b0c9;
87 | }
88 | &.display tbody > tr.selected:hover > .sorting_3, &.order-column.hover tbody > tr.selected:hover > .sorting_3 {
89 | background-color: #a5b2cb;
90 | }
91 | &.display, &.order-column.hover {
92 | tbody > tr {
93 | &:hover > .selected, > .selected:hover {
94 | background-color: #a2aec7;
95 | }
96 | }
97 | }
98 | tbody {
99 | td, th {
100 | &.select-checkbox {
101 | position: relative;
102 | &:before,
103 | &:after {
104 | position: absolute;
105 | top: 1.2em;
106 | left: 50%;
107 | box-sizing: border-box;
108 | display: block;
109 | width: 12px;
110 | height: 12px;
111 | }
112 | }
113 | }
114 | td.select-checkbox:before,
115 | th.select-checkbox:before {
116 | margin-top: 4px;
117 | margin-left: -6px;
118 | content: " ";
119 | border: 1px solid #000;
120 | border-radius: 3px;
121 | }
122 | }
123 | tr.selected {
124 | td.select-checkbox:after,
125 | th.select-checkbox:after {
126 | margin-top: 0;
127 | margin-left: -4px;
128 | text-align: center;
129 | text-shadow: 1px 1px #b0bed9, -1px -1px #b0bed9, 1px -1px #b0bed9, -1px 1px #b0bed9;
130 | content: "\2714";
131 | }
132 | }
133 | }
134 | }
135 |
136 | div.dataTables_wrapper span {
137 | &.select-info, &.select-item {
138 | margin-left: .5em;
139 | }
140 | }
141 |
142 | @media screen and (max-width: 640px) {
143 | div.dataTables_wrapper span {
144 | &.select-info, &.select-item {
145 | display: block;
146 | margin-left: 0;
147 | }
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/public/scss/free/_steppers.scss:
--------------------------------------------------------------------------------
1 | // Steppers
2 | ul.stepper {
3 | padding: 0 1.5rem;
4 | padding: 1.5rem;
5 | margin: 1em -1.5rem;
6 | overflow-x: hidden;
7 | overflow-y: auto;
8 | counter-reset: section;
9 |
10 | li {
11 | a {
12 | padding: $stepper-li-a-padding;
13 | text-align: center;
14 |
15 | .circle {
16 | display: inline-block;
17 | width: 1.75rem;
18 | height: 1.75rem;
19 | margin-right: $stepper-li-a-circle-mr;
20 | line-height: 1.7rem;
21 | color: $stepper-li-a-circle-color;
22 | text-align: center;
23 | background: $stepper-li-a-circle-bg;
24 | border-radius: $stepper-li-a-circle-border-radius;
25 | }
26 |
27 | .label {
28 | display: inline-block;
29 | color: $stepper-li-a-circle-bg;
30 | }
31 | }
32 |
33 | &.active,
34 | &.completed {
35 | a {
36 | .circle {
37 | @extend .primary-color;
38 | }
39 |
40 | .label {
41 | font-weight: 600;
42 | color: $stepper-li-a-label-color;
43 | }
44 | }
45 | }
46 |
47 | &.warning {
48 | a {
49 | .circle {
50 | // background-color: #ff3547 !important;
51 | @extend .danger-color !optional;
52 | }
53 | }
54 | }
55 | }
56 | }
57 |
58 | // Horizontal
59 | .stepper-horizontal {
60 | position: relative;
61 | display: flex;
62 | justify-content: space-between;
63 |
64 | li {
65 | position: relative;
66 | display: flex;
67 | flex: 1;
68 | align-items: center;
69 | transition: $stepper-horizontal-li-transition;
70 |
71 | a {
72 | .label {
73 | margin-top: $stepper-horizontal-li-a-label-mt;
74 | }
75 | }
76 |
77 | &:not(:last-child):after {
78 | position: relative;
79 | flex: 1;
80 | height: $stepper-horizontal-li-after-height;
81 | margin: $stepper-horizontal-li-after-margin 0 0 0;
82 | content: "";
83 | background-color: $stepper-horizontal-li-after-bgc;
84 | }
85 |
86 | &:not(:first-child):before {
87 | position: relative;
88 | flex: 1;
89 | height: $stepper-horizontal-li-after-height;
90 | margin: $stepper-horizontal-li-after-margin 0 0 0;
91 | content: "";
92 | background-color: $stepper-horizontal-li-after-bgc;
93 | }
94 |
95 | &:hover {
96 | background-color: rgba(0, 0, 0, .06);
97 | }
98 | }
99 |
100 | @media (max-width: $stepper-horizontal-breakpoint) {
101 | flex-direction: column;
102 |
103 | li {
104 | flex-direction: column;
105 | align-items: flex-start;
106 |
107 | a {
108 | .label {
109 | flex-flow: column nowrap;
110 | order: 2;
111 | margin-top: $stepper-horizontal-small-li-a-label-mt;
112 | }
113 | }
114 |
115 | &:not(:last-child):after {
116 | position: absolute;
117 | top: $stepper-horizontal-small-li-after-top;
118 | left: $stepper-horizontal-small-li-after-left;
119 | width: $stepper-horizontal-small-li-after-width;
120 | height: $stepper-horizontal-small-li-after-height;
121 | content: "";
122 | }
123 | }
124 | }
125 |
126 | > li:not(:last-of-type) {
127 | margin-bottom: 0 !important;
128 | }
129 | }
130 |
131 | // Vertical
132 | .stepper-vertical {
133 | position: relative;
134 | display: flex;
135 | flex-direction: column;
136 | justify-content: space-between;
137 |
138 | li {
139 | position: relative;
140 | display: flex;
141 | flex: 1;
142 | flex-direction: column;
143 | align-items: flex-start;
144 |
145 | a {
146 | position: relative;
147 | display: flex;
148 | align-self: flex-start;
149 |
150 | .circle {
151 | order: 1;
152 | }
153 |
154 | .label {
155 | flex-flow: column nowrap;
156 | order: 2;
157 | margin-top: $stepper-vertical-li-a-label-mt;
158 | }
159 | }
160 |
161 | &.completed {
162 | a {
163 | .label {
164 | font-weight: 500;
165 | }
166 | }
167 | }
168 |
169 | .step-content {
170 | display: block;
171 | padding: $stepper-vertical-li-step-content-padding;
172 | margin-top: 0;
173 | margin-left: $stepper-vertical-li-step-content-ml;
174 |
175 | p {
176 | font-size: $stepper-vertical-li-step-content-p-font-size;
177 | }
178 | }
179 |
180 | &:not(:last-child):after {
181 | position: absolute;
182 | top: $stepper-vertical-li-after-top;
183 | left: $stepper-vertical-li-after-left;
184 | width: $stepper-vertical-li-after-width;
185 | height: $stepper-vertical-li-after-height;
186 | content: "";
187 | background-color: $stepper-vertical-li-after-bgc;
188 | }
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/public/scss/free/_treeview.scss:
--------------------------------------------------------------------------------
1 | // Treeview
2 | .treeview {
3 | &.w-20 {
4 | width: 20rem;
5 | }
6 | .rotate {
7 | margin-top: .2rem;
8 | font-size: .8rem;
9 | vertical-align: text-top;
10 | cursor: pointer;
11 | user-select: none;
12 | transition: all .1s linear;
13 | &.down {
14 | transform: rotate(90deg);
15 | }
16 | }
17 | .nested {
18 | display: none;
19 | }
20 | .active {
21 | display: block;
22 | }
23 | ul {
24 | list-style-type: none;
25 | }
26 | .ic-w {
27 | width: 1.3rem;
28 | }
29 | }
30 |
31 | .treeview-animated {
32 | &.w-20 {
33 | width: 20rem;
34 | }
35 | ul {
36 | position: relative;
37 | padding-left: 1em;
38 | list-style: none;
39 | }
40 |
41 | .treeview-animated-list {
42 | li {
43 | padding: .2em 0 0 .2em;
44 | }
45 |
46 | .treeview-animated-items {
47 |
48 | .nested {
49 | &::before {
50 | position: absolute;
51 | left: 5px;
52 | display: block;
53 | width: 5px;
54 | height: 100%;
55 | content: "";
56 | background-color: #808080;
57 | }
58 | }
59 |
60 | .closed {
61 | display: block;
62 | padding: .2em .2em .2em .4em;
63 | margin-right: 0;
64 | border-top-left-radius: .3em;
65 | border-bottom-left-radius: .3em;
66 |
67 | &:hover {
68 | background-color: rgb(140, 185, 255);
69 | }
70 |
71 | .fa-angle-right {
72 | font-size: .8rem;
73 | transition: all .1s linear;
74 |
75 | &.down {
76 | position: relative;
77 | color: #f8f9fa;
78 | transform: rotate(90deg);
79 | }
80 | }
81 | }
82 |
83 | .open {
84 | background-color: rgb(50, 160, 255);
85 | transition: all .1s linear;
86 |
87 | &:hover {
88 | color: #f8f9fa;
89 | background-color: rgb(50, 160, 255);
90 | }
91 |
92 | span {
93 | color: #f8f9fa;
94 | }
95 | }
96 | }
97 |
98 | .treeview-animated-element {
99 | padding: .2em .2em .2em .6em;
100 | cursor: pointer;
101 | border-top-left-radius: 4px;
102 | border-bottom-left-radius: 4px;
103 | transition: all .1s linear;
104 |
105 | &:hover {
106 | background-color: rgb(140, 185, 255);
107 | }
108 |
109 | &.opened {
110 | color: #f8f9fa;
111 | background-color: rgb(50, 160, 255);
112 |
113 | &:hover {
114 | color: #f8f9fa;
115 | background-color: rgb(50, 160, 255);
116 | }
117 | }
118 | }
119 | }
120 | }
121 |
122 | .treeview-colorful {
123 | font-size: 16px;
124 | font-weight: 400;
125 | background: rgba(224, 127, 178, .2);
126 |
127 | &.w-20 {
128 | width: 20rem;
129 | }
130 |
131 | hr {
132 | border-color: #a2127a;
133 | }
134 |
135 | h6 {
136 | font-size: 1.4em;
137 | font-weight: 500;
138 | color: #a2127a;
139 | }
140 |
141 | ul {
142 | position: relative;
143 | padding-left: 0;
144 | list-style: none;
145 | }
146 |
147 | .treeview-colorful-list {
148 |
149 | ul {
150 | padding-left: 1em;
151 | margin-top: .1em;
152 | background: rgba(224, 127, 178, .2);
153 | }
154 | }
155 |
156 | .treeview-colorful-element {
157 | padding: .2em .2em .2em 1em;
158 | cursor: pointer;
159 | border: 2px solid transparent;
160 | border-right: 0 solid transparent;
161 | transition: all .1s linear;
162 |
163 | &:hover {
164 | background-color: #e07fb2;
165 | }
166 |
167 | &.opened {
168 | color: #ffac47;
169 | background-color: #a2127a;
170 | border: 2px solid #ffac47;
171 | border-right: 0 solid transparent;
172 |
173 | &:hover {
174 | color: #ffac47;
175 | background-color: #a2127a;
176 | }
177 | }
178 |
179 | }
180 | .treeview-colorful-items-header {
181 | display: block;
182 | padding: .4em;
183 | margin-right: 0;
184 | border-bottom: 2px solid transparent;
185 | transition: all .1s linear;
186 |
187 | &:hover {
188 | background-color: #e07fb2;
189 | }
190 |
191 | &.open {
192 | background-color: #a2127a;
193 | border-bottom: 2px solid #ffac47;
194 | transition: all .1s linear;
195 |
196 | span {
197 | color: #ffac47;
198 | }
199 |
200 | &:hover {
201 | color: #ffac47;
202 | background-color: #a2127a;
203 | }
204 |
205 | div:hover {
206 | background-color: #a2127a;
207 | }
208 | }
209 |
210 | .fa-angle-right {
211 | font-size: .8rem;
212 | transition: all .2s linear;
213 | }
214 |
215 | .fas {
216 | position: relative;
217 | color: #ffac47;
218 | transition: all .2s linear;
219 | transform: rotate(90deg);
220 | }
221 |
222 | .fa-minus-circle {
223 | position: relative;
224 | color: #ffac47;
225 | transition: all .2s linear;
226 | transform: rotate(180deg);
227 | }
228 | }
229 | }
230 |
--------------------------------------------------------------------------------
/src/views/products/detail.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%- include('../partials/head') %>
6 |
7 |
8 |
9 |
10 | <%- include('../partials/header') %>
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
44 |
45 |
46 |
47 | $200
48 |
49 | $100
50 |
51 |
52 |
Description
53 |
54 |
Lorem ipsum dolor sit amet consectetur adipisicing elit. Et dolor suscipit libero eos
55 | atque quia ipsa
56 | sint voluptatibus!
57 | Beatae sit assumenda asperiores iure at maxime atque repellendus maiores quia
58 | sapiente.
59 |
60 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
Additional information
88 |
89 |
Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus suscipit modi sapiente
90 | illo soluta odit
91 | voluptates,
92 | quibusdam officia. Neque quibusdam quas a quis porro? Molestias illo neque eum in
93 | laborum.
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 | <%- include('../partials/footer') %>
135 | <%- include('../partials/scripts') %>
136 |
137 |
138 |
--------------------------------------------------------------------------------
/public/js/addons/imagesloaded.pkgd.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * imagesLoaded PACKAGED v4.1.4
3 | * JavaScript is all like "You images are done yet or what?"
4 | * MIT License
5 | */
6 |
7 | !function(e,t){"function"==typeof define&&define.amd?define("ev-emitter/ev-emitter",t):"object"==typeof module&&module.exports?module.exports=t():e.EvEmitter=t()}("undefined"!=typeof window?window:this,function(){function e(){}var t=e.prototype;return t.on=function(e,t){if(e&&t){var i=this._events=this._events||{},n=i[e]=i[e]||[];return n.indexOf(t)==-1&&n.push(t),this}},t.once=function(e,t){if(e&&t){this.on(e,t);var i=this._onceEvents=this._onceEvents||{},n=i[e]=i[e]||{};return n[t]=!0,this}},t.off=function(e,t){var i=this._events&&this._events[e];if(i&&i.length){var n=i.indexOf(t);return n!=-1&&i.splice(n,1),this}},t.emitEvent=function(e,t){var i=this._events&&this._events[e];if(i&&i.length){i=i.slice(0),t=t||[];for(var n=this._onceEvents&&this._onceEvents[e],o=0;o tr.selected,
18 | table.dataTable tbody > tr > .selected {
19 | background-color: #B0BED9; }
20 |
21 | table.dataTable.stripe tbody > tr.odd.selected,
22 | table.dataTable.stripe tbody > tr.odd > .selected, table.dataTable.display tbody > tr.odd.selected,
23 | table.dataTable.display tbody > tr.odd > .selected {
24 | background-color: #acbad4; }
25 |
26 | table.dataTable.hover tbody > tr.selected:hover,
27 | table.dataTable.hover tbody > tr > .selected:hover, table.dataTable.display tbody > tr.selected:hover,
28 | table.dataTable.display tbody > tr > .selected:hover {
29 | background-color: #aab7d1; }
30 |
31 | table.dataTable.order-column tbody > tr.selected > .sorting_1, table.dataTable.order-column tbody > tr.selected > .sorting_2, table.dataTable.order-column tbody > tr.selected > .sorting_3, table.dataTable.display tbody > tr.selected > .sorting_1, table.dataTable.display tbody > tr.selected > .sorting_2, table.dataTable.display tbody > tr.selected > .sorting_3 {
32 | background-color: #acbad5; }
33 |
34 | table.dataTable.order-column tbody > tr > .selected, table.dataTable.display tbody > tr > .selected {
35 | background-color: #acbad5; }
36 |
37 | table.dataTable.display tbody > tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_1 {
38 | background-color: #a6b4cd; }
39 |
40 | table.dataTable.display tbody > tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_2 {
41 | background-color: #a8b5cf; }
42 |
43 | table.dataTable.display tbody > tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_3 {
44 | background-color: #a9b7d1; }
45 |
46 | table.dataTable.display tbody > tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_1 {
47 | background-color: #acbad5; }
48 |
49 | table.dataTable.display tbody > tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_2 {
50 | background-color: #aebcd6; }
51 |
52 | table.dataTable.display tbody > tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_3 {
53 | background-color: #afbdd8; }
54 |
55 | table.dataTable.display tbody > tr.odd > .selected, table.dataTable.order-column.stripe tbody > tr.odd > .selected {
56 | background-color: #a6b4cd; }
57 |
58 | table.dataTable.display tbody > tr.even > .selected, table.dataTable.order-column.stripe tbody > tr.even > .selected {
59 | background-color: #acbad5; }
60 |
61 | table.dataTable.display tbody > tr.selected:hover > .sorting_1, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_1 {
62 | background-color: #a2aec7; }
63 |
64 | table.dataTable.display tbody > tr.selected:hover > .sorting_2, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_2 {
65 | background-color: #a3b0c9; }
66 |
67 | table.dataTable.display tbody > tr.selected:hover > .sorting_3, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_3 {
68 | background-color: #a5b2cb; }
69 |
70 | table.dataTable.display tbody > tr:hover > .selected, table.dataTable.display tbody > tr > .selected:hover, table.dataTable.order-column.hover tbody > tr:hover > .selected, table.dataTable.order-column.hover tbody > tr > .selected:hover {
71 | background-color: #a2aec7; }
72 |
73 | table.dataTable tbody td.select-checkbox, table.dataTable tbody th.select-checkbox {
74 | position: relative; }
75 |
76 | table.dataTable tbody td.select-checkbox:before, table.dataTable tbody td.select-checkbox:after, table.dataTable tbody th.select-checkbox:before, table.dataTable tbody th.select-checkbox:after {
77 | display: block;
78 | position: absolute;
79 | top: 1.2em;
80 | left: 50%;
81 | width: 12px;
82 | height: 12px;
83 | -webkit-box-sizing: border-box;
84 | box-sizing: border-box; }
85 |
86 | table.dataTable tbody td.select-checkbox:before,
87 | table.dataTable tbody th.select-checkbox:before {
88 | content: ' ';
89 | margin-top: 4px;
90 | margin-left: -6px;
91 | border: 1px solid black;
92 | -webkit-border-radius: 3px;
93 | border-radius: 3px; }
94 |
95 | table.dataTable tr.selected td.select-checkbox:after,
96 | table.dataTable tr.selected th.select-checkbox:after {
97 | content: '\2714';
98 | margin-top: 0px;
99 | margin-left: -4px;
100 | text-align: center;
101 | text-shadow: 1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9; }
102 |
103 | div.dataTables_wrapper span.select-info, div.dataTables_wrapper span.select-item {
104 | margin-left: 0.5em; }
105 |
106 | @media screen and (max-width: 640px) {
107 | div.dataTables_wrapper span.select-info, div.dataTables_wrapper span.select-item {
108 | margin-left: 0;
109 | display: block; } }
110 |
--------------------------------------------------------------------------------
/src/views/partials/carousel.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Vea nuestros productos
27 |
28 |
29 |
30 | Los mejores del mercado
31 |
32 |
33 |
34 | Creamos ropa para vos y que te sientas super comoda!.
35 |
36 |
37 |
Ver Productos
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | Carteras Fantásticas
62 |
63 |
64 |
65 | Disfruta todas nuestras carteras al mejor precio
66 |
67 |
68 |
69 | La mas grande variedad de carteras que jamás viste en un sitio!
70 |
71 |
72 |
Ver Productos
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | Jeans Impresionantes
97 |
98 |
99 |
100 | Altos jeans para vos y tus amigas!
101 |
102 |
103 |
104 | Veni a buscar todos los jeans que quieras, mucha variedad y todos los talles para
105 | que te
106 | sientas una reina.
107 |
108 |
109 |
Ver Productos
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 | Previous
129 |
130 |
131 |
132 | Next
133 |
134 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/public/js/modules/bs-custom-file-input.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * bsCustomFileInput v1.3.2 (https://github.com/Johann-S/bs-custom-file-input)
3 | * Copyright 2018 - 2019 Johann-S
4 | * Licensed under MIT (https://github.com/Johann-S/bs-custom-file-input/blob/master/LICENSE)
5 | */
6 | (function (global, factory) {
7 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
8 | typeof define === 'function' && define.amd ? define(factory) :
9 | (global = global || self, global.bsCustomFileInput = factory());
10 | }(this, function () {
11 | 'use strict';
12 |
13 | var Selector = {
14 | CUSTOMFILE: '.custom-file input[type="file"]',
15 | CUSTOMFILELABEL: '.custom-file-label',
16 | FORM: 'form',
17 | INPUT: 'input'
18 | };
19 |
20 | var textNodeType = 3;
21 |
22 | var getDefaultText = function getDefaultText(input) {
23 | var defaultText = '';
24 | var label = input.parentNode.querySelector(Selector.CUSTOMFILELABEL);
25 |
26 | if (label) {
27 | defaultText = label.innerHTML;
28 | }
29 |
30 | return defaultText;
31 | };
32 |
33 | var findFirstChildNode = function findFirstChildNode(element) {
34 | if (element.childNodes.length > 0) {
35 | var childNodes = [].slice.call(element.childNodes);
36 |
37 | for (var i = 0; i < childNodes.length; i++) {
38 | var node = childNodes[i];
39 |
40 | if (node.nodeType !== textNodeType) {
41 | return node;
42 | }
43 | }
44 | }
45 |
46 | return element;
47 | };
48 |
49 | var restoreDefaultText = function restoreDefaultText(input) {
50 | var defaultText = input.bsCustomFileInput.defaultText;
51 | var label = input.parentNode.querySelector(Selector.CUSTOMFILELABEL);
52 |
53 | if (label) {
54 | var element = findFirstChildNode(label);
55 | element.innerHTML = defaultText;
56 | }
57 | };
58 |
59 | var fileApi = !!window.File;
60 | var FAKE_PATH = 'fakepath';
61 | var FAKE_PATH_SEPARATOR = '\\';
62 |
63 | var getSelectedFiles = function getSelectedFiles(input) {
64 | if (input.hasAttribute('multiple') && fileApi) {
65 | return [].slice.call(input.files).map(function (file) {
66 | return file.name;
67 | }).join(', ');
68 | }
69 |
70 | if (input.value.indexOf(FAKE_PATH) !== -1) {
71 | var splittedValue = input.value.split(FAKE_PATH_SEPARATOR);
72 | return splittedValue[splittedValue.length - 1];
73 | }
74 |
75 | return input.value;
76 | };
77 |
78 | function handleInputChange() {
79 | var label = this.parentNode.querySelector(Selector.CUSTOMFILELABEL);
80 |
81 | if (label) {
82 | var element = findFirstChildNode(label);
83 | var inputValue = getSelectedFiles(this);
84 |
85 | if (inputValue.length) {
86 | element.innerHTML = inputValue;
87 | } else {
88 | restoreDefaultText(this);
89 | }
90 | }
91 | }
92 |
93 | function handleFormReset() {
94 | var customFileList = [].slice.call(this.querySelectorAll(Selector.INPUT)).filter(function (input) {
95 | return !!input.bsCustomFileInput;
96 | });
97 |
98 | for (var i = 0, len = customFileList.length; i < len; i++) {
99 | restoreDefaultText(customFileList[i]);
100 | }
101 | }
102 |
103 | var customProperty = 'bsCustomFileInput';
104 | var Event = {
105 | FORMRESET: 'reset',
106 | INPUTCHANGE: 'change'
107 | };
108 | var bsCustomFileInput = {
109 | init: function init(inputSelector, formSelector) {
110 | if (inputSelector === void 0) {
111 | inputSelector = Selector.CUSTOMFILE;
112 | }
113 |
114 | if (formSelector === void 0) {
115 | formSelector = Selector.FORM;
116 | }
117 |
118 | var customFileInputList = [].slice.call(document.querySelectorAll(inputSelector));
119 | var formList = [].slice.call(document.querySelectorAll(formSelector));
120 |
121 | for (var i = 0, len = customFileInputList.length; i < len; i++) {
122 | var input = customFileInputList[i];
123 | Object.defineProperty(input, customProperty, {
124 | value: {
125 | defaultText: getDefaultText(input)
126 | },
127 | writable: true
128 | });
129 | handleInputChange.call(input);
130 | input.addEventListener(Event.INPUTCHANGE, handleInputChange);
131 | }
132 |
133 | for (var _i = 0, _len = formList.length; _i < _len; _i++) {
134 | formList[_i].addEventListener(Event.FORMRESET, handleFormReset);
135 |
136 | Object.defineProperty(formList[_i], customProperty, {
137 | value: true,
138 | writable: true
139 | });
140 | }
141 | },
142 | destroy: function destroy() {
143 | var formList = [].slice.call(document.querySelectorAll(Selector.FORM)).filter(function (form) {
144 | return !!form.bsCustomFileInput;
145 | });
146 | var customFileInputList = [].slice.call(document.querySelectorAll(Selector.INPUT)).filter(function (input) {
147 | return !!input.bsCustomFileInput;
148 | });
149 |
150 | for (var i = 0, len = customFileInputList.length; i < len; i++) {
151 | var input = customFileInputList[i];
152 | restoreDefaultText(input);
153 | input[customProperty] = undefined;
154 | input.removeEventListener(Event.INPUTCHANGE, handleInputChange);
155 | }
156 |
157 | for (var _i2 = 0, _len2 = formList.length; _i2 < _len2; _i2++) {
158 | formList[_i2].removeEventListener(Event.FORMRESET, handleFormReset);
159 |
160 | formList[_i2][customProperty] = undefined;
161 | }
162 | }
163 | };
164 |
165 | return bsCustomFileInput;
166 |
167 | }));
168 | //# sourceMappingURL=bs-custom-file-input.js.map
169 |
170 | document.addEventListener("DOMContentLoaded", function () {
171 |
172 | bsCustomFileInput.init()
173 | });
174 |
--------------------------------------------------------------------------------
/public/css/addons/datatables.css:
--------------------------------------------------------------------------------
1 | /*
2 | * MDBootstrap integration with Datatables
3 | * Learn more: https://mdbootstrap.com/docs/jquery/tables/datatables/
4 | * About MDBootstrap: https://mdbootstrap.com/
5 | *
6 | * This combined file was created by the DataTables downloader builder:
7 | * https://datatables.net/download
8 | *
9 | * To rebuild or modify this file with the latest versions of the included
10 | * software please visit:
11 | * https://datatables.net/download/#bs4/dt-1.10.18
12 | *
13 | * Included libraries:
14 | * DataTables 1.10.18
15 | */
16 | table.dataTable thead {
17 | cursor: pointer; }
18 | table.dataTable thead > tr > th:active,
19 | table.dataTable thead > tr > td:active {
20 | outline: none; }
21 |
22 | div.dataTables_wrapper div.dataTables_length.d-flex.flex-row label {
23 | margin-top: 1.2rem;
24 | margin-right: 1rem; }
25 |
26 | div.dataTables_wrapper div.dataTables_length.d-flex.flex-row .select-wrapper.mdb-select span,
27 | div.dataTables_wrapper div.dataTables_length.d-flex.flex-row .select-wrapper.mdb-select .select-dropdown {
28 | margin-top: 1rem; }
29 |
30 | div.dataTables_wrapper div.dataTables_length label, div.dataTables_wrapper div.dataTables_filter label {
31 | text-align: left;
32 | font-weight: normal;
33 | padding-top: .5rem;
34 | padding-bottom: .5rem; }
35 |
36 | div.dataTables_wrapper div.dataTables_length select,
37 | div.dataTables_wrapper div.dataTables_length input {
38 | width: auto; }
39 |
40 | div.dataTables_wrapper div.dataTables_filter {
41 | text-align: right; }
42 | div.dataTables_wrapper div.dataTables_filter select,
43 | div.dataTables_wrapper div.dataTables_filter input {
44 | width: auto; }
45 | div.dataTables_wrapper div.dataTables_filter input {
46 | margin-left: .5rem;
47 | display: inline-block; }
48 |
49 | div.dataTables_wrapper div.dataTables_info, div.dataTables_wrapper div.dataTables_paginate {
50 | font-weight: normal;
51 | padding-top: 1rem;
52 | padding-bottom: 1rem; }
53 |
54 | div.dataTables_wrapper div.dataTables_paginate {
55 | text-align: right;
56 | margin: 0; }
57 | div.dataTables_wrapper div.dataTables_paginate ul.pagination {
58 | -webkit-box-pack: end;
59 | -webkit-justify-content: flex-end;
60 | -ms-flex-pack: end;
61 | justify-content: flex-end; }
62 | div.dataTables_wrapper div.dataTables_paginate ul.pagination .page-item.active .page-link:focus {
63 | background-color: #4285f4; }
64 | div.dataTables_wrapper div.dataTables_paginate ul.pagination .page-item .page-link:focus {
65 | -webkit-box-shadow: none;
66 | box-shadow: none; }
67 |
68 | @media (max-width: 767px) {
69 | div.dataTables_wrapper div .dataTables_length,
70 | div.dataTables_wrapper div .dataTables_filter,
71 | div.dataTables_wrapper div .dataTables_info,
72 | div.dataTables_wrapper div .dataTables_paginate ul.pagination {
73 | text-align: center;
74 | -webkit-box-pack: center;
75 | -webkit-justify-content: center;
76 | -ms-flex-pack: center;
77 | justify-content: center; } }
78 |
79 | .bs-select select {
80 | display: inline-block !important; }
81 |
82 | table.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting,
83 | table.dataTable thead > tr > td.sorting_asc,
84 | table.dataTable thead > tr > td.sorting_desc,
85 | table.dataTable thead > tr > td.sorting {
86 | padding-right: 30px; }
87 |
88 | table.dataTable thead > tr > th:active,
89 | table.dataTable thead > tr > td:active {
90 | outline: none; }
91 |
92 | table.dataTable thead .sorting,
93 | table.dataTable thead .sorting_asc,
94 | table.dataTable thead .sorting_desc,
95 | table.dataTable thead .sorting_asc_disabled,
96 | table.dataTable thead .sorting_desc_disabled {
97 | cursor: pointer;
98 | position: relative; }
99 |
100 | table.dataTable thead .sorting:before, table.dataTable thead .sorting:after,
101 | table.dataTable thead .sorting_asc:before,
102 | table.dataTable thead .sorting_asc:after,
103 | table.dataTable thead .sorting_desc:before,
104 | table.dataTable thead .sorting_desc:after,
105 | table.dataTable thead .sorting_asc_disabled:before,
106 | table.dataTable thead .sorting_asc_disabled:after,
107 | table.dataTable thead .sorting_desc_disabled:before,
108 | table.dataTable thead .sorting_desc_disabled:after {
109 | position: absolute;
110 | bottom: 0.9em;
111 | display: block;
112 | opacity: 0.3; }
113 |
114 | table.dataTable thead .sorting:before,
115 | table.dataTable thead .sorting_asc:before,
116 | table.dataTable thead .sorting_desc:before,
117 | table.dataTable thead .sorting_asc_disabled:before,
118 | table.dataTable thead .sorting_desc_disabled:before {
119 | right: 1em;
120 | content: "\f0de"; }
121 |
122 | table.dataTable thead .sorting:after,
123 | table.dataTable thead .sorting_asc:after,
124 | table.dataTable thead .sorting_desc:after,
125 | table.dataTable thead .sorting_asc_disabled:after,
126 | table.dataTable thead .sorting_desc_disabled:after {
127 | content: "\f0dd";
128 | right: 16px; }
129 |
130 | table.dataTable thead .sorting:before,
131 | table.dataTable thead .sorting_asc:before,
132 | table.dataTable thead .sorting_desc:before,
133 | table.dataTable thead .sorting_asc_disabled:before,
134 | table.dataTable thead .sorting_desc_disabled:before,
135 | table.dataTable thead .sorting:after,
136 | table.dataTable thead .sorting_asc:after,
137 | table.dataTable thead .sorting_desc:after,
138 | table.dataTable thead .sorting_asc_disabled:after,
139 | table.dataTable thead .sorting_desc_disabled:after {
140 | font-family: 'Font Awesome\ 5 Free';
141 | font-weight: 900;
142 | font-size: 1rem; }
143 |
144 | table.dataTable thead .sorting_asc:before,
145 | table.dataTable thead .sorting_desc:after {
146 | opacity: 1; }
147 |
148 | table.dataTable thead .sorting_asc_disabled:before,
149 | table.dataTable thead .sorting_desc_disabled:after {
150 | opacity: 0; }
151 |
--------------------------------------------------------------------------------