34 | {%- endif -%}
35 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | A `vitepress` app to deliver the documentation for the Apostrophe CMS E-commerce Starter Kit.
2 |
3 | Install:
4 |
5 | ```bash
6 | npm install
7 | ```
8 |
9 | Optionally update the dependencies:
10 |
11 | ```bash
12 | npm update
13 | ```
14 |
15 | ## Development
16 |
17 | ```bash
18 | npm run dev
19 | ```
20 |
21 | ## Build
22 |
23 | ```bash
24 | npm run build
25 | ```
26 |
27 | ## Preview
28 |
29 | ```bash
30 | npm run preview
31 | ```
32 |
33 | ## Make it yours
34 |
35 | Open `.vitepress/config.js` and adapt it for your needs. Don't forget to update the repository configuration:
36 |
37 | ```js
38 | // .vitepress/config.js
39 |
40 | // Settings
41 | const project = `ecommerce-starter-kit`;
42 | const repo = `apostrophecms/${project}`;
43 | // Settings end
44 | ```
45 | Learn more about configuring and customizing VitePress at [https://vitepress.vuejs.org/](https://vitepress.vuejs.org/).
46 |
47 | ## Deploy
48 |
49 | A GitHub Action workflow is configured to auto build & deploy the documentation to GitHub Pages. You can find the workflow configuration in `.github/workflows/docs.yml`.
50 |
51 | Configure GH Pages and find the URL to your documentation in the repository settings under **Pages**.
52 |
53 | ## Remove
54 |
55 | You can completely remove the documentation from your project by deleting:
56 | - `docs/`
57 | - `.github/workflows/docs.yml`
58 |
--------------------------------------------------------------------------------
/docs/user/search-and-seo.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Search, SEO and Open Graph
3 | titleTemplate: User Guide
4 | ---
5 |
6 | # {{ $frontmatter.title }}
7 |
8 | The Apostrophe CMS E-commerce Starter Kit comes with a set of features, that will help you build both search engine optimized and social sharing friendly website. Furthermore, it offers a simple but powerful in-site search functionality.
9 |
10 | ## SEO and Open Graph
11 |
12 | Every page and piece, that is visible and have its own URL on your website, has dedicated to SEO and Open Graph (helping the shared content from your website to social platforms to be well offered). You can find them in the respective "SEO" and "Open Graph" tabs of the Editor Modal.
13 |
14 | 
15 |
16 | ## Search
17 |
18 | If you want to show the Apostrophe CMS core search feature (button) in the header of your site, you need to set it from the site configuration - in the "Search URL" field set choose "Page" type, and select the "Search" page from the relation field or modal.
19 |
20 | ::: info
21 | In order to have well looking search results, you need to have filled either the "SEO - Description" field of every piece/page or the "Tagline" field. The search page results will use one or the other, where the first in the order mentioned above will be shown.
22 | :::
23 |
24 | 
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/scripts/sync-down:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | TARGET="$1"
4 | if [ -z "$TARGET" ]; then
5 | echo "Usage: ./scripts/sync-down production"
6 | echo "(or as appropriate)"
7 | exit 1
8 | fi
9 |
10 | source deployment/settings || exit 1
11 | source "deployment/settings.$TARGET" || exit 1
12 |
13 | #Enter the Mongo DB name (should be same locally and remotely).
14 | dbName=$PROJECT
15 |
16 | #Enter the Project name (should be what you called it for stagecoach).
17 | projectName=$PROJECT
18 |
19 | #Enter the SSH username/url for the remote server.
20 | remoteSSH="-p $SSH_PORT $USER@$SERVER"
21 | rsyncTransport="ssh -p $SSH_PORT"
22 | rsyncDestination="$USER@$SERVER"
23 |
24 | echo "Syncing MongoDB"
25 | ssh $remoteSSH mongodump -d $dbName -o /tmp/mongodump.$dbName &&
26 | rsync -av -e "$rsyncTransport" $rsyncDestination:/tmp/mongodump.$dbName/ /tmp/mongodump.$dbName &&
27 | ssh $remoteSSH rm -rf /tmp/mongodump.$dbName &&
28 | # noIndexRestore increases compatibility between 3.x and 2.x,
29 | # and Apostrophe will recreate the indexes correctly at startup
30 | mongorestore --noIndexRestore --drop -d $dbName /tmp/mongodump.$dbName/$dbName &&
31 | echo "Syncing Files" &&
32 | rsync -av --delete -e "$rsyncTransport" $rsyncDestination:/opt/stagecoach/apps/$projectName/uploads/ ./public/uploads &&
33 | echo "Synced down from $TARGET"
34 | echo "YOU MUST RESTART THE SITE LOCALLY TO REBUILD THE MONGODB INDEXES."
35 |
--------------------------------------------------------------------------------
/modules/theme/views/icon.html:
--------------------------------------------------------------------------------
1 | {#
2 | # In order to control the color, set the "color" CSS property on the parent element.
3 | #
4 | # Arguments:
5 | # - name: the name without the "theme-svg-icon-" prefix, e.g. 'heart'
6 | # - size: (string) sm (16px) | md (24px, default) | l (32px) | xl (40px)
7 | # or any tailwind size class e.g. "w-[20px] h-[20px]"
8 | # - cls: (string) additional CSS class names to be added to the svg tag
9 | #}
10 | {% macro svg(name, size, cls = '') -%}
11 | {%- if size == 'sm' -%}
12 | {# 16px #}
13 | {% set sizeCls = "w-4 h-4" %}
14 | {%- elif size == 'md' -%}
15 | {# 24px #}
16 | {% set sizeCls = "w-6 h-6" %}
17 | {%- elif size == 'l' -%}
18 | {# 32px #}
19 | {% set sizeCls = "w-8 h-8" %}
20 | {%- elif size == 'xl' -%}
21 | {# 40px #}
22 | {% set sizeCls = "w-10 h-10" %}
23 | {%- elif not size -%}
24 | {# default #}
25 | {% set sizeCls = "w-6 h-6" %}
26 | {%- else -%}
27 | {# custom size, e.g. "w-[20px] h-[20px]"
28 | WARNING: we don't build it dynamically
29 | so that tailwind can find it when treeshaking from the caller code #}
30 | {% set sizeCls = size %}
31 | {%- endif -%}
32 |
33 | {%- set name = 'theme-svg-icon-' + name -%}
34 | {%- set _cls = '' -%}
35 | {%- if cls -%}
36 | {%- set _cls = ' ' + cls -%}
37 | {%- endif -%}
38 |
39 |
42 | {%- endmacro %}
43 |
--------------------------------------------------------------------------------
/modules/product-page/index.js:
--------------------------------------------------------------------------------
1 | export default {
2 | extend: '@apostrophecms/piece-page-type',
3 | options: {
4 | label: 'app:productPageLabel',
5 | alias: 'productPage',
6 | perPage: 15
7 | },
8 | fields: {
9 | add: {
10 | tagline: {
11 | type: 'string',
12 | textarea: true,
13 | label: 'app:tagline',
14 | max: 200
15 | },
16 | main: {
17 | type: 'area',
18 | label: 'app:content',
19 | options: {
20 | widgets: {
21 | product: {},
22 | 'product-featured': {},
23 | 'product-category': {},
24 | cta: {},
25 | promo: {},
26 | blockquote: {}
27 | }
28 | }
29 | }
30 | },
31 | group: {
32 | basics: {
33 | label: 'app:groupBasics',
34 | fields: [ 'tagline', 'main' ]
35 | }
36 | }
37 | },
38 | methods(self) {
39 | return {
40 | async beforeShow(req) {
41 | if (!req.data.piece.tagsIds.length) {
42 | return;
43 | }
44 | req.data.relatedProducts = await self.apos.product.find(req, {
45 | _id: {
46 | $ne: req.data.piece._id
47 | }
48 | })
49 | ._tags(req.data.piece.tagsIds)
50 | .sort({
51 | publishDate: -1,
52 | updatedAt: -1
53 | })
54 | .limit(4)
55 | .toArray();
56 | }
57 | };
58 | }
59 | };
60 |
--------------------------------------------------------------------------------
/modules/theme/views/design-system/cta-widget/image.njk:
--------------------------------------------------------------------------------
1 | {% extends dsPreview %}
2 | {% import "theme:cta-widget.html" as cta %}
3 | {% import "theme:helpers.html" as helpers %}
4 |
5 | {% set storyData = apos.dsp.configData('molecules-cta-widget').image %}
6 |
7 | {% block tagline %}
8 | cta Image
9 | {% endblock %}
10 |
11 | {% block preview %}
12 | {% rendercall helpers.container() %}
13 |
14 | {% rendercall cta.image(storyData) %}
15 |
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.
61 | {% endblock %}
62 |
--------------------------------------------------------------------------------
/deployment/start:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Make the site live again, for instance by tweaking a .htaccess file
4 | # or starting a node server. In this example we also set up a
5 | # data/port file so that sc-proxy.js can figure out what port
6 | # to forward traffic to for this site. The idea is that every
7 | # folder in /var/webapps represents a separate project with a separate
8 | # node process, each listening on a specific port, and they all
9 | # need traffic forwarded from a reverse proxy server on port 80
10 |
11 | # Useful for debugging
12 | #set -x verbose
13 |
14 | # Express should not reveal information on errors,
15 | # also optimizes Express performance
16 | export NODE_ENV=production
17 |
18 | if [ ! -f "app.js" ]; then
19 | echo "I don't see app.js in the current directory."
20 | exit 1
21 | fi
22 |
23 | # Assign a port number if we don't yet have one
24 |
25 | if [ -f "data/port" ]; then
26 | PORT=`cat data/port`
27 | else
28 | # No port set yet for this site. Scan and sort the existing port numbers if any,
29 | # grab the highest existing one
30 | PORT=`cat ../../../*/data/port 2>/dev/null | sort -n | tail -1`
31 | if [ "$PORT" == "" ]; then
32 | echo "First app ever, assigning port 3000"
33 | PORT=3000
34 | else
35 | # Bash is much nicer than sh! We can do math without tears!
36 | let PORT+=1
37 | fi
38 | echo $PORT > data/port
39 | echo "First startup, chose port $PORT for this site"
40 | fi
41 |
42 | # Run the app via 'forever' so that it restarts automatically if it fails
43 | # Use `pwd` to make sure we have a full path, forever is otherwise easily confused
44 | # and will stop every server with the same filename
45 |
46 | # Use a "for" loop. A classic single-port file will do the
47 | # right thing, but so will a file with multiple port numbers
48 | # for load balancing across multiple cores
49 | for port in $PORT
50 | do
51 | export PORT=$port
52 | forever --minUptime=1000 --spinSleepTime=10000 -o data/console.log -e data/error.log start `pwd`/app.js && echo "Site started"
53 | done
54 |
55 | # Run the app without 'forever'. Record the process id so 'stop' can kill it later.
56 | # We recommend installing 'forever' instead for node apps. For non-node apps this code
57 | # may be helpful
58 | #
59 | # node app.js >> data/console.log 2>&1 &
60 | # PID=$!
61 | # echo $PID > data/pid
62 | #
63 | #echo "Site started"
64 |
--------------------------------------------------------------------------------
/modules/theme/ui/src/tailwind.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | /* Typography */
6 | @layer base {
7 | html {
8 | @apply font-sans
9 | text-base
10 | font-normal
11 | text-gray-700;
12 | }
13 |
14 | h1 {
15 | @apply text-6xl
16 | font-extrabold;
17 | }
18 |
19 | h2 {
20 | @apply text-5xl
21 | font-extrabold;
22 | }
23 |
24 | h3 {
25 | @apply text-4xl
26 | font-extrabold;
27 | }
28 |
29 | h4 {
30 | @apply text-3xl
31 | font-bold;
32 | }
33 |
34 | h5 {
35 | @apply text-2xl
36 | font-bold;
37 | }
38 |
39 | h6 {
40 | @apply text-xl
41 | font-bold;
42 | }
43 |
44 | /* Page layout */
45 | .app {
46 | @apply min-h-screen;
47 | display: grid;
48 | grid-template-rows: auto 1fr auto;
49 | overflow-x: hidden;
50 | }
51 |
52 |
53 | /* Apos/Tiptap specific */
54 |
55 | .t-richtext li > p {
56 | @apply m-0;
57 | }
58 |
59 | .apos-input--select {
60 | background-image: none;
61 | }
62 |
63 | .app-pager {
64 | @apply mt-4 md:mt-8 border-b border-gray text-lg text-center;
65 | }
66 |
67 | .app-pager__item,
68 | .app-pager__item > a {
69 | display: inline-block;
70 | }
71 |
72 | .app-pager__item > a {
73 | @apply p-4;
74 | }
75 |
76 | .app-pager__item.is-active {
77 | @apply p-4 border-b-[3px] border-brand;
78 | }
79 |
80 | /* Image widget */
81 | .image-widget__wrapper {
82 | @apply my-5 md:my-10;
83 | }
84 | .image-widget__caption {
85 | @apply mt-1 text-sm text-gray-600;
86 | }
87 | }
88 |
89 | @layer components {
90 | .t-display {
91 | @apply text-7xl
92 | font-extrabold leading-tight;
93 | }
94 |
95 | .t-subtitle {
96 | @apply text-xl
97 | font-light;
98 | }
99 |
100 | .t-caption {
101 | @apply text-sm
102 | font-semibold
103 | uppercase
104 | tracking-wider;
105 | }
106 |
107 | .t-link {
108 | @apply font-bold underline
109 | text-brand
110 | transition-all ease-in-out delay-150
111 | hover:text-brand-700
112 | active:text-brand-700
113 | visited:text-brand-700
114 | cursor-pointer;
115 | }
116 |
117 | .t-richtext {
118 | @apply prose prose-p:text-base max-w-2xl;
119 | }
120 |
121 | .break-anywhere {
122 | overflow-wrap: anywhere;
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/modules/theme/views/design-system/promo-widget/promo.njk:
--------------------------------------------------------------------------------
1 | {% extends dsPreview %}
2 | {% import "theme:promo-widget.html" as promoWidget %}
3 | {% import "theme:helpers.html" as helpers %}
4 |
5 | {% set storyData = apos.dsp.configData('molecules-promo-widget').promo %}
6 |
7 | {% block tagline %}
8 | Promo Widget
9 | {% endblock %}
10 |
11 | {% block preview %}
12 | {% rendercall helpers.container() %}
13 | {% rendercall promoWidget.render(storyData) %}
14 |
Summer Sale
15 |
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.
27 | {% dscode 'njk' %}
28 | {% import "theme:cta-widget.html" as cta %}
29 | {# Cta-widget with default dark solid background when no renderType is specified #}
30 | {% rendercall cta.solid(storyData) %}
31 |
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.
61 | {% endfragment %}
62 |
--------------------------------------------------------------------------------
/docs/user/products-and-categories.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Products and Categories
3 | titleTemplate: User Guide
4 | ---
5 |
6 | # {{ $frontmatter.title }}
7 |
8 | The Apostrophe CMS E-commerce Starter Kit comes with Product and Product Category pieces and pages. Be sure to check out the [Getting Started](./getting-started.md) section first for a list of tips and recommendations as first steps in building your site content, including receipes for content taxonomy.
9 |
10 | ## Product Category
11 |
12 | You can create new categories by either using the quick menu (the blue plus button at the top of the page) and choosing "Product Category", or by using the "New Product Category" button after clicking the "Content - Product Categories" administration menu item.
13 |
14 | Beside the essential fields, when adding a new category piece, you can also:
15 |
16 | - Add "Publication Date" to control the order of the categories when shown in the page or widget. Categories having newer publication date will be shown first. If you leave that field empty, it will contain the date when the category was created.
17 | - From the "Page" tab, you can control the heading type of every category view page via the "Header Type" field. By default, a "Title" will be set, resulting in the default Title/Tagline heading. You can choose "Hero" and you'll see a new area for adding the Hero widget.
18 |
19 | **Title**
20 | 
21 |
22 | **Hero**
23 | 
24 |
25 | ::: tip
26 | You can choose your user experience - manage your widgets within the page itself or inside the Page Editor. Keep in mind, that the Heading area will be visible once you choose the "Hero" heading type, which can happen only in the Page Editor.
27 | :::
28 |
29 | ## Product
30 |
31 | You can create new products by either using the quick menu (the blue plus button at the top of the page) and choosing "Product", or by using the "New Product" button after clicking the "Content - Products" administration menu item.
32 |
33 | Beside the essential fields, when adding a new category piece, you can also:
34 |
35 | - Add Buy Now URL. It will be shown as Buy Now button in the product view page and on any product card on your site.
36 | - Add "Publication Date" to control the order of the products when shown in the page or widget. Products having newer publication date will be shown first. If you leave that field empty, it will contain the date when the product was created.
37 | - Add product metadata and specifications. They will be shown in the product view page.
38 | 
39 | - Add Promo Price. It will be shown in the product view page, beside the regular price.
40 |
41 | ::: info Note
42 | You can choose any vendor, that provides a Buy Now URL service and use the generated links in your products. The Apostrophe CMS E-commerce Starter Kit does not provide any e-commerce functionality, it's just a starter kit for building e-commerce websites.
43 | :::
44 |
45 | ### Related Products
46 |
47 | The product view page shows a list of related products. This is a fully automated section in matter of filtering. It will show up to 4 other products that have at least one tag in common with the viewed product. You can add tags to the product via the "Tags" field.
48 |
49 | ## Custom Pages and Widgets
50 |
51 | You can turn any custom page into a product landing page. You can learn more about custom pages in the [Custom Pages section](./custom-pages.md). Find out more about widgets in the [dedicated section](./widgets.md).
52 |
--------------------------------------------------------------------------------
/docs/.vitepress/config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vitepress';
2 |
3 | // Settings
4 | const project = 'starter-kit-ecommerce';
5 | const repo = `apostrophecms/${project}`;
6 | // Settings end
7 |
8 | // https://vitepress.dev/reference/site-config
9 | export default defineConfig({
10 | base: `/${project}/`,
11 | title: 'Starter Kit',
12 | description: 'Apostrophe CMS Starter Kit for e-commerce projects, built with Tailwind CSS.',
13 | appearance: true,
14 | themeConfig: {
15 | editLink: {
16 | pattern: `https://github.com/${repo}/edit/main/docs/:path`
17 | },
18 | logo: {
19 | dark: '/images/logo-on-dark.svg',
20 | light: '/images/logo-on-light.svg',
21 | alt: 'Apostrophe CMS'
22 | },
23 | // https://vitepress.dev/reference/default-theme-config
24 | nav: [
25 | {
26 | text: 'User Guide',
27 | link: '/user/',
28 | activeMatch: '/user/'
29 | },
30 | {
31 | text: 'Developer Guide',
32 | link: '/developer/',
33 | activeMatch: '/developer/'
34 | }
35 | ],
36 |
37 | sidebar: {
38 | '/user/': [
39 | {
40 | text: 'User Guide',
41 | collapsed: false,
42 | items: [
43 | {
44 | text: 'Introduction',
45 | link: '/user/'
46 | },
47 | {
48 | text: 'Getting Started',
49 | link: '/user/getting-started'
50 | },
51 | {
52 | text: 'Products & Categories',
53 | link: '/user/products-and-categories'
54 | },
55 | {
56 | text: 'Custom Pages',
57 | link: '/user/custom-pages'
58 | },
59 | {
60 | text: 'Widgets',
61 | link: '/user/widgets'
62 | },
63 | {
64 | text: 'Search & SEO',
65 | link: '/user/search-and-seo'
66 | }
67 | ]
68 | }
69 | ],
70 | '/developer/': [
71 | {
72 | text: 'Developer Guide',
73 | collapsed: false,
74 | items: [
75 | {
76 | text: 'Introduction',
77 | link: '/developer/'
78 | },
79 | {
80 | text: 'Getting Started',
81 | link: '/developer/getting-started'
82 | },
83 | {
84 | text: 'Branding & UI',
85 | link: '/developer/branding-and-ui'
86 | },
87 | {
88 | text: 'Modules & Widgets',
89 | link: '/developer/modules-and-widgets'
90 | },
91 | {
92 | text: 'Design System',
93 | link: '/developer/design-system'
94 | },
95 | {
96 | text: 'Resources',
97 | link: '/developer/resources'
98 | }
99 | ]
100 | }
101 | ]
102 | },
103 |
104 | socialLinks: [
105 | {
106 | icon: 'github',
107 | link: `https://github.com/${repo}`
108 | }
109 | ]
110 | },
111 | markdown: {
112 | languages: [
113 | {
114 | id: 'njk-html',
115 | scopeName: 'text.html.njk',
116 | grammar: require('./njk-html.tmLanguage.json'),
117 | displayName: 'Nunjucks',
118 | embeddedLangs: [ 'html' ],
119 | aliases: [ 'njk', 'nunjucks' ]
120 | }
121 | ]
122 | }
123 | });
124 |
--------------------------------------------------------------------------------
/modules/theme/views/design-system/hero-widget/full.njk:
--------------------------------------------------------------------------------
1 | {% extends dsPreview %}
2 | {% import "theme:hero-widget.html" as hero %}
3 | {% import "theme:helpers.html" as helpers %}
4 |
5 | {% set storyData = apos.dsp.configData('molecules-hero-widget').full %}
6 |
7 | {% block tagline %}
8 | Hero Full
9 | {% endblock %}
10 |
11 | {% block preview %}
12 | {% rendercall helpers.container() %}
13 |
14 | {% rendercall hero.full(storyData) %}
15 |
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.
45 |
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.
54 |
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.
42 |
43 | {% endrendercall %}
44 |
45 | {% dscode 'njk' %}
46 | {% import "theme:hero-widget.html" as hero %}
47 | {# Hero Widget with image on the right, with even ratio "image-content" #}
48 | {% rendercall hero.split(storyData | merge ({ imagePosition: 'right' }), { even: true }) %}
49 |
HERO SPLIT
50 |
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut magna, scelerisque vitae augue et, cursus placerat lorem. In nisi lacus, eleifend tincidunt quam et, consequat semper.
51 |
57 |
58 | {# ensure the story finishes with a nice spacing #}
59 |
60 |
61 | {% endrendercall %}
62 | {% endblock %}
63 |
--------------------------------------------------------------------------------
/modules/theme/views/design-system/hero-widget/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "full": {
3 | "caption": "Hero Widget-Full Caption",
4 | "ctaPrimary":
5 | {
6 | "label": "Shop Now",
7 | "urlType": "custom",
8 | "url": "#urlCtaPrimary"
9 | }
10 | ,
11 | "ctaOutlined": {
12 | "label": "Explore",
13 | "urlType": "page",
14 | "_page": [
15 | {
16 | "_url": "#_page_urlCtaOutlined"
17 | }
18 | ]
19 | },
20 | "dark": true,
21 | "_image": [
22 | {
23 | "_id": "clgyx91c9000s3eh9b9ji3dto:en:draft",
24 | "attachment": {
25 | "_id": "clgyx90ed000p3eh97uy897xp",
26 | "group": "images",
27 | "name": "some-hero",
28 | "title": "some hero",
29 | "extension": "jpg",
30 | "type": "attachment",
31 | "width": 1800,
32 | "height": 1350,
33 | "_urls": {
34 | "max": "https://picsum.photos/seed/hero/1600/1200",
35 | "full": "https://picsum.photos/seed/hero/1140/850",
36 | "two-thirds": "https://picsum.photos/seed/hero/760/570",
37 | "one-half": "https://picsum.photos/seed/hero/570/428",
38 | "one-third": "https://picsum.photos/seed/hero/380/285",
39 | "one-sixth": "https://picsum.photos/seed/hero/190/143",
40 | "original": "https://picsum.photos/seed/hero/1800/1350"
41 | },
42 | "srcset": "https://picsum.photos/seed/hero/1600/1200 1600w, https://picsum.photos/seed/hero/1140/850 1140w, https://picsum.photos/seed/hero/760/570 760w, https://picsum.photos/seed/hero/570/428 570w, https://picsum.photos/seed/hero/380/285 380w, https://picsum.photos/seed/hero/190/143 190w"
43 |
44 | },
45 | "title": "Hero Widget image",
46 | "alt": "Hero Widget alt",
47 | "slug": "image-laptop2",
48 | "archived": false,
49 | "type": "@apostrophecms/image",
50 | "aposLocale": "en:draft",
51 | "aposMode": "draft",
52 | "aposDocId": "clgyx91c9000s3eh9b9ji3dto",
53 | "metaType": "doc",
54 | "visibility": "public"
55 | }
56 | ]
57 | },
58 | "split": {
59 | "caption": "Hero Widget-Split Caption",
60 | "ctaPrimary":
61 | {
62 | "label": "Shop Now",
63 | "urlType": "custom",
64 | "url": "#urlCtaPrimary"
65 | }
66 | ,
67 | "ctaOutlined": {
68 | "label": "Explore",
69 | "urlType": "page",
70 | "_page": [
71 | {
72 | "_url": "#_page_urlCtaOutlined"
73 | }
74 | ]
75 | },
76 | "imagePosition": "left",
77 | "_image": [
78 | {
79 | "_id": "clgyx91c9000s3eh9b9ji3dto:en:draft",
80 | "attachment": {
81 | "_id": "clgyx90ed000p3eh97uy897xp",
82 | "group": "images",
83 | "name": "some-hero",
84 | "title": "some hero",
85 | "extension": "jpg",
86 | "type": "attachment",
87 | "width": 1800,
88 | "height": 1350,
89 | "_urls": {
90 | "max": "https://picsum.photos/seed/hero/1600/1200",
91 | "full": "https://picsum.photos/seed/hero/1140/850",
92 | "two-thirds": "https://picsum.photos/seed/hero/760/570",
93 | "one-half": "https://picsum.photos/seed/hero/570/428",
94 | "one-third": "https://picsum.photos/seed/hero/380/285",
95 | "one-sixth": "https://picsum.photos/seed/hero/190/143",
96 | "original": "https://picsum.photos/seed/hero/1800/1350"
97 | },
98 | "srcset": "https://picsum.photos/seed/hero/1600/1200 1600w, https://picsum.photos/seed/hero/1140/850 1140w, https://picsum.photos/seed/hero/760/570 760w, https://picsum.photos/seed/hero/570/428 570w, https://picsum.photos/seed/hero/380/285 380w, https://picsum.photos/seed/hero/190/143 190w"
99 |
100 | },
101 | "title": "Hero Widget image",
102 | "alt": "Hero Widget alt",
103 | "slug": "image-laptop2",
104 | "archived": false,
105 | "type": "@apostrophecms/image",
106 | "aposLocale": "en:draft",
107 | "aposMode": "draft",
108 | "aposDocId": "clgyx91c9000s3eh9b9ji3dto",
109 | "metaType": "doc",
110 | "visibility": "public"
111 | }
112 | ]
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/docs/user/getting-started.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Getting started
3 | titleTemplate: User Guide
4 | ---
5 |
6 | # {{ $frontmatter.title }}
7 |
8 | This section contains a list of tips and recommendations as first steps in building your site content.
9 |
10 | ## Before you start
11 |
12 | Take a moment to think about the structure of your product catalog and generally - your site. Outline the pages needed, beside the essential product related ones.
13 |
14 | ### Content taxonomy
15 |
16 | The tag based product taxonomy requires a bit of planning. You need to understand how it works first. The taxonomy is based entirely on tags. Tags are controlled via the "Content - Content Tags" administration menu. Currently they are used to:
17 | - filter products in the Products widget
18 | - assign products to categories
19 |
20 | Here is how product categories work:
21 | - when you create a product, you assign any number of tags to it
22 | - when you create a product category, you also assign any number of tags to it
23 | - when browsing a category page, only products that have at least one tag in common with the category are shown
24 |
25 | Additionally, when adding a product widget to any page, you can filter the products shown by up to ten tags. This allows you to create landing pages for promotions, or just to show a subset of products on any page.
26 |
27 | Based on that knowledge, you need to decide on the following:
28 | - what are the product categories
29 | - what tags will be used in the product categories in order to filter products for each category
30 | - what tags will be used to filter products in the Products widget, thus on the Home page and the eventual future landing (promo) pages
31 |
32 | The output of this planning should be a list of essential tags, that can be created in advance. This will allow you to assign them to products and categories as you create them, thus saving time and effort. It's also a good way to further scale your product catalog in the future.
33 |
34 | For example, you might have tags "Kids", "Shoes" and "September Sale". This would allow you to have product categories such as "Kids", "Shoes" and/or "Kids Shoes". You can also create a landing page for the September Sale by adding a Products widget to a Custom Page, and filtering the products by the "September Sale" tag.
35 |
36 | If the appropriate tags are added to the products in advance (while creating them), you'll save a lot of forth and back when further arranging your site content.
37 |
38 | ## Essential Pages
39 |
40 | The following pages are essential for your site to function properly, and should be created as a first step:
41 |
42 | - **Products Page**: this page is the landing page for your products. You need to create it once, using the "Product" type from the Type dropdown in the page editor.
43 | - **Product Category Page**: this page is the landing page for your product categories. If you don't plan to use categories, you can skip this step. Otherwise, you need to create it once, using the "Product Category" type from the Type dropdown in the page editor.
44 |
45 | Learn more about products and categories in the [dedicated section](./products-and-categories.md).
46 |
47 | You might also want to create placeholders (empty pages) for any other content you would initially like to have on your site. For example "About Us", "Contact Us", "Terms and Conditions", etc. You can create them as Custom Pages, and add content to them later. You can create a custom page by selecting the "Default" type from the Type dropdown in the page editor. Learn more about custom pages in the [dedicated section](./custom-pages.md).
48 |
49 | ## Configuration
50 |
51 | Use the top right configuration (cog) button to access the site configuration. Here you can:
52 | - create and manage the main navigation menu
53 | - control various header related features
54 | - create and manage the footer navigation menu
55 | - add and manage social links (shown in the footer)
56 | - brand your site with a brand name, logo and a favicon
57 |
58 | ## Home Page
59 |
60 | You should edit your Home page after your entire site content (and most importantly - your [product catalog and categories](./products-and-categories.md)) is in place. It is managed in a similar to a [custom page](./custom-pages.md) way.
61 |
62 | ## SEO
63 |
64 | Add the SEO related configuration while creating your content. Learn more in the [dedicated section](./search-and-seo.md).
65 |
--------------------------------------------------------------------------------
/modules/theme/views/design-system/button/icon.njk:
--------------------------------------------------------------------------------
1 | {% extends dsPreview %}
2 |
3 | {# The button macro #}
4 | {% import "theme:button.html" as buttons %}
5 |
6 |
7 | {# The component tagline #}
8 | {% block tagline %}
9 | Icon buttons
10 | {% endblock %}
11 |
12 | {# Preview of the component inside of `previewSimple` or `preview` block #}
13 | {% block preview %}
14 |
75 |
76 | {% endrendercall %}
77 | {% endfragment %}
78 |
79 | {% fragment _mainNav(navData, id = 'main-menu', hidden = '', cls = '') %}
80 |
94 | {% endfragment %}
95 |
--------------------------------------------------------------------------------
/docs/developer/getting-started.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Getting Started
3 | titleTemplate: Developer
4 | ---
5 |
6 | # {{ $frontmatter.title }}
7 |
8 | The e-commerce starter application aims to deliver a good starting point of Apostrophe CSM based e-commerce solutions, using the wide variety of features and techiques prvodied by the Apostrophe core.
9 |
10 | ## Try it on Codespaces
11 |
12 | You can try the starter kit on GitHub Codespaces. On the main page of the `apostrophecms/starter-kit-ecommerce` repository, under the "Template" dropdown, choose "Open in a codespace":
13 |
14 | 
15 |
16 | You can find a detailed guide at using.
17 |
18 | ::: tip
19 | When codespaces is initialized for a first time, it will take some time to install the dependencies and build the application. You can check the progress in the "Terminal" tab. Once the application is built, you can start the application via `npm run dev`.
20 |
21 | You may see an initial screen of the MongoDB extensions. You can safely ignore it and close the tab. No configuration is needed for the application to run.
22 | :::
23 |
24 | ## Local Installation
25 |
26 | ::: tip
27 | You will need the proper Node.js environment, a MongoDB up and running, etc. Follow the [official documentation](https://v3.docs.apostrophecms.org/guide/setting-up.html) for more information.
28 | :::
29 |
30 | ### Method 1
31 |
32 | 1. If you haven't already, install the [Apostrophe CLI tool](https://docs.apostrophecms.org/guide/setting-up.html#the-apostrophe-cli-tool) using
33 |
34 | ``` sh
35 | npm install -g @apostrophecms/cli
36 | ```
37 |
38 | 2. Clone the project locally by navigating to the parent directory you want the repo installed within and run the command:
39 |
40 | ``` sh
41 | apos create my-project-name --starter=ecommerce
42 | ```
43 |
44 | 3. Change to the new directory and run it:
45 |
46 | ``` sh
47 | npm run dev
48 | ```
49 |
50 | ### Method 2
51 |
52 | 1. Choose "Use this template" button on the main repository page and create your own repository:
53 |
54 | 
55 |
56 | 2. Clone it (replace `user/repo-name` as appropriate)
57 |
58 | ```sh
59 | git clone git@github.com:user/repo-name.git
60 | ```
61 |
62 | 3. Install the dependencies
63 |
64 | ```sh
65 | npm install
66 | ```
67 |
68 | Optionally, you can update the core dependencies to the latest versions:
69 |
70 | ```sh
71 | npm update
72 | ```
73 |
74 | 4. Run it
75 |
76 | ```sh
77 | npm run dev
78 | ```
79 |
80 | ## Initial configuration
81 |
82 | - Change the `shortName` value in your configuration in `app.js` note that installation using the CLI will complete this step automatically.
83 |
84 | ```js
85 | import apostrophe from 'apostrophe';
86 |
87 | apostrophe({
88 | root: import.meta,
89 | shortName: 'my-project-name',
90 | // ...rest of the configuration
91 | });
92 | ```
93 |
94 | - The control for restarting the application on change (dev mode only) has been moved to `modules/theme/index.js` compared to the default `starter-kit-essentials` application (`asset` module). If you want to disable this feature:
95 |
96 | ```js
97 | // modules/theme/index.js
98 | handlers(self) {
99 | return {
100 | '@apostrophecms/page:beforeSend': {
101 | webpack(req) {
102 | req.data.isDev = (process.env.NODE_ENV !== 'production'); // [!code --]
103 | req.data.isDev = false; // [!code ++]
104 | }
105 | }
106 | };
107 | },
108 | ```
109 |
110 | ## Production
111 |
112 | You need to build the application and execute the migrations when starting it in production:
113 |
114 | ```sh
115 | npm run release
116 | npm run start
117 | ```
118 |
119 | ## Architecture
120 |
121 | The starter kit is a standard Apostrophe CMS application, built on top of the official [`starter-kit-essentials`](https://github.com/apostrophecms/starter-kit-essentials) template. All the modules (including widgets) can be found in the `modules/` folder. You can learn more about the modules in the [Modules & Widgets](./modules-and-widgets.md) section.
122 |
123 | The entire UI (except the product view page) lives in the `theme` module. The application uses a standard Tailwind CSS configuration. You can learn more in the [Branding & UI](./branding-and-ui.md) section.
124 |
125 | We have developed a tool for automated SVG sprites. It's seamlessly integrated and is explained in detail in the [Branding & UI](./branding-and-ui.md) section.
126 |
--------------------------------------------------------------------------------
/modules/theme/views/design-system/button/primary.njk:
--------------------------------------------------------------------------------
1 | {% extends dsPreview %}
2 |
3 | {# The button macro #}
4 | {% import "theme:button.html" as buttons %}
5 |
6 |
7 | {# The component tagline #}
8 | {% block tagline %}
9 | Primary buttons
10 | {% endblock %}
11 |
12 | {# Preview of the component inside of `previewSimple` or `preview` block #}
13 | {% block preview %}
14 |