├── .config
├── .browserslistrc
├── .eslintrc.js
├── .stylelintrc.js
├── postcss.config.js
└── webpack
│ ├── webpack.common.js
│ ├── webpack.dev.js
│ └── webpack.prod.js
├── .github
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE
│ ├── bug-report.yml
│ └── config.yml
├── PULL_REQUEST_TEMPLATE.md
└── img
│ ├── banner.svg
│ └── logo.svg
├── .gitignore
├── LICENSE
├── README.md
├── jsconfig.json
├── package.json
├── shopify
├── .theme-check.yml
├── README.md
├── assets
│ └── file.static.md
├── config
│ ├── settings_data.json
│ └── settings_schema.json
├── layout
│ └── theme.liquid
├── locales
│ ├── en.default.json
│ └── en.default.schema.json
├── sections
│ ├── footer.liquid
│ ├── header.liquid
│ ├── main-404.liquid
│ ├── main-article.liquid
│ ├── main-blog.liquid
│ ├── main-cart.liquid
│ ├── main-collection.liquid
│ ├── main-index.liquid
│ ├── main-list-collections.liquid
│ ├── main-page-contact.liquid
│ ├── main-page.liquid
│ ├── main-password.liquid
│ ├── main-product.liquid
│ ├── main-search.liquid
│ └── vue-examples.liquid
├── snippets
│ └── layout-menu.liquid
└── templates
│ ├── 404.json
│ ├── article.json
│ ├── blog.json
│ ├── cart.json
│ ├── collection.json
│ ├── customers
│ ├── account.liquid
│ ├── activate_account.liquid
│ ├── addresses.liquid
│ ├── login.liquid
│ ├── order.liquid
│ ├── register.liquid
│ └── reset_password.liquid
│ ├── gift_card.liquid
│ ├── index.json
│ ├── list-collections.json
│ ├── page.contact.json
│ ├── page.json
│ ├── password.json
│ ├── product.json
│ └── search.json
└── src
├── css
└── main.css
├── main.js
├── tailwind.config.js
└── vue
├── components
├── render
│ └── my-component.vue
└── renderless
│ └── my-component.vue
├── directives
└── global.directive.js
├── mixins
└── global.mixin.js
└── store
└── my-module.js
/.config/.browserslistrc:
--------------------------------------------------------------------------------
1 | # docs: https://www.npmjs.com/package/browserslist
2 | # run '$ npx browserslist' in .config/ directory to see wich browsers are selected by your queries for [production].
3 |
4 | [development]
5 | last 2 chrome versions
6 | last 2 firefox versions
7 |
8 | [production]
9 | last 4 versions
10 | not IE <= 11
--------------------------------------------------------------------------------
/.config/.eslintrc.js:
--------------------------------------------------------------------------------
1 | const isDevelopment = process.env.NODE_ENV === 'development'
2 |
3 | module.exports = {
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:vue/vue3-recommended' // use 'plugin:vue/vue3-essential' for less strict linting rules - https://eslint.vuejs.org/rules
7 | ],
8 | plugins: [
9 | 'vue'
10 | ],
11 | parserOptions: {
12 | ecmaVersion: 2021,
13 | sourceType: 'module'
14 | },
15 | env: {
16 | node: true,
17 | commonjs: true,
18 | browser: true,
19 | es6: true
20 | },
21 | globals: {
22 | Shopify: 'readonly'
23 | },
24 | ignorePatterns: [
25 | /**
26 | * ignore certain files
27 | * docs: https://eslint.org/docs/user-guide/configuring#ignorepatterns-in-config-files
28 | */
29 | // 'my-file.js',
30 | // '**/my-directory/*.js'
31 | ],
32 | rules: {
33 | /**
34 | * add custom rules
35 | * docs: https://eslint.org/docs/rules
36 | */
37 | 'no-unused-vars': isDevelopment ? 'off' : 'error',
38 | // 'quotes': ['error', 'single'],
39 | // 'semi': ['error', 'never']
40 | }
41 | }
--------------------------------------------------------------------------------
/.config/.stylelintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: 'stylelint-config-recommended',
3 | plugins: [
4 | /**
5 | * add plugins
6 | * docs: https://stylelint.io/user-guide/configure#plugins
7 | */
8 | // 'stylelint-scss' // stylelint by itself supports SCSS syntax very well
9 | ],
10 | ignoreFiles: [
11 | /**
12 | * ignore certain files
13 | * docs: https://stylelint.io/user-guide/configure#ignorefiles
14 | */
15 | // 'my-file.css',
16 | // '**/my-directory/*.css'
17 | ],
18 | rules: {
19 | /**
20 | * add custom rules
21 | * docs: https://stylelint.io/user-guide/rules/list
22 | */
23 | 'at-rule-no-unknown': null,
24 | 'no-descending-specificity': null
25 | },
26 | customSyntax: 'postcss-html'
27 | }
--------------------------------------------------------------------------------
/.config/postcss.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | module.exports = {
4 | plugins: [
5 | require('postcss-import'),
6 | require('tailwindcss/nesting'),
7 | require('tailwindcss')(path.resolve(__dirname, '../src/tailwind.config.js')),
8 | require('autoprefixer')
9 | ]
10 | }
--------------------------------------------------------------------------------
/.config/webpack/webpack.common.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const webpack = require('webpack')
3 | const { CleanWebpackPlugin } = require('clean-webpack-plugin')
4 | const MiniCssExtractPlugin = require('mini-css-extract-plugin')
5 | const { VueLoaderPlugin } = require('vue-loader')
6 |
7 | module.exports = {
8 | stats: 'minimal',
9 | entry: path.resolve(__dirname, '../../src/main.js'),
10 | output: {
11 | path: path.resolve(__dirname, '../../shopify/assets/'),
12 | filename: 'bundle.js'
13 | },
14 | resolve: {
15 | extensions: ['*', '.js', '.vue', '.json'],
16 | alias: {
17 | 'vue$': 'vue/dist/vue.esm-bundler.js',
18 | '@': path.resolve(__dirname, '../../src/'),
19 | '@shopify-directory': path.resolve(__dirname, '../../shopify/')
20 | }
21 | },
22 | module: {
23 | rules: [
24 | {
25 | test: /\.vue$/,
26 | loader: 'vue-loader'
27 | },
28 | {
29 | test: /\.(png|svg|jpg|gif)$/,
30 | use: [
31 | {
32 | loader: 'url-loader',
33 | options: {
34 | limit: 8192
35 | }
36 | }
37 | ]
38 | },
39 | ... (() => {
40 | const rules = []
41 |
42 | const loaders = [
43 | { test: /\.(css|postcss)$/i },
44 | { test: /\.s[ac]ss$/i, loader: 'sass-loader' },
45 | { test: /\.less$/i, loader: 'less-loader' },
46 | { test: /\.styl$/i, loader: 'stylus-loader' }
47 | ]
48 |
49 | loaders.forEach((element, index) => {
50 | rules.push({
51 | test: element.test,
52 | use: [
53 | MiniCssExtractPlugin.loader,
54 | 'css-loader',
55 | {
56 | loader: 'postcss-loader',
57 | options: {
58 | postcssOptions: require(path.resolve(__dirname, '../postcss.config.js'))
59 | }
60 | }
61 | ]
62 | })
63 |
64 | if (element.loader) rules[index].use.push(element.loader)
65 | })
66 |
67 | return rules
68 | })()
69 | ]
70 | },
71 | plugins: [
72 | /**
73 | * don't clean files with the 'static' keyword in their filename
74 | * docs: https://github.com/johnagan/clean-webpack-plugin
75 | */
76 | new CleanWebpackPlugin({
77 | cleanOnceBeforeBuildPatterns: ['**/*', '!*static*']
78 | }),
79 | /**
80 | * docs: https://webpack.js.org/plugins/mini-css-extract-plugin
81 | */
82 | new MiniCssExtractPlugin({
83 | filename: './bundle.css',
84 | chunkFilename: '[id].css'
85 | }),
86 | new VueLoaderPlugin(),
87 | new webpack.DefinePlugin({
88 | __VUE_OPTIONS_API__: 'true',
89 | __VUE_PROD_DEVTOOLS__: 'false'
90 | })
91 | ]
92 | }
--------------------------------------------------------------------------------
/.config/webpack/webpack.dev.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const { merge } = require('webpack-merge')
3 | const ESLintPlugin = require('eslint-webpack-plugin')
4 | const StylelintPlugin = require('stylelint-webpack-plugin')
5 | const common = require('./webpack.common.js')
6 |
7 | module.exports = merge(common, {
8 | mode: 'development',
9 | plugins: [
10 | /**
11 | * docs: https://www.npmjs.com/package/eslint-webpack-plugin
12 | */
13 | new ESLintPlugin({
14 | files: 'src/**/*.{js,vue}',
15 | overrideConfigFile: path.resolve(__dirname, '../.eslintrc.js')
16 | }),
17 | /**
18 | * docs: https://www.npmjs.com/package/stylelint-webpack-plugin
19 | */
20 | new StylelintPlugin({
21 | files: 'src/**/*.{vue,css,sass,scss}',
22 | configFile: path.resolve(__dirname, '../.stylelintrc.js')
23 | })
24 | ]
25 | })
--------------------------------------------------------------------------------
/.config/webpack/webpack.prod.js:
--------------------------------------------------------------------------------
1 | const { merge } = require('webpack-merge')
2 | const TerserPlugin = require('terser-webpack-plugin') // included in webpack 5, no need to add to package.json
3 | const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
4 | const common = require('./webpack.common.js')
5 |
6 | module.exports = merge(common, {
7 | mode: 'production',
8 | performance: {
9 | hints: false
10 | },
11 | module: {
12 | rules: [
13 | {
14 | test: /\.js$/,
15 | loader: 'babel-loader',
16 | exclude: /node_modules/,
17 | options: {
18 | presets: [ '@babel/preset-env' ],
19 | plugins: [ '@babel/plugin-transform-runtime' ]
20 | }
21 | }
22 | ]
23 | },
24 | optimization: {
25 | minimize: true,
26 | minimizer: [
27 | /**
28 | * docs: https://webpack.js.org/plugins/terser-webpack-plugin
29 | */
30 | new TerserPlugin({
31 | terserOptions: {
32 | format: {
33 | comments: /@license/i // preserve license comments
34 | }
35 | },
36 | extractComments: false
37 | }),
38 | /**
39 | * docs: https://webpack.js.org/plugins/css-minimizer-webpack-plugin
40 | */
41 | new CssMinimizerPlugin()
42 | ]
43 | }
44 | })
--------------------------------------------------------------------------------
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | contact@sergej.codes.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | [https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
120 |
121 | Community Impact Guidelines were inspired by
122 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
123 |
124 | For answers to common questions about this code of conduct, see the FAQ at
125 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available
126 | at [https://www.contributor-covenant.org/translations][translations].
127 |
128 | [homepage]: https://www.contributor-covenant.org
129 | [v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
130 | [Mozilla CoC]: https://github.com/mozilla/diversity
131 | [FAQ]: https://www.contributor-covenant.org/faq
132 | [translations]: https://www.contributor-covenant.org/translations
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing guide
2 | Please take a moment to read this document in order to make the contribution process easy and effective for everyone.
3 |
4 | ### Project goals
5 | > **Shopify Theme Lab** was built to provide a great developer experience while crafting Shopify themes.
6 |
7 | #### This project aims to be:
8 | - **Modular** - It should be effortless to alter, add, remove or swap any component.
9 | - **Fast** - Automating tedious processes as much as possible.
10 | - **Intuitive** - This project as a whole, file contents and directory structure should be quick to grasp and easy to work with.
11 | - **Modern** - Gone are the days of jQuery.
12 |
13 | Please keep the above points in mind when submitting issues or adding new features.
14 |
15 | ### Bug reports
16 | A good bug report should be easy to understand and as detailed as possible. Explanations on how to reproduce the problem and/or screenshots are a great help.
17 |
18 | ### Feature requests
19 | Before submitting a feature request try to find out whether your idea fits with the scope and aims of the project. Provide as much detail and context as possible.
20 |
21 | ### Pull requests
22 | Good pull requests - patches, improvements, new features - are a great help. They should remain focused in scope and avoid containing unrelated commits.
23 |
24 | **Please ask first** before starting any significant pull request (e.g. implementing new features, refactoring code), otherwise you risk spending a lot of time working on something that might not be merged into the project.
25 |
26 | Also follow to the coding conventions used throughout the project (indentation, comments, etc.).
27 |
28 | > All pull requests should be submitted to the `dev` branch, **not** the `master` branch.
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: File a bug report
3 | title: "[Bug]: YOUR TITLE HERE"
4 | labels: [bug]
5 | body:
6 | -
7 | type: markdown
8 | attributes:
9 | value: "## Setup"
10 | -
11 | type: input
12 | attributes:
13 | label: Operating system
14 | description: Which operating system/version are you using?
15 | placeholder: Windows 10
16 | validations:
17 | required: true
18 | -
19 | type: input
20 | attributes:
21 | label: Node.js version
22 | description: Which Node.js version are you using?
23 | placeholder: 14.0.0
24 | validations:
25 | required: true
26 | -
27 | type: input
28 | attributes:
29 | label: Shopify CLI version
30 | description: Which Shopify CLI version are you using?
31 | placeholder: 2.0.0
32 | validations:
33 | required: true
34 | -
35 | type: dropdown
36 | id: browsers
37 | attributes:
38 | label: Browsers
39 | description: Which browsers are you seeing the problem on?
40 | multiple: true
41 | options:
42 | - Chrome
43 | - Firefox
44 | - Safari
45 | - Microsoft Edge
46 | -
47 | type: markdown
48 | attributes:
49 | value: "## Software"
50 | -
51 | type: dropdown
52 | id: version
53 | attributes:
54 | label: Version
55 | description: Which version of our software are you running?
56 | options:
57 | - 4 (Current)
58 | - 3 (Legacy)
59 | validations:
60 | required: true
61 | -
62 | type: textarea
63 | id: modifications
64 | attributes:
65 | label: Modifications
66 | description: Did you modify our software? If yes, please describe how you altered it from the base state.
67 | placeholder: |
68 | I added framework X.
69 | I removed component Y.
70 | -
71 | type: textarea
72 | id: details
73 | attributes:
74 | label: Details
75 | description: Tell us what happened and the steps to reproduce the issue. Have you tried anything to solve the issue yourself? Images and videos can be a great help!
76 | placeholder: |
77 | 1. I installed the software
78 | 2. I ran command X
79 | 3. An error occurred
80 | Solution Y from Z didn't help.
81 | validations:
82 | required: true
83 | -
84 | type: checkboxes
85 | id: notice
86 | attributes:
87 | label: Notice
88 | description: |
89 | A detailed bug report helps tremendously in tracking down and fixing possible issues. We aren't going to waste time chasing you after missing information. If you provided insufficient details, your bug report might get closed without any assistance.
90 | options:
91 | - label: I read the notice
92 | required: true
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | **What kind of change does this PR introduce?** (check at least one)
5 | - [ ] Bugfix
6 | - [ ] Feature
7 | - [ ] Code style update
8 | - [ ] Refactor
9 | - [ ] Other, please describe:
10 |
11 | **Does this PR introduce a breaking change?** (check one)
12 | - [ ] Yes
13 | - [ ] No
14 |
15 | If yes, please describe the impact and migration path for existing applications:
16 |
17 | **The PR fulfills these requirements:**
18 | - [ ] It's submitted to the `dev` branch, _not_ the `main` branch
19 |
20 | If adding a **new feature**, the PR's description includes:
21 | - [ ] A convincing reason for adding this feature (to avoid wasting your time, it's best to open a suggestion issue first and wait for approval before working on it)
22 |
23 | **Other information:**
--------------------------------------------------------------------------------
/.github/img/banner.svg:
--------------------------------------------------------------------------------
1 |
47 |
--------------------------------------------------------------------------------
/.github/img/logo.svg:
--------------------------------------------------------------------------------
1 |
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .DS_Store
3 | *.log
4 |
5 | # ignore all files inside shopify/assets/ except files with 'static' keyword in their filename
6 | shopify/assets/*
7 | !shopify/assets/*static*
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2020-present, Sergej Samsonenko
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | Shopify Theme Lab
21 |
22 | Shopify Theme Lab is a customizable modular development environment for blazing-fast Shopify theme creation. It is built on top of the [Shopify CLI](https://shopify.dev/themes/tools/cli) and extends it with additional workflow and building capabilities. By default, it's bundled with Vue.js and Tailwind CSS, but you can swap them for pretty much anything. Build a custom Shopify theme from scratch with a modern stack!
23 |
24 | > If you are looking for the old Theme Lab it's here: [Legacy Version 3 branch](https://github.com/uicrooks/shopify-theme-lab/tree/legacy-v3)
25 |
26 |
27 |
28 | ## Docs
29 |
30 | 👉 You can find the documentation [here](https://uicrooks.github.io/shopify-theme-lab-docs)
31 |
32 |
33 |
34 | ## Ecosystem
35 | | Project | Status | Description |
36 | | - | - | - |
37 | | [Shopify Theme Lab](https://github.com/uicrooks/shopify-theme-lab) |
| Modular development environment for blazing-fast Shopify theming |
38 | | [Shopify Foundation Theme](https://github.com/uicrooks/shopify-foundation-theme) |
| A modern Shopify starter theme built with Vue and Tailwind CSS |
39 | | [Shopify Theme Lab Plugins](https://github.com/uicrooks/shopify-theme-lab-plugins) |
| Official Shopify Theme Lab plugins |
40 |
41 |
42 |
43 | ## Contributing
44 |
45 | Everyone is welcome to make Shopify theme development better! Please read the [Contributing guide](.github/CONTRIBUTING.md) before creating issues or submitting pull requests.
46 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "paths": {
5 | "@/*": ["./src/*"],
6 | "@shopify-directory/*": ["./shopify/*"]
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "shopify-theme-lab",
3 | "description": "Customizable modular development environment for blazing-fast Shopify theme creation",
4 | "author": "Sergej Samsonenko",
5 | "version": "4.4.1",
6 | "license": "MIT",
7 | "scripts": {
8 | "start": "run-p -sr shopify:serve webpack:watch",
9 | "deploy": "run-s webpack:build && cd shopify && shopify theme push",
10 | "deploy:new": "run-s webpack:build && cd shopify && shopify theme push --unpublished",
11 | "webpack:watch": "cross-env NODE_ENV=development BROWSERSLIST_ENV=development BROWSERSLIST_CONFIG=.config/.browserslistrc webpack --config .config/webpack/webpack.dev.js --watch --progress",
12 | "webpack:build": "cross-env NODE_ENV=production BROWSERSLIST_ENV=production BROWSERSLIST_CONFIG=.config/.browserslistrc webpack --config .config/webpack/webpack.prod.js --progress",
13 | "shopify:serve": "cd shopify && shopify theme serve",
14 | "shopify:pull": "cd shopify && shopify theme pull",
15 | "lint": "run-s -c lint:*",
16 | "lint:js": "eslint src/**/*.{js,vue} --config .config/.eslintrc.js",
17 | "lint:css": "stylelint src/**/*.{vue,css,sass,scss} --config .config/.stylelintrc.js",
18 | "lint:shopify": "cd shopify && shopify theme check",
19 | "fix": "run-s -c fix:*",
20 | "fix:js": "eslint src/**/*.{js,vue} --config .config/.eslintrc.js --fix",
21 | "fix:css": "stylelint src/**/*.{vue,css,sass,scss} --config .config/.stylelintrc.js --fix",
22 | "fix:shopify": "cd shopify && shopify theme check -a"
23 | },
24 | "dependencies": {
25 | "tailwindcss": "^3.0.2",
26 | "vue": "^3.2.26",
27 | "vuex": "^4.0.2"
28 | },
29 | "devDependencies": {
30 | "@babel/core": "^7.16.0",
31 | "@babel/plugin-transform-runtime": "^7.16.4",
32 | "@babel/preset-env": "^7.16.4",
33 | "@vue/compiler-sfc": "^3.2.26",
34 | "autoprefixer": "^10.4.0",
35 | "babel-loader": "^8.2.3",
36 | "clean-webpack-plugin": "^4.0.0",
37 | "cross-env": "^7.0.3",
38 | "css-loader": "^6.5.1",
39 | "css-minimizer-webpack-plugin": "^3.2.0",
40 | "eslint": "^8.4.1",
41 | "eslint-plugin-vue": "^8.2.0",
42 | "eslint-webpack-plugin": "^3.1.1",
43 | "mini-css-extract-plugin": "^2.4.5",
44 | "npm-run-all": "^4.1.5",
45 | "postcss": "^8.4.5",
46 | "postcss-html": "^1.3.0",
47 | "postcss-import": "^14.0.2",
48 | "postcss-loader": "^6.2.1",
49 | "stylelint": "^14.1.0",
50 | "stylelint-config-recommended": "^6.0.0",
51 | "stylelint-webpack-plugin": "^3.1.0",
52 | "url-loader": "^4.1.1",
53 | "vue-loader": "^16.8.3",
54 | "webpack": "^5.65.0",
55 | "webpack-cli": "^4.9.1",
56 | "webpack-merge": "^5.8.0"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/shopify/.theme-check.yml:
--------------------------------------------------------------------------------
1 | MatchingTranslations:
2 | enabled: false
3 |
--------------------------------------------------------------------------------
/shopify/README.md:
--------------------------------------------------------------------------------
1 | ## Shopify
2 | Shopify theme structure and a minimal theme setup. For detailed templates and code examples have a look at the **Shopify Theme Lab** [Foundation Theme](https://github.com/uicrooks/shopify-foundation-theme), or the official [Shopify Dawn Theme](https://github.com/Shopify/dawn).
3 |
4 | ## Links
5 | - [Shopify Theme Docs](https://shopify.dev/themes)
6 | - [Shopify Cheat Sheet](https://www.shopify.com/partners/shopify-cheat-sheet)
--------------------------------------------------------------------------------
/shopify/assets/file.static.md:
--------------------------------------------------------------------------------
1 | ## Static files
2 |
3 | Add the `static` keyword to the filename of any file you place manually in this directory.
--------------------------------------------------------------------------------
/shopify/config/settings_data.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/shopify/config/settings_schema.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "theme_info",
4 | "theme_name": "Shopify Theme Lab",
5 | "theme_version": "1.0.0",
6 | "theme_author": "THEME_AUTHOR",
7 | "theme_documentation_url": "https://THEME_DOCUMENTATION_URL.com",
8 | "theme_support_url": "https://THEME_SUPPORT_URL.com"
9 | },
10 | {
11 | "name": "t:settings_schema.custom_settings.name",
12 | "settings": [
13 | {
14 | "type": "header",
15 | "content": "t:settings_schema.custom_settings.settings.header"
16 | },
17 | {
18 | "type": "paragraph",
19 | "content": "t:settings_schema.custom_settings.settings.paragraph"
20 | }
21 | ]
22 | },
23 | {
24 | "name": "t:settings_schema.favicon.name",
25 | "settings": [
26 | {
27 | "type": "image_picker",
28 | "id": "favicon",
29 | "label": "t:settings_schema.favicon.settings.label",
30 | "info": "t:settings_schema.favicon.settings.info"
31 | }
32 | ]
33 | }
34 | ]
--------------------------------------------------------------------------------
/shopify/layout/theme.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | {% if settings.favicon %}
13 |
14 | {% endif %}
15 |
16 | {{ page_title | escape }}
17 |
18 | {% if page_description %}
19 |
20 | {% endif %}
21 |
22 | {{ 'bundle.css' | asset_url | stylesheet_tag }}
23 |
24 |
25 | {{ content_for_header }}
26 |
27 |
28 |
29 |
30 | {% section 'header' %}
31 |
32 |
33 | {{ content_for_layout }}
34 |
35 |
36 | {% section 'footer' %}
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/shopify/locales/en.default.json:
--------------------------------------------------------------------------------
1 | {
2 | "action": {
3 | "log_in": "Log in",
4 | "log_out": "Log out",
5 | "register": "Register",
6 | "account": "Account",
7 | "cart": "Cart"
8 | },
9 | "404": {
10 | "title": "404 Page Not Found",
11 | "text": "The page you requested does not exist."
12 | }
13 | }
--------------------------------------------------------------------------------
/shopify/locales/en.default.schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "settings_schema": {
3 | "custom_settings": {
4 | "name": "Custom settings",
5 | "settings": {
6 | "header": "About JSON settings",
7 | "paragraph": "The settings_schema.json file controls the content of the Theme settings area of the theme editor. Settings in this file translate to global theme settings, which can be accessed through the Liquid settings object. [Learn more](https://shopify.dev/themes/architecture/settings)"
8 | }
9 | },
10 | "favicon": {
11 | "name": "Favicon",
12 | "settings": {
13 | "label": "Image",
14 | "info": "32 x 32px .png recommended"
15 | }
16 | }
17 | },
18 | "sections": {
19 | "header": {
20 | "name": "Header",
21 | "settings": {
22 | "paragraph": "Add custom settings for this section. [Learn more](https://shopify.dev/themes/architecture/settings)"
23 | }
24 | },
25 | "footer": {
26 | "name": "Footer",
27 | "settings": {
28 | "paragraph": "Add custom settings for this section. [Learn more](https://shopify.dev/themes/architecture/settings)"
29 | }
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/shopify/sections/footer.liquid:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 | © Shopify Theme Lab
12 |
13 |
14 |
15 | {% schema %}
16 | {
17 | "name": "t:sections.footer.name",
18 | "settings": [
19 | {
20 | "type": "paragraph",
21 | "content": "t:sections.footer.settings.paragraph"
22 | }
23 | ]
24 | }
25 | {% endschema %}
--------------------------------------------------------------------------------
/shopify/sections/header.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 | Logo
4 |
5 |
6 | {% render 'layout-menu' %}
7 |
8 |
9 | {% if shop.customer_accounts_enabled %}
10 | {% if customer %}
11 |
12 | {{ 'action.account' | t }}
13 |
14 | {{ 'action.log_out' | t | customer_logout_link }}
15 | {% else %}
16 | {{ 'action.log_in' | t | customer_login_link }}
17 | {{ 'action.register' | t | customer_register_link }}
18 | {% endif %}
19 | {% endif %}
20 |
21 |
22 | {{ 'action.cart' | t }}
23 |
24 |
25 |
26 |
27 | {% schema %}
28 | {
29 | "name": "t:sections.header.name",
30 | "settings": [
31 | {
32 | "type": "paragraph",
33 | "content": "t:sections.header.settings.paragraph"
34 | }
35 | ]
36 | }
37 | {% endschema %}
--------------------------------------------------------------------------------
/shopify/sections/main-404.liquid:
--------------------------------------------------------------------------------
1 | {{ '404.title' | t }}
2 | {{ '404.text' | t }}
--------------------------------------------------------------------------------
/shopify/sections/main-article.liquid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uicrooks/shopify-theme-lab/478019b8fc16554621cbff8010dbd084ad6b4144/shopify/sections/main-article.liquid
--------------------------------------------------------------------------------
/shopify/sections/main-blog.liquid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uicrooks/shopify-theme-lab/478019b8fc16554621cbff8010dbd084ad6b4144/shopify/sections/main-blog.liquid
--------------------------------------------------------------------------------
/shopify/sections/main-cart.liquid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uicrooks/shopify-theme-lab/478019b8fc16554621cbff8010dbd084ad6b4144/shopify/sections/main-cart.liquid
--------------------------------------------------------------------------------
/shopify/sections/main-collection.liquid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uicrooks/shopify-theme-lab/478019b8fc16554621cbff8010dbd084ad6b4144/shopify/sections/main-collection.liquid
--------------------------------------------------------------------------------
/shopify/sections/main-index.liquid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uicrooks/shopify-theme-lab/478019b8fc16554621cbff8010dbd084ad6b4144/shopify/sections/main-index.liquid
--------------------------------------------------------------------------------
/shopify/sections/main-list-collections.liquid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uicrooks/shopify-theme-lab/478019b8fc16554621cbff8010dbd084ad6b4144/shopify/sections/main-list-collections.liquid
--------------------------------------------------------------------------------
/shopify/sections/main-page-contact.liquid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uicrooks/shopify-theme-lab/478019b8fc16554621cbff8010dbd084ad6b4144/shopify/sections/main-page-contact.liquid
--------------------------------------------------------------------------------
/shopify/sections/main-page.liquid:
--------------------------------------------------------------------------------
1 | {{ page.title }}
2 | {{ page.content }}
--------------------------------------------------------------------------------
/shopify/sections/main-password.liquid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uicrooks/shopify-theme-lab/478019b8fc16554621cbff8010dbd084ad6b4144/shopify/sections/main-password.liquid
--------------------------------------------------------------------------------
/shopify/sections/main-product.liquid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uicrooks/shopify-theme-lab/478019b8fc16554621cbff8010dbd084ad6b4144/shopify/sections/main-product.liquid
--------------------------------------------------------------------------------
/shopify/sections/main-search.liquid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uicrooks/shopify-theme-lab/478019b8fc16554621cbff8010dbd084ad6b4144/shopify/sections/main-search.liquid
--------------------------------------------------------------------------------
/shopify/sections/vue-examples.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Shopify Theme Lab 🧪
5 |
6 |
7 |
8 | Customizable modular development environment for blazing-fast Shopify theme creation.
9 |
10 |
11 |
12 |
17 |
18 |
19 |
20 |
28 |
29 | Vue component with slots and props
30 |
31 |
32 |
33 |
34 |
35 |
36 | Global Vue mixin
37 |
38 |
39 |
40 | NODE_ENV: {% raw %}{{ env }}{% endraw %}
41 |
42 |
43 |
44 |
45 |
46 |
47 | Global Vue directive
48 |
49 |
50 |
51 | this text
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | Renderless Vue component + Vuex
62 |
63 |
64 |
65 | Vuex “my-module” state “visible” is set to {% raw %}{{ visible }}{% endraw %}
66 |
67 |
68 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | Vuex anywhere!
78 |
79 |
80 |
81 | Vuex “my-module” state “visible” is set to {% raw %}{{ $store.state['my-module'].visible }}{% endraw %}
82 |
83 |
84 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | .shopify-theme-lab {
98 | background: rgb(240,240,240);
99 | border-radius: 10px;
100 | padding: 30px;
101 | margin: 20px 0;
102 | }
103 |
104 | .shopify-theme-lab__headline {
105 | font-size: 24px;
106 | font-weight: 700;
107 | text-align: center;
108 | margin-bottom: 10px;
109 | }
110 |
111 | .shopify-theme-lab__subline {
112 | font-size: 16px;
113 | font-weight: 700;
114 | }
115 |
116 | .shopify-theme-lab__text {
117 | font-size: 18px;
118 | text-align: center;
119 | margin-bottom: 40px;
120 | }
121 |
122 | .shopify-theme-lab__examples {
123 | display: flex;
124 | flex-wrap: wrap;
125 | justify-content: center;
126 | gap: 40px;
127 | }
128 |
129 | .shopify-theme-lab__example {
130 | display: flex;
131 | flex-direction: column;
132 | gap: 20px;
133 | }
134 |
135 | .shopify-theme-lab__button {
136 | color: rgb(255,255,255);
137 | background: rgb(0,0,0);
138 | font-size: 12px;
139 | font-weight: 700;
140 | text-transform: uppercase;
141 | letter-spacing: 0.1em;
142 | border-radius: 4px;
143 | padding: 5px 15px;
144 | margin-top: 5px;
145 | }
146 |
147 | .shopify-theme-lab__button:hover {
148 | background: rgb(70,70,70);
149 | }
150 |
151 |
152 | {% schema %}
153 | {
154 | "name": "Vue examples",
155 | "class": "vue-section",
156 | "presets": [
157 | {
158 | "name": "Vue examples"
159 | }
160 | ]
161 | }
162 | {% endschema %}
--------------------------------------------------------------------------------
/shopify/snippets/layout-menu.liquid:
--------------------------------------------------------------------------------
1 |
2 | {% for link in linklists.main-menu.links %}
3 |
18 | {% endfor %}
19 |
--------------------------------------------------------------------------------
/shopify/templates/404.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "main": {
4 | "type": "main-404"
5 | }
6 | },
7 | "order": [
8 | "main"
9 | ]
10 | }
--------------------------------------------------------------------------------
/shopify/templates/article.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "main": {
4 | "type": "main-article"
5 | }
6 | },
7 | "order": [
8 | "main"
9 | ]
10 | }
--------------------------------------------------------------------------------
/shopify/templates/blog.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "main": {
4 | "type": "main-blog"
5 | }
6 | },
7 | "order": [
8 | "main"
9 | ]
10 | }
--------------------------------------------------------------------------------
/shopify/templates/cart.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "main": {
4 | "type": "main-cart"
5 | }
6 | },
7 | "order": [
8 | "main"
9 | ]
10 | }
--------------------------------------------------------------------------------
/shopify/templates/collection.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "main": {
4 | "type": "main-collection"
5 | }
6 | },
7 | "order": [
8 | "main"
9 | ]
10 | }
--------------------------------------------------------------------------------
/shopify/templates/customers/account.liquid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uicrooks/shopify-theme-lab/478019b8fc16554621cbff8010dbd084ad6b4144/shopify/templates/customers/account.liquid
--------------------------------------------------------------------------------
/shopify/templates/customers/activate_account.liquid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uicrooks/shopify-theme-lab/478019b8fc16554621cbff8010dbd084ad6b4144/shopify/templates/customers/activate_account.liquid
--------------------------------------------------------------------------------
/shopify/templates/customers/addresses.liquid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uicrooks/shopify-theme-lab/478019b8fc16554621cbff8010dbd084ad6b4144/shopify/templates/customers/addresses.liquid
--------------------------------------------------------------------------------
/shopify/templates/customers/login.liquid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uicrooks/shopify-theme-lab/478019b8fc16554621cbff8010dbd084ad6b4144/shopify/templates/customers/login.liquid
--------------------------------------------------------------------------------
/shopify/templates/customers/order.liquid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uicrooks/shopify-theme-lab/478019b8fc16554621cbff8010dbd084ad6b4144/shopify/templates/customers/order.liquid
--------------------------------------------------------------------------------
/shopify/templates/customers/register.liquid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uicrooks/shopify-theme-lab/478019b8fc16554621cbff8010dbd084ad6b4144/shopify/templates/customers/register.liquid
--------------------------------------------------------------------------------
/shopify/templates/customers/reset_password.liquid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uicrooks/shopify-theme-lab/478019b8fc16554621cbff8010dbd084ad6b4144/shopify/templates/customers/reset_password.liquid
--------------------------------------------------------------------------------
/shopify/templates/gift_card.liquid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uicrooks/shopify-theme-lab/478019b8fc16554621cbff8010dbd084ad6b4144/shopify/templates/gift_card.liquid
--------------------------------------------------------------------------------
/shopify/templates/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "vue-examples": {
4 | "type": "vue-examples"
5 | },
6 | "main": {
7 | "type": "main-index"
8 | }
9 | },
10 | "order": [
11 | "vue-examples",
12 | "main"
13 | ]
14 | }
--------------------------------------------------------------------------------
/shopify/templates/list-collections.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "main": {
4 | "type": "main-list-collections"
5 | }
6 | },
7 | "order": [
8 | "main"
9 | ]
10 | }
--------------------------------------------------------------------------------
/shopify/templates/page.contact.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "main": {
4 | "type": "main-page-contact"
5 | }
6 | },
7 | "order": [
8 | "main"
9 | ]
10 | }
--------------------------------------------------------------------------------
/shopify/templates/page.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "main": {
4 | "type": "main-page"
5 | }
6 | },
7 | "order": [
8 | "main"
9 | ]
10 | }
--------------------------------------------------------------------------------
/shopify/templates/password.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "main": {
4 | "type": "main-password"
5 | }
6 | },
7 | "order": [
8 | "main"
9 | ]
10 | }
--------------------------------------------------------------------------------
/shopify/templates/product.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "main": {
4 | "type": "main-product"
5 | }
6 | },
7 | "order": [
8 | "main"
9 | ]
10 | }
--------------------------------------------------------------------------------
/shopify/templates/search.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": {
3 | "main": {
4 | "type": "main-search"
5 | }
6 | },
7 | "order": [
8 | "main"
9 | ]
10 | }
--------------------------------------------------------------------------------
/src/css/main.css:
--------------------------------------------------------------------------------
1 | /**
2 | * entry file for Tailwind CSS
3 | * and other style files
4 | */
5 | @import "tailwindcss/base";
6 | @import "tailwindcss/components";
7 |
8 | /* @import "my-file"; */
9 |
10 | @import "tailwindcss/utilities";
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * imports
3 | */
4 | import { createApp } from 'vue'
5 | import { createStore } from 'vuex'
6 | import './css/main.css'
7 |
8 | /**
9 | * vuex
10 | * auto-import all modules and prepare shared store
11 | */
12 | const vuexModules = require.context('./vue/store/', true, /\.js$/)
13 | const modules = {}
14 |
15 | vuexModules.keys().forEach(key => {
16 | const name = key.replace(/\.(\/|js)/g, '').replace(/\s/g, '-')
17 | modules[name] = vuexModules(key).default
18 | })
19 |
20 | const store = createStore({
21 | strict: process.env.NODE_ENV !== 'production',
22 | modules
23 | })
24 |
25 | /**
26 | * create vue instance function
27 | */
28 | const createVueApp = () => {
29 | const app = createApp({})
30 |
31 | /**
32 | * vue components
33 | * auto-import all vue components
34 | */
35 | const vueComponents = require.context('./vue/components/', true, /\.(vue|js)$/)
36 |
37 | vueComponents.keys().forEach(key => {
38 | const component = vueComponents(key).default
39 |
40 | // if a component has a name defined use the name, else use the path as the component name
41 | const name = component.name
42 | ? component.name
43 | : key.replace(/\.(\/|vue|js)/g, '').replace(/(\/|-|_|\s)\w/g, (match) => match.slice(1).toUpperCase())
44 |
45 | app.component(name, component)
46 | })
47 |
48 | /**
49 | * vue mixins
50 | * auto-register all mixins with a 'global' keyword in their filename
51 | */
52 | const mixins = require.context('./vue/mixins/', true, /.*global.*\.js$/)
53 |
54 | mixins.keys().forEach(key => {
55 | app.mixin(mixins(key).default)
56 | })
57 |
58 | /**
59 | * vue directives
60 | * auto-register all directives with a 'global' keyword in their filename
61 | */
62 | const directives = require.context('./vue/directives/', true, /.*global.*\.js$/)
63 |
64 | directives.keys().forEach(key => {
65 | const directive = directives(key).default
66 | app.directive(directive.name, directive.directive)
67 | })
68 |
69 | /**
70 | * vue plugins
71 | * extend with additional features
72 | */
73 | app.use(store)
74 |
75 | return app
76 | }
77 |
78 | /**
79 | * create and mount vue instance(s)
80 | */
81 | const appElement = document.querySelector('#app')
82 |
83 | if (appElement) {
84 | createVueApp().mount(appElement)
85 | } else {
86 | const vueElements = document.querySelectorAll('[vue]')
87 | if (vueElements) vueElements.forEach(el => createVueApp().mount(el))
88 | }
89 |
90 | /**
91 | * fixes for Shopify sections
92 | * 1. properly render vue components on user insert in the theme editor
93 | * 2. reload the current page to rerender async inserted sections with vue components
94 | *
95 | * add the 'vue' keyword to the section's wrapper classes if the section uses any vue functionality e.g.:
96 | * {% schema %}
97 | * {
98 | * "class": "vue-section"
99 | * }
100 | * {% endschema %}
101 | */
102 | if (Shopify.designMode) {
103 | document.addEventListener('shopify:section:load', (event) => {
104 | if (event.target.classList.value.includes('vue')) {
105 | createVueApp().mount(event.target)
106 | }
107 | })
108 | } else if (!Shopify.designMode && process.env.NODE_ENV === 'development') {
109 | new MutationObserver((mutationsList) => {
110 | mutationsList.forEach(record => {
111 | const vue = Array.from(record.addedNodes).find(node => node.classList && node.classList.value.includes('vue'))
112 | if (vue) window.location.reload()
113 | })
114 | }).observe(document.body, {
115 | childList: true,
116 | subtree: true
117 | })
118 | }
--------------------------------------------------------------------------------
/src/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Tailwind CSS configuration file
3 | *
4 | * docs: https://tailwindcss.com/docs/configuration
5 | * default: https://github.com/tailwindcss/tailwindcss/blob/master/stubs/defaultConfig.stub.js
6 | */
7 | const path = require('path')
8 |
9 | module.exports = {
10 | theme: {
11 | extend: {},
12 | container: {
13 | center: true,
14 | padding: '1rem'
15 | }
16 | },
17 | plugins: [],
18 | content: [
19 | path.resolve(__dirname, '**/*.{js,vue}'),
20 | path.resolve(__dirname, '../shopify/**/*.liquid')
21 | ]
22 | }
--------------------------------------------------------------------------------
/src/vue/components/render/my-component.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | -
10 | {{ key }}: {{ value }}
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/vue/components/renderless/my-component.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/vue/directives/global.directive.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'myDirective',
3 | directive: {
4 | beforeMount (el) {
5 | el.innerText = `“v-my-directive” was used on ${el.innerText}`
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/src/vue/mixins/global.mixin.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data () {
3 | return {
4 | env: process.env.NODE_ENV
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/src/vue/store/my-module.js:
--------------------------------------------------------------------------------
1 | /**
2 | * state
3 | */
4 | const state = {
5 | visible: false
6 | }
7 |
8 | /**
9 | * getters
10 | */
11 | const getters = {}
12 |
13 | /**
14 | * mutations
15 | */
16 | const mutations = {
17 | TOGGLE (state) {
18 | state.visible = !state.visible
19 | },
20 |
21 | SHOW (state) {
22 | state.visible = true
23 | },
24 |
25 | HIDE (state) {
26 | state.visible = false
27 | }
28 | }
29 |
30 | /**
31 | * actions
32 | */
33 | const actions = {
34 | toggle ({ commit }) {
35 | commit('TOGGLE')
36 | },
37 |
38 | show ({ commit }) {
39 | commit('SHOW')
40 | },
41 |
42 | hide ({ commit }) {
43 | commit('HIDE')
44 | }
45 | }
46 |
47 | /**
48 | * export
49 | */
50 | export default {
51 | namespaced: true,
52 | state,
53 | getters,
54 | mutations,
55 | actions
56 | }
--------------------------------------------------------------------------------