├── src ├── scss │ ├── global │ │ ├── _a11y.scss │ │ ├── _boxmodel.scss │ │ ├── _headlines.scss │ │ ├── _settings.scss │ │ └── _fonts.scss │ ├── components │ │ ├── _content.scss │ │ ├── _top-bar.scss │ │ └── _dialog.scss │ ├── objects │ │ ├── _containers.scss │ │ ├── _link.scss │ │ ├── _button.scss │ │ └── _table.scss │ ├── base.scss │ └── utils │ │ └── _a11y.scss ├── views │ ├── About.vue │ ├── ProductListing.vue │ ├── Settings.vue │ └── Orders.vue ├── components │ ├── Logline.vue │ ├── Hint.vue │ ├── Logo.vue │ ├── UserActions.vue │ ├── ShoppingCartButton.vue │ ├── ProgressBar.vue │ ├── Navigation.vue │ ├── accessibleapp │ │ ├── AccessibleAppInfo.vue │ │ └── components │ │ │ └── SwitchButton.vue │ ├── AccountNavigationMenu.vue │ ├── Menu.vue │ ├── ProductTable.vue │ └── ShoppingCartMenu.vue ├── main.js ├── store.js ├── router.js └── App.vue ├── babel.config.js ├── public ├── favicon.ico └── index.html ├── vue.config.js ├── .gitignore ├── README.md └── package.json /src/scss/global/_a11y.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/scss/components/_content.scss: -------------------------------------------------------------------------------- 1 | .c-content { 2 | max-width: $width-max-content; 3 | } -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accessible-app/vuejs/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/scss/global/_boxmodel.scss: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | margin: 0; 4 | box-sizing: border-box; 5 | } -------------------------------------------------------------------------------- /src/scss/objects/_containers.scss: -------------------------------------------------------------------------------- 1 | .o-layout-inner { 2 | max-width: $width-max; 3 | margin: auto; 4 | padding: 0 1rem; 5 | } -------------------------------------------------------------------------------- /src/scss/global/_headlines.scss: -------------------------------------------------------------------------------- 1 | h1, 2 | h2, 3 | h3, 4 | h4, 5 | h5, 6 | h6 { 7 | margin-top: 0; 8 | font-weight: normal; 9 | } -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | lintOnSave: undefined, 3 | 4 | css: { 5 | loaderOptions: { 6 | sass: { 7 | data: '@import "@/scss/global/_settings.scss";' 8 | } 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /src/scss/global/_settings.scss: -------------------------------------------------------------------------------- 1 | // Colors 2 | $color-brand-primary: #2368a2; 3 | $textcolor-brand-primary: #ffffff; 4 | 5 | $brand-white: #ffffff; 6 | 7 | $textcolor-content: #373a3c; 8 | $textcolor-content-link: $color-brand-primary; 9 | 10 | // Dimensions 11 | $width-max: 62.5rem; 12 | $width-max-content: 65rem; 13 | -------------------------------------------------------------------------------- /src/scss/global/_fonts.scss: -------------------------------------------------------------------------------- 1 | html { 2 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif; 3 | font-size: 16px; 4 | -ms-text-size-adjust: 100%; 5 | -webkit-text-size-adjust: 100%; 6 | -moz-osx-font-smoothing: grayscale; 7 | -webkit-font-smoothing: antialiased; 8 | 9 | @media (max-width: 37.5em) { 10 | font-size: 14px; 11 | } 12 | } -------------------------------------------------------------------------------- /src/scss/base.scss: -------------------------------------------------------------------------------- 1 | @import 'global/boxmodel'; 2 | @import 'global/headlines'; 3 | @import 'global/fonts'; 4 | @import 'global/a11y'; 5 | 6 | @import 'objects/containers'; 7 | @import 'objects/link'; 8 | @import 'objects/button'; 9 | @import 'objects/table'; 10 | 11 | @import 'components/top-bar'; 12 | @import 'components/content'; 13 | @import 'components/dialog'; 14 | 15 | @import 'utils/a11y'; 16 | -------------------------------------------------------------------------------- /src/components/Logline.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 21 | -------------------------------------------------------------------------------- /src/scss/objects/_link.scss: -------------------------------------------------------------------------------- 1 | .o-link { 2 | 3 | &, 4 | &:active, 5 | &:visited { 6 | padding-bottom: 2px; 7 | text-decoration: underline; 8 | color: $textcolor-content-link; 9 | font-weight: 700; 10 | } 11 | 12 | &:hover, 13 | &:focus { 14 | color: $textcolor-brand-primary; 15 | box-shadow: inset 0 1.25em 0 0 $textcolor-content-link; 16 | outline: 0; 17 | text-decoration: none; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/components/Hint.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vuejs implentation of accessible-app. 2 | 3 | **[FIND THE DEMO HERE](https://vuejs.accessible-app.com)** 4 | 5 | ## Project setup 6 | ``` 7 | npm install 8 | ``` 9 | 10 | ### Compiles and hot-reloads for development 11 | ``` 12 | npm run serve 13 | ``` 14 | 15 | ### Compiles and minifies for production 16 | ``` 17 | npm run build 18 | ``` 19 | 20 | ### Run your tests 21 | ``` 22 | npm run test 23 | ``` 24 | 25 | ### Lints and fixes files 26 | ``` 27 | npm run lint 28 | ``` 29 | 30 | ### Customize configuration 31 | See [Configuration Reference](https://cli.vuejs.org/config/). 32 | -------------------------------------------------------------------------------- /src/components/Logo.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 31 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | import App from './App.vue'; 4 | 5 | import store from './store'; 6 | import router from './router'; 7 | 8 | import A11yDialog from 'vue-a11y-dialog'; 9 | import PortalVue from 'portal-vue'; 10 | import VueAnnouncer from 'vue-announcer' 11 | 12 | Vue.use(VueAnnouncer); 13 | Vue.use(PortalVue); 14 | Vue.use(A11yDialog); 15 | 16 | Vue.config.productionTip = false; 17 | 18 | Vue.filter('toEUR', function (value) { 19 | return "€ " + (value / 100).toLocaleString("de-DE", {minimumFractionDigits: 2}); 20 | }); 21 | 22 | new Vue({ 23 | store, 24 | router, 25 | render: h => h(App) 26 | }).$mount('#app'); -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Accessibooks - Products 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/views/ProductListing.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 29 | -------------------------------------------------------------------------------- /src/views/Settings.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 33 | -------------------------------------------------------------------------------- /src/components/UserActions.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 28 | 29 | 37 | -------------------------------------------------------------------------------- /src/scss/components/_top-bar.scss: -------------------------------------------------------------------------------- 1 | .c-top-bar { 2 | background-color: $color-brand-primary; 3 | color: $textcolor-brand-primary; 4 | height: 6.75rem; 5 | 6 | @media (max-width: 37.5em) { 7 | height: auto; 8 | } 9 | 10 | &__wrapper { 11 | display: flex; 12 | justify-content: space-between; 13 | align-items: flex-end; 14 | height: inherit; 15 | } 16 | 17 | &__footer { 18 | display: flex; 19 | justify-content: space-between; 20 | align-items: center; 21 | height: 5rem; 22 | margin-bottom: 1rem; 23 | 24 | @media (max-width: 37.5em) { 25 | margin-bottom: 0; 26 | } 27 | } 28 | 29 | &__wrapper, 30 | &__footer { 31 | @media (max-width: 37.5em) { 32 | flex-direction: column; 33 | justify-content: center; 34 | align-items: flex-start; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/scss/utils/_a11y.scss: -------------------------------------------------------------------------------- 1 | .u-visually-hidden { 2 | clip: rect(1px 1px 1px 1px); 3 | clip: rect(1px, 1px, 1px, 1px); 4 | height: 1px; 5 | overflow: hidden; 6 | position: absolute; 7 | white-space: nowrap; 8 | width: 1px; 9 | } 10 | 11 | .u-button-link-look { 12 | border: none; 13 | -webkit-appearance: none; 14 | background: transparent; 15 | padding: 0; 16 | font-size: inherit; 17 | font-family: inherit; 18 | cursor: pointer; 19 | 20 | &:focus { 21 | outline: 0; 22 | } 23 | } 24 | 25 | [tabindex="-1"]:focus { 26 | outline: none; 27 | } 28 | 29 | @media (prefers-reduced-motion: reduce) { 30 | 31 | * { 32 | animation: none !important; 33 | -webkit-animation: none !important; 34 | } 35 | } 36 | 37 | .user-prefers-reduced-motion-reduce { 38 | 39 | * { 40 | animation: none !important; 41 | -webkit-animation: none !important; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/components/ShoppingCartButton.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 35 | -------------------------------------------------------------------------------- /src/components/ProgressBar.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 38 | 39 | 44 | -------------------------------------------------------------------------------- /src/scss/objects/_button.scss: -------------------------------------------------------------------------------- 1 | .o-button, 2 | [data-vue-details-summmary], 3 | [data-vue-menu-button] { 4 | -webkit-appearance: none; 5 | background: transparent; 6 | font-size: inherit; 7 | font-family: inherit; 8 | border-radius: 4px; 9 | padding: .5rem .75rem; 10 | border: 1px solid $color-brand-primary; 11 | color: $color-brand-primary; 12 | opacity: 1; 13 | transition: opacity .2s; 14 | 15 | &[disabled] { 16 | opacity: .33; 17 | } 18 | 19 | &:not([disabled]):hover, 20 | &:not([disabled]):focus { 21 | color: $textcolor-brand-primary; 22 | background-color: $color-brand-primary; 23 | outline: 0; 24 | } 25 | 26 | & + & { 27 | margin-left: 1rem; 28 | } 29 | } 30 | 31 | .o-button--secondary { 32 | font-size: .75rem; 33 | padding: .33rem; 34 | min-width: 9rem; 35 | margin-right: 1rem; 36 | margin-bottom: .5rem; 37 | 38 | & + & { 39 | margin: 0 .5rem 0 0; 40 | } 41 | } 42 | 43 | .o-button--bare { 44 | padding: .25rem .5rem; 45 | color: $color-brand-primary; 46 | display: inline-flex; 47 | 48 | &:focus, 49 | &:hover { 50 | color: #ffffff; 51 | } 52 | } 53 | 54 | -------------------------------------------------------------------------------- /src/scss/objects/_table.scss: -------------------------------------------------------------------------------- 1 | .o-table { 2 | overflow-y: auto; 3 | width: 100%; 4 | background-image: linear-gradient(to right, white, white), linear-gradient(to right, white, white), linear-gradient(to right, rgba(0, 0, 20, .25), rgba(255, 255, 255, 0)), linear-gradient(to left, rgba(0, 0, 20, .25), rgba(255, 255, 255, 0)); 5 | background-position: left center, right center, left center, right center; 6 | background-repeat: no-repeat; 7 | background-color: white; 8 | background-size: 25px 100%, 25px 100%, 12px 100%, 12px 100%; 9 | background-attachment: local, local, scroll, scroll; 10 | 11 | &__table { 12 | border: 2px solid rgba(235, 235, 235, 0.99); 13 | border-collapse: collapse; 14 | width: 100%; 15 | } 16 | 17 | &::-webkit-scrollbar { 18 | -webkit-appearance: none; 19 | width: 14px; 20 | height: 14px; 21 | } 22 | 23 | &::-webkit-scrollbar-thumb { 24 | border-radius: 8px; 25 | border: 3px solid #fff; 26 | background-color: rgba(0, 0, 0, .3); 27 | } 28 | 29 | &__cell--data, 30 | &__cell--header { 31 | text-align: left; 32 | padding: .75rem; 33 | } 34 | 35 | &__cell--price { 36 | text-align: right; 37 | } 38 | 39 | &__cell--header { 40 | padding-right: 2rem; 41 | background-color: rgba(235, 235, 235, 0.99); 42 | } 43 | } -------------------------------------------------------------------------------- /src/store.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex from "vuex"; 3 | 4 | Vue.use(Vuex); 5 | 6 | const store = new Vuex.Store({ 7 | state: { 8 | enhancedFocus: false, 9 | reducedMotion: false, 10 | shoppingCartItems: [] 11 | }, 12 | mutations: { 13 | toggleEnhancedFocus(state) { 14 | state.enhancedFocus = !state.enhancedFocus; 15 | }, 16 | toggleReducedMotion(state) { 17 | state.reducedMotion = !state.reducedMotion; 18 | }, 19 | toggleShoppingCartState(state, product) { 20 | if (state.shoppingCartItems.includes(product)) { 21 | // Remove from shopping cart 22 | state.shoppingCartItems = state.shoppingCartItems.filter( 23 | item => item !== product 24 | ); 25 | } else { 26 | // Add to shopping cart 27 | state.shoppingCartItems.push(product); 28 | } 29 | }, 30 | removeAllShoppingCartItems(state) { 31 | state.shoppingCartItems = []; 32 | } 33 | }, 34 | getters: { 35 | getEnhancedFocus: state => { 36 | return state.enhancedFocus; 37 | }, 38 | getReducedMotion: state => { 39 | return state.reducedMotion; 40 | }, 41 | getProductIsInShoppingCart: (state) => (product) => { 42 | return state.shoppingCartItems.includes(product); 43 | }, 44 | shoppingCartItems: state => { 45 | return state.shoppingCartItems; 46 | } 47 | } 48 | }); 49 | 50 | export default store; 51 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vue-cli-service serve", 7 | "serve": "vue-cli-service serve", 8 | "build": "vue-cli-service build", 9 | "lint": "vue-cli-service lint" 10 | }, 11 | "dependencies": { 12 | "details-element-polyfill": "^2.3.0", 13 | "portal-vue": "^1.5.0", 14 | "vue": "^2.5.17", 15 | "vue-a11y-dialog": "^0.3.1", 16 | "vue-announcer": "^1.0.4", 17 | "vue-router": "^3.0.1", 18 | "vuex": "^3.0.1" 19 | }, 20 | "devDependencies": { 21 | "@vue/cli-plugin-babel": "^3.2.0", 22 | "@vue/cli-plugin-eslint": "^3.2.0", 23 | "@vue/cli-service": "^4.1.2", 24 | "babel-eslint": "^10.0.1", 25 | "eslint": "^5.8.0", 26 | "eslint-plugin-vue": "^5.0.0-0", 27 | "node-sass": "^4.11.0", 28 | "sass-loader": "^7.1.0", 29 | "vue-cli-plugin-scss-base": "^0.1.10", 30 | "vue-template-compiler": "^2.5.17" 31 | }, 32 | "eslintConfig": { 33 | "root": true, 34 | "env": { 35 | "node": true 36 | }, 37 | "extends": [ 38 | "plugin:vue/essential", 39 | "eslint:recommended" 40 | ], 41 | "parserOptions": { 42 | "parser": "babel-eslint" 43 | } 44 | }, 45 | "postcss": { 46 | "plugins": { 47 | "autoprefixer": {} 48 | } 49 | }, 50 | "browserslist": [ 51 | "> 1%", 52 | "last 2 versions", 53 | "not ie <= 8" 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /src/components/Navigation.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | 17 | 64 | -------------------------------------------------------------------------------- /src/components/accessibleapp/AccessibleAppInfo.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 28 | 29 | 60 | -------------------------------------------------------------------------------- /src/components/AccountNavigationMenu.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 32 | 33 | 74 | -------------------------------------------------------------------------------- /src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Router from "vue-router"; 3 | import ProductListing from "./views/ProductListing.vue"; 4 | 5 | Vue.use(Router); 6 | 7 | export default new Router({ 8 | routes: [ 9 | { 10 | path: "/", 11 | name: "home", 12 | component: ProductListing, 13 | meta: { title: "Accessibooks - Products" } 14 | }, 15 | { 16 | path: "/about", 17 | name: "about", 18 | // route level code-splitting 19 | // this generates a separate chunk (about.[hash].js) for this route 20 | // which is lazy-loaded when the route is visited. 21 | component: () => 22 | import(/* webpackChunkName: "about" */ "./views/About.vue"), 23 | meta: { title: "Accessibooks - About us" } 24 | }, 25 | { 26 | path: "/settings", 27 | name: "settings", 28 | // route level code-splitting 29 | // this generates a separate chunk (about.[hash].js) for this route 30 | // which is lazy-loaded when the route is visited. 31 | component: () => 32 | import(/* webpackChunkName: "about" */ "./views/Settings.vue"), 33 | meta: { title: "Accessibooks - My Settings" } 34 | }, 35 | { 36 | path: "/orders", 37 | name: "orders", 38 | // route level code-splitting 39 | // this generates a separate chunk (about.[hash].js) for this route 40 | // which is lazy-loaded when the route is visited. 41 | component: () => 42 | import(/* webpackChunkName: "about" */ "./views/Orders.vue"), 43 | meta: { title: "Accessibooks - My past orders" } 44 | } 45 | ] 46 | }); 47 | -------------------------------------------------------------------------------- /src/components/accessibleapp/components/SwitchButton.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 50 | 51 | 74 | -------------------------------------------------------------------------------- /src/views/Orders.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 85 | -------------------------------------------------------------------------------- /src/components/Menu.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 69 | 70 | 135 | -------------------------------------------------------------------------------- /src/scss/components/_dialog.scss: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------- *\ 2 | * Necessary styling for the dialog to work 3 | * -------------------------------------------------------------------------- */ 4 | 5 | /** 6 | * When `` is properly supported, the overlay is implied and can be 7 | * styled with `::backdrop`, which means the DOM one should be removed. 8 | */ 9 | [data-a11y-dialog-native] .dialog-overlay { 10 | display: none; 11 | } 12 | 13 | /** 14 | * When `` is not supported, its default display is `inline` which can 15 | * cause layout issues. 16 | */ 17 | dialog[open] { 18 | display: block; 19 | } 20 | 21 | .dialog[aria-hidden="true"] { 22 | display: none; 23 | } 24 | 25 | /* -------------------------------------------------------------------------- *\ 26 | * Styling to make the dialog look like a dialog 27 | * -------------------------------------------------------------------------- */ 28 | 29 | .dialog-overlay { 30 | z-index: 2; 31 | background-color: rgba(0, 0, 0, 0.66); 32 | position: fixed; 33 | top: 0; 34 | left: 0; 35 | bottom: 0; 36 | right: 0; 37 | } 38 | 39 | dialog::backdrop { 40 | background-color: rgba(0, 0, 0, 0.66); 41 | } 42 | 43 | .dialog-content { 44 | background-color: rgb(255, 255, 255); 45 | z-index: 3; 46 | position: fixed; 47 | top: 50%; 48 | left: 50%; 49 | -webkit-transform: translate(-50%, -50%); 50 | -ms-transform: translate(-50%, -50%); 51 | transform: translate(-50%, -50%); 52 | margin: 0; 53 | } 54 | 55 | /* -------------------------------------------------------------------------- *\ 56 | * Extra dialog styling to make it shiny 57 | * -------------------------------------------------------------------------- */ 58 | 59 | @keyframes fade-in { 60 | from { opacity: 0; } 61 | to { opacity: 1; } 62 | } 63 | 64 | @keyframes appear { 65 | from { transform: translate(-50%, -40%); opacity: 0; } 66 | to { transform: translate(-50%, -50%); opacity: 1; } 67 | } 68 | 69 | .dialog:not([aria-hidden='true']) > .dialog-overlay { 70 | animation: fade-in 200ms 1 both; 71 | } 72 | 73 | .dialog:not([aria-hidden='true']) > .dialog-content { 74 | animation: appear 400ms 150ms 1 both; 75 | } 76 | 77 | .dialog-content { 78 | padding: 1em; 79 | max-width: 90%; 80 | width: 600px; 81 | border-radius: 2px; 82 | } 83 | 84 | 85 | @media screen and (min-width: 700px) { 86 | .dialog-content { 87 | padding: 2em; 88 | } 89 | } 90 | 91 | .dialog-overlay { 92 | background-color: rgba(43, 46, 56, 0.9); 93 | } 94 | 95 | .dialog h1 { 96 | margin: 0 0 1rem; 97 | font-size: 1.25em; 98 | } 99 | 100 | .dialog-close { 101 | position: absolute; 102 | top: 0.5em; 103 | right: 0.5em; 104 | border: 0; 105 | padding: 0; 106 | background-color: transparent; 107 | font-weight: bold; 108 | font-size: 1.25em; 109 | width: 1.2em; 110 | height: 1.2em; 111 | text-align: center; 112 | cursor: pointer; 113 | transition: 0.15s; 114 | 115 | &:focus { 116 | outline: 1px dashed #2368a2; 117 | line-height: 0; 118 | padding: 0; 119 | } 120 | } 121 | 122 | @media screen and (min-width: 700px) { 123 | .dialog-close { 124 | top: 1em; 125 | right: 1em; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 107 | 108 | 111 | -------------------------------------------------------------------------------- /src/components/ProductTable.vue: -------------------------------------------------------------------------------- 1 | 63 | 64 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /src/components/ShoppingCartMenu.vue: -------------------------------------------------------------------------------- 1 | 68 | 69 | 115 | 116 | 175 | --------------------------------------------------------------------------------